From bc76cd6e15bd66b6c13a29a64a29a68d3bfe225f Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Wed, 13 Apr 2016 10:58:43 +0200 Subject: [PATCH] Fixed series of bugs and optimalised arguments preparation Fixed kdbus pool memory managment. Refactored tslog (getenv called only once). Removed duplicated credential information. Dropped unused timeouts. Added lockless calls when logs are disabled. Removed udesc allocation. Decreased KDBUS_POOL_SIZE from 16M to 1M. Minor fixes. Change-Id: I1e5fda8df4dbd1dd6dfecae60aff6d7d67705a3b --- src/dbuspolicy1/libdbuspolicy1.h | 3 - src/internal/internal.cpp | 65 +++- src/internal/internal.h | 11 +- src/internal/libdbuspolicy1-private.hpp | 11 +- src/internal/timer.hpp | 77 ----- src/internal/tslog.hpp | 89 +----- src/internal/xml_parser.hpp | 227 +++++--------- src/internal/xml_policy.hpp | 359 +++++++++------------- src/libdbuspolicy1-private.h | 3 + src/libdbuspolicy1.c | 515 ++++++++++++++------------------ 10 files changed, 515 insertions(+), 845 deletions(-) delete mode 100644 src/internal/timer.hpp diff --git a/src/dbuspolicy1/libdbuspolicy1.h b/src/dbuspolicy1/libdbuspolicy1.h index 0037fc7..ae9b0c2 100644 --- a/src/dbuspolicy1/libdbuspolicy1.h +++ b/src/dbuspolicy1/libdbuspolicy1.h @@ -29,9 +29,6 @@ extern "C" { #define SYSTEM_BUS_CONF_FILE_SECONDARY "/etc/dbus-1/system-local.conf" #define SESSION_BUS_CONF_FILE_SECONDARY "/etc/dbus-1/session-local.conf" -#define SYSTEM_BUS 1 -#define SESSION_BUS 2 - /** used when check policy for message prepared to send */ #define DBUSPOLICY_DIRECTION_SENDING 0 diff --git a/src/internal/internal.cpp b/src/internal/internal.cpp index 274d321..e26c510 100644 --- a/src/internal/internal.cpp +++ b/src/internal/internal.cpp @@ -23,14 +23,20 @@ extern "C" { #endif -static const char* get_bus(int bus_type) { - return (bus_type == SYSTEM_BUS) ? "SYSTEM" : "SESSION"; -} - static const char* get_str(const char* const szstr) { return (szstr != NULL) ? szstr : ""; } +static std::string get_strv(const char *s) { + unsigned i = 0; + if (s) { + i = -1; + char c; + while ((c = s[++i]) && ' ' != c); + } + return std::string{s, i}; +} + static const char* get_message_type(int type) { const char* sztype; switch(type) { @@ -43,14 +49,41 @@ static const char* get_message_type(int type) { return sztype; } -int __internal_init(unsigned int bus_type, const char* const config_name) +int __internal_init(bool bus_type, const char* const config_name) { - _ldp_xml_parser::XmlAsyncParser p; - auto err = p.parse_policy(get_bus(bus_type), get_str(config_name)); + _ldp_xml_parser::XmlParser p; + auto err = p.parse_policy(bus_type, get_str(config_name)); return err.get(); } -int __internal_can_send(unsigned int bus_type, +pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +void __internal_init_once() +{ + tslog::init(); +} + +void __internal_init_flush_logs() +{ + if (tslog::enabled()) { + pthread_mutex_lock(&g_mutex); + std::cout << std::flush; + pthread_mutex_unlock(&g_mutex); + } +} + +void __internal_enter() +{ + if (tslog::enabled()) + pthread_mutex_lock(&g_mutex); +} +void __internal_exit() +{ + if (tslog::enabled()) + pthread_mutex_unlock(&g_mutex); +} + +int __internal_can_send(bool bus_type, const char* const user, const char* const group, const char* const label, @@ -60,12 +93,12 @@ int __internal_can_send(unsigned int bus_type, const char* const member, int type) { - _ldp_xml_parser::XmlAsyncParser p; - auto err = p.can_send(get_bus(bus_type), get_str(user), get_str(group), get_str(label), get_str(destination), get_str(path), get_str(interface), get_str(member), get_message_type(type)); + _ldp_xml_parser::XmlParser p; + auto err = p.can_send(bus_type, get_str(user), get_str(group), get_str(label), get_strv(destination), get_str(path), get_str(interface), get_str(member), get_message_type(type)); return err.get(); } -int __internal_can_recv(unsigned int bus_type, +int __internal_can_recv(bool bus_type, const char* const user, const char* const group, const char* const label, @@ -75,18 +108,18 @@ int __internal_can_recv(unsigned int bus_type, const char* const member, int type) { - _ldp_xml_parser::XmlAsyncParser p; - auto err = p.can_recv(get_bus(bus_type), get_str(user), get_str(group), get_str(label), get_str(sender), get_str(path), get_str(interface), get_str(member), get_message_type(type)); + _ldp_xml_parser::XmlParser p; + auto err = p.can_recv(bus_type, get_str(user), get_str(group), get_str(label), get_strv(sender), get_str(path), get_str(interface), get_str(member), get_message_type(type)); return err.get(); } -int __internal_can_own(unsigned int bus_type, +int __internal_can_own(bool bus_type, const char* const user, const char* const group, const char* const service) { - _ldp_xml_parser::XmlAsyncParser p; - auto err = p.can_own(get_bus(bus_type), get_str(user), get_str(group), get_str(service)); + _ldp_xml_parser::XmlParser p; + auto err = p.can_own(bus_type, get_str(user), get_str(group), get_str(service)); return err.get(); } diff --git a/src/internal/internal.h b/src/internal/internal.h index 84a1069..0914abe 100644 --- a/src/internal/internal.h +++ b/src/internal/internal.h @@ -22,8 +22,13 @@ extern "C" { #endif int __internal_init(unsigned int bus_type, const char* const config_name); +void __internal_init_once(void); +extern pthread_mutex_t g_mutex; +void __internal_init_flush_logs(void); +void __internal_enter(void); +void __internal_exit(void); -int __internal_can_send(unsigned int bus_type, +int __internal_can_send(bool bus_type, const char* const user, const char* const group, const char* const label, @@ -33,7 +38,7 @@ int __internal_can_send(unsigned int bus_type, const char* const member, int type); -int __internal_can_recv(unsigned int bus_type, +int __internal_can_recv(bool bus_type, const char* const user, const char* const group, const char* const label, @@ -43,7 +48,7 @@ int __internal_can_recv(unsigned int bus_type, const char* const member, int type); -int __internal_can_own(unsigned int bus_type, +int __internal_can_own(bool bus_type, const char* const user, const char* const group, const char* const service); diff --git a/src/internal/libdbuspolicy1-private.hpp b/src/internal/libdbuspolicy1-private.hpp index 4b467b4..0cef333 100644 --- a/src/internal/libdbuspolicy1-private.hpp +++ b/src/internal/libdbuspolicy1-private.hpp @@ -19,6 +19,12 @@ #include +namespace arraySizeDetail { + template constexpr size_t size(T const (&)[S]) { return S; } + template constexpr size_t size(std::initializer_list const &l) { return l.size(); } +} +#define TABSIZE(...) (::arraySizeDetail::size(__VA_ARGS__)) + namespace { class ErrCode { int m_err; @@ -26,7 +32,6 @@ namespace { ErrCode(int e, const std::string& s) : m_err(e), m_err_str(s) {} public: ErrCode() : m_err(0), m_err_str("") {} - virtual ~ErrCode() {} static ErrCode ok() { return ErrCode(0, "OK"); @@ -41,10 +46,6 @@ namespace { return ErrCode(-1, what); } - static ErrCode timeout(const std::string& what) { - return ErrCode(-99, std::string("Timeout: ") + what); - } - int get() const { return m_err; } diff --git a/src/internal/timer.hpp b/src/internal/timer.hpp deleted file mode 100644 index 2d856b3..0000000 --- a/src/internal/timer.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015 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. -*/ - -#ifndef _TIMER_HPP -#define _TIMER_HPP -#include - -namespace _ldp_timer -{ - template - class Duration : public BaseTimeUnit { - public: - void setNanoTime(std::chrono::nanoseconds nano) { - BaseTimeUnit d = std::chrono::duration_cast(nano); - BaseTimeUnit::operator =(d); - } - - double getSeconds() { - typename BaseTimeUnit::period p; - return 1.0 * BaseTimeUnit::count() * p.num/p.den; - } - - uint64_t getNativeTime() { - return BaseTimeUnit::count(); - } - - friend std::ostream& operator<< (std::ostream& os, - const Duration& d) { - typename BaseTimeUnit::period p; - std::string unit; - switch(p.den/p.num) { - case 1000000000: unit = "ns"; break; - case 1000000: unit = "us"; break; - case 1000: unit = "ms"; break; - case 1: unit = "s"; break; - } - - os << d.count() << " " << unit; - return os; - } - }; - - typedef Duration nanosec; - typedef Duration microsec; - typedef Duration millisec; - typedef Duration sec; - - template - class Timer { - typedef std::chrono::steady_clock CLK; - CLK::time_point tbegin; - _T* const pOT; - public: - Timer(_T* const pTP) - : tbegin(CLK::now()), pOT(pTP) {} - - virtual ~Timer() { - if(pOT) - pOT->setNanoTime(CLK::now() - tbegin); - } - }; -} - -#endif // _TIMER_HPP diff --git a/src/internal/tslog.hpp b/src/internal/tslog.hpp index 3452dbc..dd57976 100644 --- a/src/internal/tslog.hpp +++ b/src/internal/tslog.hpp @@ -19,87 +19,26 @@ #include #include -#include +#include #include -namespace _ldp_tslog -{ - typedef std::ostream& (*t_ManFun)(std::ostream&); - - namespace { - static constexpr bool LOG_DEFAULT_ENABLE = false; - static constexpr bool LOG_DEFAULT_VERBOSE = false; - static const std::string LDP_ENV_VERBOSE_NAME = "LDP_VERBOSE"; - static const std::string LDP_ENV_LOG_NAME = "LDP_LOG"; - - const bool get_log_env(const std::string& name) { - bool bret; - char* ldp_log_mode = getenv(name.c_str()); - if(ldp_log_mode) { - const std::string slog(ldp_log_mode); - bret = (slog == "0") ? false : true; - } else { - bret = (name == LDP_ENV_LOG_NAME) ? LOG_DEFAULT_ENABLE : LOG_DEFAULT_VERBOSE; - } - return bret; - } - } - - const bool get_verbose() { - return get_log_env(LDP_ENV_VERBOSE_NAME); - } - - const bool get_enable() { - return get_log_env(LDP_ENV_LOG_NAME); - } - - class TsLog - { - private: - static bool m_verbose; - static std::mutex m_mtx; - std::ostream& m_os; - bool m_enable; +typedef std::ostream& (*t_ManFun)(std::ostream&); - template - TsLog& lckLog(const T& t) { - if(m_enable) { - std::unique_lock lck(m_mtx); - m_os << t; - } - return *this; - } - - public: - TsLog() = delete; - - explicit TsLog(std::ostream& os, bool enable = true) - : m_os(os), m_enable(enable) {} - - virtual ~TsLog() {} +namespace tslog +{ + int8_t g_verbosity; // <0 disable 0 brief >0 verbose - template - TsLog& operator<< (const T& t) { - return lckLog(t); - } + bool get_log_env(char const *name) { + char const *ldp_log_mode = getenv(name); + return ldp_log_mode && '0' != *ldp_log_mode; + } - TsLog& operator<< (t_ManFun f) { - return lckLog(f); - } + void init() { + g_verbosity = get_log_env("LDP_LOG") ? get_log_env("LDP_VERBOSE") : -1; + } - }; - std::mutex TsLog::m_mtx; + bool enabled() { return g_verbosity >= 0; } + bool verbose() { return g_verbosity > 0; } } -namespace { - //Thread-safe loggers - _ldp_tslog::TsLog tout(std::cout, _ldp_tslog::get_enable()); - _ldp_tslog::TsLog terr(std::cerr, _ldp_tslog::get_enable()); - - namespace verbose { - _ldp_tslog::TsLog tout(std::cout, _ldp_tslog::get_enable() && _ldp_tslog::get_verbose()); - _ldp_tslog::TsLog terr(std::cerr, _ldp_tslog::get_enable() && _ldp_tslog::get_verbose()); - } -} //namespace - #endif diff --git a/src/internal/xml_parser.hpp b/src/internal/xml_parser.hpp index 05df566..61e60e4 100644 --- a/src/internal/xml_parser.hpp +++ b/src/internal/xml_parser.hpp @@ -17,39 +17,26 @@ #ifndef _XML_PARSER_HPP #define _XML_PARSER_HPP -#include -#include -#include +#include #include #include #include -#include #include #include -#include "timer.hpp" #include "xml_policy.hpp" namespace _ldp_xml_parser { - class XmlAsyncParser : boost::noncopyable + class XmlParser : boost::noncopyable { public: - XmlAsyncParser() { - } - - virtual ~XmlAsyncParser() { - } - - ErrCode parse_policy(const std::string bus, - const std::string fname, - const std::chrono::milliseconds timeout = std::chrono::milliseconds(std::numeric_limits::max())) { - set_policy_bus_filename(bus, fname); - m_xml_policy.init(); - ErrCode err = parse(timeout); + ErrCode parse_policy(bool bus, + std::string const &fname) { + ErrCode err = parse(bus, fname); return err; } - ErrCode can_send(const std::string bus, + ErrCode can_send(bool bus, const std::string user, const std::string group, const std::string label, @@ -62,7 +49,7 @@ namespace _ldp_xml_parser return m_xml_policy.can_send_to(bus, idx_v, label); } - ErrCode can_recv(const std::string bus, + ErrCode can_recv(bool bus, const std::string user, const std::string group, const std::string label, @@ -75,7 +62,7 @@ namespace _ldp_xml_parser return m_xml_policy.can_recv_from(bus, idx_v, label); } - ErrCode can_own(const std::string bus, + ErrCode can_own(bool bus, const std::string user, const std::string group, const std::string service) { @@ -86,173 +73,95 @@ namespace _ldp_xml_parser private: //IO operation - std::string m_bus; - std::string m_filename; - static std::map m_hashes; - static std::mutex m_io_xml_mtx; + static std::set m_parsed; //Data obtained from XML static XmlPolicy m_xml_policy; - //Called by calling user thread - void set_policy_bus_filename(const std::string& bus, const std::string& fname) { - m_filename = fname; - m_bus = bus; - } - - const std::string& get_policy_bus() const { - return m_bus; - } - - const std::string& get_policy_filename() const { - return m_filename; - } - - ErrCode parse(const std::chrono::milliseconds timeout) { + ErrCode parse(bool bus, std::string const &filename) { ErrCode err; std::vector incl_files; - err = parse(get_policy_filename(), incl_files, timeout); - if(err.is_ok()) { + err = parse(bus, true, filename, incl_files); + if (err.is_ok()) for(const auto& x : incl_files) { - err = parse(x, incl_files, timeout); - if(err.is_error()) { break; } + err = parse(bus, false, x, incl_files); + if (err.is_error()) break; } - } - if(err.is_ok()) { - m_xml_policy.print_decision_trees(); - } + if(err.is_ok()) + m_xml_policy.print_decision_trees(bus); return err; } - ErrCode parse(const std::string& filename, std::vector& included_files, const std::chrono::milliseconds timeout) { + ErrCode parse(bool bus, bool first, const std::string& filename, std::vector& included_files) { std::pair errparam; - verbose::tout << "=== XML PARSING BEGIN === : " << filename << std::endl; + if (tslog::verbose()) + std::cout << "=== XML PARSING BEGIN === : " << filename << '\n'; - auto fut = std::async(std::launch::async, &XmlAsyncParser::async_xml_parse, this, filename); - - auto r = fut.wait_for(timeout); - if(r == std::future_status::ready) { - errparam = fut.get(); - if(errparam.first.get() >= 0) { - get_included_files(filename, errparam.second, included_files); - } - } else if(r == std::future_status::timeout) { - errparam.first = ErrCode::timeout("XML parsing timeout"); - } + errparam = xml_parse(bus, filename); + if (first && errparam.first.get() >= 0 && errparam.second != "") + get_included_files(filename, errparam.second, included_files); - verbose::tout << "=== XML PARSING END ===" << std::endl << std::endl; - tout << "Processing of " << filename << " -> [" << errparam.first.get() << ", " << errparam.first.get_str() << "]" << std::endl; + if (tslog::enabled()) { + if (tslog::verbose()) + std::cout << "=== XML PARSING END ===\n\n"; + std::cout << "Processing of " << filename << " -> [" << errparam.first.get() << ", " << errparam.first.get_str() << "]\n"; + } return errparam.first; } //Get all the .conf files within included subdirectory, POSIX style as boost::filesystem is not header-only void get_included_files(const std::string& filename, const std::string& incldir, std::vector& files) { - if(get_policy_filename() == filename && incldir != "") { - DIR *dir; - struct dirent *ent; - std::string fname; - std::copy(filename.begin(), filename.end(), fname.begin()); - std::string dname = dirname(const_cast(fname.c_str())); - dname += (std::string("/") + incldir); - files.clear(); - if((dir = opendir(dname.c_str())) != NULL) { - while((ent = readdir(dir)) != NULL) { - std::string s(ent->d_name); - if(s.find(".conf") != std::string::npos) { - files.push_back(dname + std::string("/") + s); - } - } - closedir(dir); - - tout << std::endl << "includedir for " << filename << " is " << incldir << ", " << files.size() << " included files found:" << std::endl; - if(_ldp_tslog::get_enable()) { std::copy(files.begin(), files.end(), std::ostream_iterator(std::cout, "\n")); } - tout << std::endl; - } else { - terr << "could not open directory " << dname << std::endl; - } - } - } - - //All 'async_*' methods are executed in library's internal worker threads - std::pair async_xml_parse(const std::string& filename) { + DIR *dir; + struct dirent *ent; + std::string fname; + std::copy(filename.begin(), filename.end(), fname.begin()); + std::string dname = dirname(const_cast(fname.c_str())); + dname += (std::string("/") + incldir); + files.clear(); + if((dir = opendir(dname.c_str())) != NULL) { + while((ent = readdir(dir)) != NULL) { + std::string s(ent->d_name); + if(s.find(".conf") != std::string::npos) { + files.push_back(dname + std::string("/") + s); + } + } + closedir(dir); + + if (tslog::enabled()) { + std::cout << "\nincludedir for " << filename << " is " << incldir << ", " << files.size() << " included files found:\n"; + std::copy(files.begin(), files.end(), std::ostream_iterator(std::cout, "\n")); + std::cout << '\n'; + } + } else if (tslog::enabled()) + std::cout << "could not open directory " << dname << '\n'; + } + + std::pair xml_parse(bool bus, const std::string& filename) { std::pair ret; - _ldp_timer::microsec latency; - try { - boost::property_tree::ptree pt; + if (m_parsed.insert(filename).second) + try { + boost::property_tree::ptree pt; + read_xml(filename, pt); + if (!pt.empty()) { + m_xml_policy.update(bus, pt); + ret.second = pt.get("busconfig.includedir", ""); + } + } catch(const boost::property_tree::xml_parser::xml_parser_error& ex) { + ret.first = ErrCode::error(ex.what()); + } catch(const boost::property_tree::ptree_error& ex) { + ret.first = ErrCode::error(ex.what()); + } catch(...) { + ret.first = ErrCode::error(filename + std::string(": unknown error while parsing XML")); + } - //XML file IO critical section - { - std::unique_lock lck(m_io_xml_mtx); - _ldp_timer::Timer<_ldp_timer::microsec> t(&latency); - - std::size_t hash; - if(async_xml_parsing_needed(filename, hash)) { - read_xml(filename, pt); - async_xml_hash_update(filename, hash); - } - } - - m_xml_policy.update(get_policy_bus(), pt); - - ret.second = pt.get("busconfig.includedir", ""); - - ret.first = ErrCode::ok(); - } catch(const boost::property_tree::xml_parser::xml_parser_error& ex) { - ret.first = ErrCode::error(ex.what()); - } catch(const boost::property_tree::ptree_error& ex) { - ret.first = ErrCode::error(ex.what()); - } catch(...) { - ret.first = ErrCode::error(filename + std::string(": unknown error while parsing XML")); - } - - tout << "XML processing latency: " << latency << std::endl; - return ret; - } - - std::size_t async_xml_hash(const std::string& filename) { - std::size_t seed = 0; - std::ifstream ifs(filename); - for(std::string line; getline(ifs, line); ) { - boost::hash_combine(seed, line); - } - ifs.close(); - - return seed; - } - - void async_xml_hash_update(const std::string& filename, const std::size_t hash) { - auto r = m_hashes.insert(std::pair(filename, hash)); - if(r.second == false) { - auto it = r.first; - it->second = hash; - } - } - - bool async_xml_parsing_needed(const std::string& filename, std::size_t& hash) { - bool ret = false; - hash = async_xml_hash(filename); - auto it = m_hashes.find(filename); - if(it != m_hashes.end()) { - if(hash == it->second) { - ret = false; - } else { - ret = true; - } - } else { - ret = true; - } return ret; } - }; - std::map XmlAsyncParser::m_hashes; - std::mutex XmlAsyncParser::m_io_xml_mtx; - XmlPolicy XmlAsyncParser::m_xml_policy; } //namespace #endif diff --git a/src/internal/xml_policy.hpp b/src/internal/xml_policy.hpp index 63fe956..48fa7f9 100644 --- a/src/internal/xml_policy.hpp +++ b/src/internal/xml_policy.hpp @@ -20,11 +20,17 @@ #include #include #include +#include #include "libdbuspolicy1-private.hpp" -#include "timer.hpp" #include "tslog.hpp" #include "cynara.hpp" +enum class TreeType : uint8_t { + SEND, + RECV, + OWN +}; + namespace _ldp_xml_parser { namespace { @@ -56,7 +62,6 @@ namespace _ldp_xml_parser static const size_t IDX_OWN_LENGTH = IDX_SERVICE + 1; static const size_t IDX_DEFAULT = IDX_GROUP + 1; - std::string m_bus; std::vector m_path_content; std::string m_privilege; bool m_bsend; @@ -66,9 +71,8 @@ namespace _ldp_xml_parser bool m_ballow; static size_t m_weight; - Key(const std::string& bus) - : m_bus(bus), - m_path_content(std::vector(IDX_TOTAL_LENGTH, ANY)), + Key(bool bus) + : m_path_content(std::vector(IDX_TOTAL_LENGTH, ANY)), m_bsend(false), m_brecv(false), m_bown(false), @@ -85,9 +89,8 @@ namespace _ldp_xml_parser const std::string get_path() const { std::string path = "R"; auto it_cend = m_bown ? m_path_content.cbegin() + IDX_OWN_LENGTH : m_path_content.cend(); - for(auto it = m_path_content.cbegin(); it != it_cend; ++it) { - path += (std::string(1, Key::DELIM) + *it); - } + for(auto it = m_path_content.cbegin(); it != it_cend; ++it) + (path += Key::DELIM) += *it; return path; } }; @@ -121,11 +124,10 @@ namespace _ldp_xml_parser } friend std::ostream& operator<<(std::ostream& os, const Leaf& lf) { - if(lf.m_check) { + if(lf.m_check) os << "check," << lf.m_privilege << "," << lf.m_weight; - } else { + else os << (lf.m_decision ? "true" : "false") << "," << lf.m_weight; - } return os; } @@ -138,24 +140,20 @@ namespace _ldp_xml_parser for(auto it = tokens.begin(); it != tokens.end(); ++it) { const auto it_last = std::next(tokens.begin(), size - 1); if(it == tokens.begin()) { - if(size > 2) { + if(size > 2) lf.m_check = (*it == "check") ? true : false; - } else { + else lf.m_decision = (*it == "true") ? true : false; - } - } else if(it == it_last) { + } else if(it == it_last) lf.m_weight = std::stoul(*it); - } else { - if(size > 2) { - lf.m_privilege = *it; - } - } + else if(size > 2) + lf.m_privilege = *it; } return is; } }; - static const std::string get_context_str(const CtxType& ctx_type) { + static char const *get_context_str(const CtxType& ctx_type) { switch(ctx_type) { case CtxType::DEFAULT: return "(default)"; break; case CtxType::SPECIFIC: return "(specific)"; break; @@ -165,34 +163,24 @@ namespace _ldp_xml_parser } static const std::string get_field_str(const std::string& field) { - return (field == "") ? Key::ANY : field; + return field == "" ? Key::ANY : field; } //Data obtained from XML parsing - decision trees - typedef std::map Trees_t; - std::map m_dec_trees; - std::mutex m_xml_policy_mtx; - - boost::property_tree::ptree* get_decision_tree(const std::string& bus, const std::string& tree_type) { - boost::property_tree::ptree* p_tree = NULL; - - auto it1 = m_dec_trees.find(bus); - if(it1 != m_dec_trees.end()) { - auto it2 = it1->second.find(tree_type); - if(it2 != it1->second.end()) { - p_tree = &it2->second; - } - } - return p_tree; + boost::property_tree::ptree m_dec_trees[2][3]; + + boost::property_tree::ptree &get_decision_tree(bool bus, TreeType tree_type) { + return m_dec_trees[bus][static_cast(tree_type)]; } - boost::property_tree::ptree* get_decision_tree(const Key& key) { - std::string tree_type; - if(key.m_bsend) { tree_type = "SEND"; } - else if(key.m_brecv) { tree_type = "RECV"; } - else if(key.m_bown) { tree_type = "OWN"; } + boost::property_tree::ptree* get_decision_tree(bool bus, const Key& key) { + TreeType tree_type; + if(key.m_bsend) tree_type = TreeType::SEND; + else if(key.m_brecv) tree_type = TreeType::RECV; + else if(key.m_bown) tree_type = TreeType::OWN; + else return NULL; - return get_decision_tree(key.m_bus, tree_type); + return &get_decision_tree(bus, tree_type); } void print_decision_tree(const boost::property_tree::ptree& pt, int level = 0) { @@ -202,31 +190,30 @@ namespace _ldp_xml_parser } } - void print_decision_key(const Key& key) { - if(_ldp_tslog::get_verbose()) { - std::string s = key.m_bus + " "; - if(key.m_bsend && !key.m_brecv) { s += "--> #"; } - if(!key.m_bsend && key.m_brecv) { s += "<-- #"; } - if(!key.m_bsend && !key.m_brecv && key.m_bown) { s += "OWN #"; } + void print_decision_key(bool bus, const Key& key) { + if (tslog::verbose()) { + std::string s = bus + " "; + if(key.m_bsend && !key.m_brecv) s += "--> #"; + if(!key.m_bsend && key.m_brecv) s += "<-- #"; + if(!key.m_bsend && !key.m_brecv && key.m_bown) s += "OWN #"; std::string prv = key.m_bcheck ? key.m_privilege : ""; - verbose::tout << s + std::cout << s << (key.m_bcheck ? "check " : std::to_string(key.m_ballow)) << prv << " : " << key.get_path() << " (weight: " << key.m_weight - << ")" - << std::endl; + << ")\n"; } } - void update_decision_tree(const Key& key) { + void update_decision_tree(bool bus, const Key& key) { if(!key.get_path().empty()) { - print_decision_key(key); + print_decision_key(bus, key); //update - boost::property_tree::ptree* const p_tree = get_decision_tree(key); + boost::property_tree::ptree* const p_tree = get_decision_tree(bus, key); if(p_tree) { boost::property_tree::ptree::path_type tpath(key.get_path(), Key::DELIM); p_tree->put(tpath, Leaf(key.m_ballow, key.m_bcheck, key.m_privilege, key.m_weight)); @@ -260,7 +247,7 @@ namespace _ldp_xml_parser ++key.m_weight; } else { if(attr) { - std::string data_str = (v.second.data() == "*") ? Key::ANY : v.second.data(); + std::string data_str = v.second.data() == "*" ? Key::ANY : v.second.data(); if(v.first == "context") { if(data_str == "mandatory") { key.m_path_content[Key::IDX_USER] = Key::MRY; @@ -272,20 +259,16 @@ namespace _ldp_xml_parser current_ctx = CtxType::DEFAULT; } } else if(v.first == "user") { - if(current_ctx == CtxType::SPECIFIC) { + if(current_ctx == CtxType::SPECIFIC) key.m_path_content[Key::IDX_USER] = data_str; - } } else if(v.first == "group") { - if(current_ctx == CtxType::SPECIFIC) { + if(current_ctx == CtxType::SPECIFIC) key.m_path_content[Key::IDX_GROUP] = data_str; - } } else { - if(field_has(v, "send_")) { + if(field_has(v, "send_")) key.m_bsend = true; - } - if(field_has(v, "receive_")) { + if(field_has(v, "receive_")) key.m_brecv = true; - } if(v.first == "own") { key.m_bown = true; key.m_path_content[Key::IDX_SERVICE] = data_str; @@ -294,27 +277,20 @@ namespace _ldp_xml_parser key.m_bown = true; key.m_path_content[Key::IDX_SERVICE] = data_str + "*"; } - if(field_has(v, "_destination")) { + if(field_has(v, "_destination")) key.m_path_content[Key::IDX_DEST] = data_str; - } - if(field_has(v, "_sender")) { + if(field_has(v, "_sender")) key.m_path_content[Key::IDX_SENDER] = data_str; - } - if(field_has(v, "_path")) { + if(field_has(v, "_path")) key.m_path_content[Key::IDX_PATH] = data_str; - } - if(field_has(v, "_interface")) { + if(field_has(v, "_interface")) key.m_path_content[Key::IDX_IFACE] = data_str; - } - if(field_has(v, "_member")) { + if(field_has(v, "_member")) key.m_path_content[Key::IDX_MEMBER] = data_str; - } - if(field_has(v, "_type")) { + if(field_has(v, "_type")) key.m_path_content[Key::IDX_TYPE] = data_str; - } - if(v.first == "privilege") { + if(v.first == "privilege") key.m_privilege = data_str; - } key.m_bcheck = bcheck; key.m_ballow = allden; @@ -328,14 +304,15 @@ namespace _ldp_xml_parser } void print_field(const boost::property_tree::ptree::value_type& v, int level) { - verbose::tout << ((level > 0) ? std::string((level - 1) * 8, ' ') + std::string(8, '.') : "") - << v.first - << " : " - << v.second.data() - << std::endl; + std::cout << ((level > 0) ? std::string((level - 1) * 8, ' ') + std::string(8, '.') : "") + << v.first + << " : " + << v.second.data() + << '\n'; } - void xml_traversal(const boost::property_tree::ptree& pt, + void xml_traversal(bool bus, + const boost::property_tree::ptree& pt, Key& key, CtxType& current_ctx, bool allden = false, @@ -349,20 +326,18 @@ namespace _ldp_xml_parser if(v.first == "") { continue; } update_decision_path(v, key, current_ctx, allden, bcheck, attr); - //print_field(v, level); - xml_traversal(v.second, key, current_ctx, allden, bcheck, attr, level + 1); + //if (tslog::verbose()) print_field(v, level); + xml_traversal(bus, v.second, key, current_ctx, allden, bcheck, attr, level + 1); } - if(!pt.empty() && attr && level > 1) { - update_decision_tree(key); - } - } else { - terr << "XML traversal max level reached: " << level << std::endl; - } + if(!pt.empty() && attr && level > 1) + update_decision_tree(bus, key); + } else if (tslog::enabled()) + std::cout << "XML traversal max level reached: " << level << '\n'; } void print_indexing_path(size_t idx, const std::string& path, const Leaf& leaf = Leaf(), bool empty = true) { - if(_ldp_tslog::get_verbose()) { + if (tslog::verbose()) { std::string s; if(!empty) { s = " : <"; @@ -373,72 +348,59 @@ namespace _ldp_xml_parser s += std::string(">"); } - verbose::tout << "path #" - << idx - << " : " - << path - << s - << std::endl; + std::cout << "path #" + << idx + << " : " + << path + << s + << '\n'; } } void prepare_indexing_path(const std::vector& idx_v, - const size_t pattern, + size_t pattern, const size_t usrgrp_obfuscate_order, const bool obfuscate_params, const CtxType& ctx_type, std::string& path) { - const size_t offset = Key::IDX_DEFAULT; + constexpr size_t offset = Key::IDX_DEFAULT; path = "R"; if(ctx_type == CtxType::SPECIFIC) { - switch(usrgrp_obfuscate_order) { - case 0: - path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_USER])); - path += (std::string(1, Key::DELIM) + Key::ANY); - break; - case 1: - path += (std::string(1, Key::DELIM) + Key::ANY); - path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_GROUP])); - break; - case 2: - path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_USER])); - path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_GROUP])); - break; - case 3: - default: - path += (std::string(1, Key::DELIM) + Key::ANY); - path += (std::string(1, Key::DELIM) + Key::ANY); - break; - } - } else { - for(size_t i = 0; i < offset; ++i) { - const std::string as = (ctx_type == CtxType::MANDATORY) ? Key::MRY : Key::DEF; - path += (std::string(1, Key::DELIM) + as); - } - } + path += Key::DELIM; + if (usrgrp_obfuscate_order & 1) // 1 3 + path += Key::ANY; + else + path += get_field_str(idx_v[Key::IDX_USER]); + path += Key::DELIM; + if ((usrgrp_obfuscate_order+1) & 2) // 1 2 + path += get_field_str(idx_v[Key::IDX_GROUP]); + else + path += Key::ANY; + } else + for(size_t i = 0; i < offset; ++i) + (path += Key::DELIM) += ctx_type == CtxType::MANDATORY ? Key::MRY : Key::DEF; - const size_t m = 1; const size_t n = idx_v.size() - offset; - for(size_t i = 0; i < n; ++i) { - std::string s = get_field_str(idx_v[i + offset]); + for (size_t i = 0; i < n; ++i) { path += Key::DELIM; - if(obfuscate_params && (pattern & (m << i))) { - path += Key::ANY; - } else { - path += s; - } + if (obfuscate_params && pattern & 1) + path += Key::ANY; + else + path += get_field_str(idx_v[i + offset]); + pattern >>= 1; } } ErrCode service_leaf_found(const Leaf& leaf, const std::string& label, const std::vector& idx_v) { ErrCode err; if(leaf.get_check()) { - verbose::tout << __func__ - << ": cynara check needed for privilege " << leaf.get_privilege() - << ", weight " << leaf.get_weight() - << std::endl; + if (tslog::verbose()) + std::cout << __func__ + << ": cynara check needed for privilege " << leaf.get_privilege() + << ", weight " << leaf.get_weight() + << '\n'; //cynara check try { @@ -487,14 +449,16 @@ namespace _ldp_xml_parser if(!found) { err = ErrCode::error("No path"); } } catch(...) { print_indexing_path(p, path); - verbose::tout << "Unknown exception while indexing decision tree!" << std::endl; + if (tslog::verbose()) + std::cout << "Unknown exception while indexing decision tree!\n"; if(!found) { err = ErrCode::error("Unknown err, no path"); } } } if(found) { err = service_leaf_found(leaf_found, label, idx_v); - verbose::tout << __func__ << ": returning decision #" << err.get() << " " << err.get_str() << ", weight " << leaf_found.get_weight() << std::endl; + if (tslog::verbose()) + std::cout << __func__ << ": returning decision #" << err.get() << " " << err.get_str() << ", weight " << leaf_found.get_weight() << '\n'; break; } } @@ -509,85 +473,63 @@ namespace _ldp_xml_parser const CtxType& ctx_type) { ErrCode err; - tout << "context: " << get_context_str(ctx_type) << ", indexing arguments: "; - if(_ldp_tslog::get_enable()) { std::copy(idx_v.begin(), idx_v.end(), std::ostream_iterator(std::cout, ", ")); } - tout << std::endl; + if (tslog::enabled()) { + std::cout << "context: " << get_context_str(ctx_type) << ", indexing arguments: "; + std::copy(idx_v.begin(), idx_v.end(), std::ostream_iterator(std::cout, ", ")); + std::cout << '\n'; + } //Examine policy data and make decision - _ldp_timer::microsec latency; - { - _ldp_timer::Timer<_ldp_timer::microsec> t(&latency); - err = index_decision_tree(pt, idx_v, label, obfuscate_params, ctx_type); - } + err = index_decision_tree(pt, idx_v, label, obfuscate_params, ctx_type); - tout << __func__ << ": #" << err.get() << " " << err.get_str() << " " << get_context_str(ctx_type) << std::endl; - tout << "tree indexing latency: " << latency << std::endl; + if (tslog::enabled()) + std::cout << __func__ << ": #" << err.get() << " " << err.get_str() << " " << get_context_str(ctx_type) << '\n'; return err; } - ErrCode can_do_action(const std::string& bus, - const std::string& tree_type, + ErrCode can_do_action(bool bus, + TreeType tree_type, const std::vector& idx_v, const std::string& label = "", const bool analyze_prefix = false) { - std::unique_lock lck(m_xml_policy_mtx); ErrCode err; - boost::property_tree::ptree* const p_tree = get_decision_tree(bus, tree_type); - if(p_tree) { - err = index_decision_tree_lat(*p_tree, idx_v, label, !analyze_prefix, CtxType::MANDATORY); - if(!err.is_ok()) { - err = index_decision_tree_lat(*p_tree, idx_v, label, !analyze_prefix, CtxType::SPECIFIC); - if(!err.is_ok()) { - err = index_decision_tree_lat(*p_tree, idx_v, label, !analyze_prefix, CtxType::DEFAULT); - } - } - } else { - err = ErrCode::error("Get decision tree returned NULL ptr"); - } - tout << __func__ << ": #" << err.get() << " " << err.get_str() << std::endl; + boost::property_tree::ptree const &p_tree = get_decision_tree(bus, tree_type); + err = index_decision_tree_lat(p_tree, idx_v, label, !analyze_prefix, CtxType::MANDATORY); + if(!err.is_ok()) { + err = index_decision_tree_lat(p_tree, idx_v, label, !analyze_prefix, CtxType::SPECIFIC); + if(!err.is_ok()) + err = index_decision_tree_lat(p_tree, idx_v, label, !analyze_prefix, CtxType::DEFAULT); + } + if (tslog::enabled()) + std::cout << __func__ << ": #" << err.get() << " " << err.get_str() << '\n'; return err; } public: XmlPolicy() { - Trees_t t; - t.emplace("SEND", typename Trees_t::mapped_type()); - t.emplace("RECV", typename Trees_t::mapped_type()); - t.emplace("OWN", typename Trees_t::mapped_type()); - m_dec_trees.emplace("SYSTEM", t); - m_dec_trees.emplace("SESSION", t); - } - - virtual ~XmlPolicy() {} - - void init() { - std::unique_lock lck(m_xml_policy_mtx); Key::m_weight = 0; } - void update(const std::string& bus, const boost::property_tree::ptree& pt) { - if(!pt.empty()) { - std::unique_lock lck(m_xml_policy_mtx); - const auto& children = pt.get_child(ROOT_FIELD); - for(const auto& x : children) { - if(x.first == ROOT_POLICY) { - Key key(bus); - CtxType current_ctx = CtxType::SPECIFIC; - xml_traversal(x.second, key, current_ctx); - } - } - } + void update(bool bus, const boost::property_tree::ptree& pt) { + const auto& children = pt.get_child(ROOT_FIELD); + for(const auto& x : children) { + if(x.first == ROOT_POLICY) { + Key key(bus); + CtxType current_ctx = CtxType::SPECIFIC; + xml_traversal(bus, x.second, key, current_ctx); + } + } } - ErrCode can_send_to(const std::string bus, const std::vector& idx_v, const std::string label) { - return can_do_action(bus, "SEND", idx_v, label); + ErrCode can_send_to(bool bus, const std::vector& idx_v, const std::string label) { + return can_do_action(bus, TreeType::SEND, idx_v, label); } - ErrCode can_recv_from(const std::string bus, const std::vector& idx_v, const std::string label) { - return can_do_action(bus, "RECV", idx_v, label); + ErrCode can_recv_from(bool bus, const std::vector& idx_v, const std::string label) { + return can_do_action(bus, TreeType::RECV, idx_v, label); } - ErrCode can_own_what(const std::string bus, const std::vector& idx_v) { + ErrCode can_own_what(bool bus, const std::vector& idx_v) { ErrCode err; //Evaluate own_prefix @@ -596,34 +538,29 @@ namespace _ldp_xml_parser const size_t srv_size = srv.size(); for(size_t n = 1; n <= srv_size; ++n) { const std::string sub = srv.substr(0, n) + "*"; - verbose::tout << "own_prefix: " << sub << std::endl; + if (tslog::enabled()) + std::cout << "own_prefix: " << sub << '\n'; iv.pop_back(); iv.push_back(sub); - err = can_do_action(bus, "OWN", iv, "", true); - if(err.is_ok()) { + err = can_do_action(bus, TreeType::OWN, iv, "", true); + if(err.is_ok()) break; - } } //Evaluate own - if(err.is_error()) { - err = can_do_action(bus, "OWN", idx_v); - } + if(err.is_error()) + err = can_do_action(bus, TreeType::OWN, idx_v); return err; } - void print_decision_trees() { - if(_ldp_tslog::get_verbose()) { - std::unique_lock lck(m_xml_policy_mtx); - - for(const auto& x : m_dec_trees) { - for(const auto& y : x.second) { - verbose::tout << x.first << " " << y.first << " " << (y.second.empty() ? "(empty)" : "") << std::endl; + void print_decision_trees(bool bus) { + if (tslog::verbose()) + for (unsigned i = 0; i < TABSIZE(m_dec_trees[bus]); ++i) + for(auto const& y : m_dec_trees[bus][i]) { + std::cout << i << " " << y.first << " " << (y.second.empty() ? "(empty)" : "") << '\n'; print_decision_tree(y.second); } - } - } } }; //XmlPolicy diff --git a/src/libdbuspolicy1-private.h b/src/libdbuspolicy1-private.h index 58e27bd..24c3d02 100644 --- a/src/libdbuspolicy1-private.h +++ b/src/libdbuspolicy1-private.h @@ -26,4 +26,7 @@ #define DBUSPOLICY1_EXPORT __attribute__ ((visibility("default"))) +typedef uint8_t dbus_name_len; +#define MAX_DBUS_NAME_LEN 255 + #endif diff --git a/src/libdbuspolicy1.c b/src/libdbuspolicy1.c index 68f13a9..0ff7d6b 100644 --- a/src/libdbuspolicy1.c +++ b/src/libdbuspolicy1.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "libdbuspolicy1-private.h" @@ -38,30 +39,30 @@ #define KDBUS_PATH_PREFIX "/sys/fs/kdbus/" #define KDBUS_SYSTEM_BUS_PATH "/sys/fs/kdbus/0-system/bus" +#define KDBUS_POOL_SIZE (1024UL * 1024UL) -#define KDBUS_POOL_SIZE (16 * 1024UL * 1024UL) +#define SYSTEM_BUS 0 +#define SESSION_BUS 1 #define ALIGN8(l) (((l) + 7) & ~7) +#define ALIGNDN8(l) ((l) & ~7) #define UID_INVALID ((uid_t) -1) #define GID_INVALID ((gid_t) -1) -#define FOREACH_STRV(i,l, s, os)\ -for(\ -({\ -i=0;\ -l = strlen(s);\ -name = malloc(sizeof(char*)*(l+1));\ -strncpy(os, s, sizeof(char*)*(l+1)-1);\ -});\ -i < l;\ -i++) - -#define GET_NEXT_STR(i,s,os)\ - os = s+i;\ - for(;s[i] && s[i] != ' ';i++);\ - s[i] = 0; - +static char const *foreach_strv_advance(char const *str) { + char c; + while ((c = *str++)) + if (' ' == c) + return str; + return NULL; +} +/* iterate over STR; iterate once with "" if !STR or !*STR */ +#define FOREACH_STRV_DEFAULT(ITERLVALPTR,STR) for (\ + ITERLVALPTR = (!STR || !*STR) ? "" : STR;\ + ITERLVALPTR;\ + ITERLVALPTR = foreach_strv_advance(ITERLVALPTR)\ +) /** A process ID */ typedef unsigned long dbus_pid_t; @@ -70,159 +71,64 @@ typedef unsigned long dbus_uid_t; /** A group ID */ typedef unsigned long dbus_gid_t; -struct kcreds { - uid_t uid; - gid_t gid; - char* label; - char** names; -}; - struct kconn { int fd; uint64_t id; char *pool; -}; +} g_conn[2]; + struct udesc { - unsigned int bus_type; char user[256]; dbus_uid_t uid; char group[256]; dbus_gid_t gid; char label[256]; - struct kconn* conn; -}; - +} g_udesc; static int kdbus_open_bus(const char *path) { return open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC); } -static int kdbus_hello(struct kconn *kc, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv) +static int kdbus_hello(bool bus_type, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv) { - struct kdbus_cmd_hello kcmd_hello; - int r; + struct kdbus_cmd_hello cmd; + int fd = g_conn[bus_type].fd; - memset(&kcmd_hello, 0, sizeof(kcmd_hello)); - kcmd_hello.flags = hello_flags; - kcmd_hello.attach_flags_send = attach_flags_send; - kcmd_hello.attach_flags_recv = attach_flags_recv; - kcmd_hello.size = sizeof(kcmd_hello); - kcmd_hello.pool_size = KDBUS_POOL_SIZE; + cmd.size = sizeof(cmd); + cmd.flags = hello_flags; + cmd.attach_flags_send = attach_flags_send; + cmd.attach_flags_recv = attach_flags_recv; + cmd.pool_size = KDBUS_POOL_SIZE; - r = ioctl(kc->fd, KDBUS_CMD_HELLO, &kcmd_hello); - if (r < 0) + if (ioctl(fd, KDBUS_CMD_HELLO, &cmd) < 0) return -errno; - kc->id = (uint64_t)kcmd_hello.id; - kc->pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kc->fd, 0); - if (kc->pool == MAP_FAILED) + g_conn[bus_type].id = cmd.id; + if (MAP_FAILED == (g_conn[bus_type].pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0))) return -errno; return 0; } -static int kdbus_is_unique_id(const char* name) +static bool kdbus_is_unique_id(const char* name) { - return (strlen(name)>3 && name[0]==':' && isdigit(name[1]) && name[2]=='.'); + return ':' == name[0]; } -static int kdbus_get_creds_from_name(struct kconn* kc, struct kcreds* kcr, const char* name) +static uint64_t kdbus_unique_id(char const *name) { - unsigned long long int unique_id; - struct kdbus_cmd_info* cmd; - struct kdbus_info* conn_info; - struct kdbus_item *item; - char** tmp_names; - int j, r, l, counter; - unsigned int size; - - counter = 0; - kcr->names = calloc(counter+1, sizeof(char *)); - - kcr->uid = UID_INVALID; - kcr->gid = GID_INVALID; - kcr->label = NULL; - - if (kdbus_is_unique_id(name)) { - l = sizeof(unique_id); - unique_id = strtoull(name+3, NULL, 10); - size = sizeof(struct kdbus_cmd_info); - cmd = aligned_alloc(8, size); - memset(cmd, 0, sizeof(struct kdbus_cmd_info)); - cmd->id = unique_id; - cmd->size = size; - cmd->attach_flags = KDBUS_ATTACH_CREDS | KDBUS_ATTACH_SECLABEL | KDBUS_ATTACH_NAMES; - } else { - l = strlen(name) + 1; - size = offsetof(struct kdbus_cmd_info, items) + ALIGN8((l) + offsetof(struct kdbus_item, data)); - cmd = aligned_alloc(8, size); - memset(cmd, 0, sizeof(struct kdbus_cmd_info)); - cmd->items[0].size = l + offsetof(struct kdbus_item, data); - cmd->items[0].type = KDBUS_ITEM_NAME; - memcpy(cmd->items[0].str, name, l); - cmd->size = size; - cmd->attach_flags = KDBUS_ATTACH_CREDS | KDBUS_ATTACH_SECLABEL | KDBUS_ATTACH_NAMES; - } - - r = ioctl(kc->fd, KDBUS_CMD_CONN_INFO, cmd); - if (r < 0) - return -errno; - - conn_info = (struct kdbus_info *) ((uint8_t *) kc->pool + cmd->offset); - - for(item = conn_info->items; - ((uint8_t *)(item) < (uint8_t *)(conn_info) + (conn_info)->size) && - ((uint8_t *) item >= (uint8_t *) conn_info); - item = ((typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))) ) - { - switch (item->type) - { - case KDBUS_ITEM_CREDS: - if (item->creds.euid != UID_INVALID) - { - kcr->uid = (uid_t) item->creds.euid; - } - if (item->creds.egid != GID_INVALID) - { - kcr->gid = (gid_t) item->creds.egid; - } - break; - case KDBUS_ITEM_SECLABEL: - kcr->label = strdup(item->str); - break; - case KDBUS_ITEM_OWNED_NAME: - counter++; - tmp_names = calloc(counter+1, sizeof(char*)); - for (j = 0;kcr->names[j]; j++) - { - tmp_names[j] = kcr->names[j]; - } - tmp_names[j] = strdup(item->name.name); - free(kcr->names); - kcr->names = tmp_names; - break; - } - } - - return 0; -} - -static void kcreds_free(struct kcreds* kcr) -{ - int i = 0; - if (kcr == NULL) - return; - - free(kcr->label); - for (i=0; kcr->names[i];i++) - free(kcr->names[i]); - free(kcr->names[i]); - free(kcr->names); - free(kcr); + uint64_t res; + unsigned i = 2; + int c; + while (!(c = name[++i] - '0')); + res = c; + while ((c = (int)(name[++i]) - '0') > 0) + res = res*10 + c; + return res; } -static int dbuspolicy_init_udesc(struct kconn* kc, unsigned int bus_type, struct udesc* p_udesc) +static bool dbuspolicy_init_once(void) { struct passwd pwent; struct passwd *pwd; @@ -239,30 +145,28 @@ static int dbuspolicy_init_udesc(struct kconn* kc, unsigned int bus_type, struct close(attr_fd); - if (r < 0 || r >= (long int)sizeof(p_udesc->label)) /* read */ - return -1; - - snprintf(p_udesc->label, r + 1 /* additional byte for \0 */, "%s", buf); + if (r < 0 || r >= (long int)sizeof(g_udesc.label)) /* read */ + return true; - p_udesc->uid = getuid(); - p_udesc->gid = getgid(); + snprintf(g_udesc.label, r + 1 /* additional byte for \0 */, "%s", buf); + if (getpwuid_r(g_udesc.uid, &pwent, buf, sizeof(buf), &pwd)) + return true; - if (getpwuid_r(p_udesc->uid, &pwent, buf, sizeof(buf), &pwd)) - return -1; - - if (getgrgid_r(p_udesc->gid, &grent, buf, sizeof(buf), &gg)) - return -1; + if (getgrgid_r(g_udesc.gid, &grent, buf, sizeof(buf), &gg)) + return true; if (!pwd || !gg) return -1; - snprintf(p_udesc->user, sizeof(p_udesc->user), "%s", pwd->pw_name); - snprintf(p_udesc->group, sizeof(p_udesc->group), "%s", gg->gr_name); + snprintf(g_udesc.user, sizeof(g_udesc.user), "%s", pwd->pw_name); + snprintf(g_udesc.group, sizeof(g_udesc.group), "%s", gg->gr_name); - p_udesc->bus_type = bus_type; - p_udesc->conn = kc; + g_udesc.uid = getuid(); + g_udesc.gid = getgid(); - return 0; + __internal_init_once(); + + return false; } static int bus_path_resolve(const char *bus_path, char *resolved_path, unsigned resolved_path_size, unsigned int *bus_type) @@ -296,62 +200,62 @@ static int bus_path_resolve(const char *bus_path, char *resolved_path, unsigned return 0; } +static bool init_once_done = false; + DBUSPOLICY1_EXPORT void* dbuspolicy1_init(const char *bus_path) { - uint64_t hello_flags = 0; - uint64_t attach_flags_send = _KDBUS_ATTACH_ANY; - uint64_t attach_flags_recv = _KDBUS_ATTACH_ALL; - struct kconn* kc = NULL; - struct udesc* p_udesc = NULL; - unsigned int bus_type = -1; - char resolved_path[PATH_MAX] = { 0 }; - - if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type) < 0) - goto err; - - kc = (struct kconn*) calloc(1, sizeof(struct kconn)); - if (!kc) - goto err; - - if ((kc->fd = kdbus_open_bus(resolved_path)) < 0) - goto err; - - if (kdbus_hello(kc, hello_flags, attach_flags_send, attach_flags_recv) < 0) - goto err; - - if (__internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_PRIMARY : SESSION_BUS_CONF_FILE_PRIMARY) < 0 - && __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY) < 0) - goto err; - - p_udesc = (struct udesc*)malloc(sizeof(struct udesc)); - if (!p_udesc) - goto err; - - if (dbuspolicy_init_udesc(kc, bus_type, p_udesc) < 0) - goto err; - - return p_udesc; - + unsigned int bus_type = -1; + char resolved_path[PATH_MAX] = { 0 }; + int rp, rs; + bool rb; + + _Static_assert(SYSTEM_BUS == 0, "SYSTEM_BUS not 0"); + _Static_assert(SESSION_BUS == 1, "SESSION_BUS not 0"); + + if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type) < 0) + return NULL; + + if (bus_type) + bus_type = SESSION_BUS; + + rb = false; + pthread_mutex_lock(&g_mutex); + if (!init_once_done) { + init_once_done = true; + rb = dbuspolicy_init_once(); + } + pthread_mutex_unlock(&g_mutex); + if (rb) + goto err_close; + + if ((g_conn[bus_type].fd = kdbus_open_bus(resolved_path)) < 0) + goto err; + + if (kdbus_hello(bus_type, 0, _KDBUS_ATTACH_ALL, 0) < 0) + goto err_close; + + rp = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_PRIMARY : SESSION_BUS_CONF_FILE_PRIMARY); + rs = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY); + __internal_init_flush_logs(); + if ((rp & rs) < 0) /* when both negative */ + goto err_close; + + return &g_conn[bus_type]; + +err_close: + close(g_conn[bus_type].fd); err: - if (kc && kc->fd != -1) - close(kc->fd); - free(kc); - free(p_udesc); - - return NULL; + return NULL; } DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration) { - struct udesc* p_udesc = (struct udesc*)configuration; - if(p_udesc) { - close(p_udesc->conn->fd); - free(p_udesc->conn); - free(p_udesc); - p_udesc = NULL; - } + if (configuration) + close(((typeof(&g_conn[0]))configuration)->fd); } +static bool configuration_bus_type(struct kconn const *configuration) { return configuration != g_conn; } + /** * dbuspolicy1_can_send * @param: <> @@ -370,62 +274,103 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration, int reply_serial, int requested_reply) { - struct udesc* const p_udesc = (struct udesc*)configuration; - int i, rs, rr, l, r = 0; - struct kcreds* p_creds = NULL; - char gid[25], uid[25]; - char* name = NULL; - char empty_names = 1; - - rs = 0; - rr = 1; - - if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL || (destination != NULL && *destination != '\0') ) { - p_creds = calloc(1, sizeof(struct kcreds)); - r = kdbus_get_creds_from_name(p_udesc->conn, p_creds, destination); - if(r < 0) { - kcreds_free(p_creds); - return 0; - } - - snprintf(uid, 24, "%lu", (unsigned long int)p_creds->uid); - snprintf(gid, 24, "%lu", (unsigned long int)p_creds->gid); - if (!p_creds->names[0]) - empty_names = 0; - - for (i=0;p_creds->names[i];i++) - { - rs = __internal_can_send(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, p_creds->names[i], path, interface, member, message_type); - if (rs > 0) - break; - } - } + char const *label = NULL; + int r; + uid_t uid_n = UID_INVALID; + gid_t gid_n = GID_INVALID; + bool free_offset = false; + bool empty_names = true; + bool bus_type = configuration_bus_type(configuration); + union { + struct kdbus_cmd_info cmd_info; + struct kdbus_cmd_free cmd_free; + uint8_t _buffer_[sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(MAX_DBUS_NAME_LEN+1)]; + } cmd; + + __internal_enter(); + + if (DBUSPOLICY_MESSAGE_TYPE_SIGNAL != message_type || (destination && *destination)) { + struct kdbus_info *conn_info; + struct kdbus_item *item; + uintptr_t items_end; + + cmd.cmd_info.flags = 0; + cmd.cmd_info.attach_flags = KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | (DBUSPOLICY_MESSAGE_TYPE_SIGNAL != message_type ? KDBUS_ATTACH_SECLABEL : 0); + + if (kdbus_is_unique_id(destination)) { + cmd.cmd_info.size = sizeof(cmd.cmd_info); + cmd.cmd_info.id = kdbus_unique_id(destination); + } else { + int l = strlen(destination); + cmd.cmd_info.size = sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(l+1); + cmd.cmd_info.id = 0; + cmd.cmd_info.items->size = offsetof(struct kdbus_item, data) + l+1; + cmd.cmd_info.items->type = KDBUS_ITEM_NAME; + *(uint64_t*)ALIGNDN8((uintptr_t)cmd.cmd_info.items->str + l) = 0; /* trailing zero + padding */ + memcpy(cmd.cmd_info.items->str, destination, l); + } + + r = ioctl(g_conn[bus_type].fd, KDBUS_CMD_CONN_INFO, &cmd.cmd_info); + if (r < 0) { + r = -errno; + goto end; + } + + cmd.cmd_free.size = sizeof(cmd.cmd_free); + /* flags already 0 */ + _Static_assert(sizeof(cmd.cmd_info.flags) == sizeof(cmd.cmd_free.flags), "cmd_info/cmd_free: flag sizeof differs"); + _Static_assert(offsetof(typeof(cmd.cmd_info), flags) == offsetof(typeof(cmd.cmd_free), flags), "cmd_info/cmd_free: flag offsetof differs"); + cmd.cmd_free.offset = cmd.cmd_info.offset; + + free_offset = true; + + conn_info = (struct kdbus_info *) ((uint8_t *) g_conn[bus_type].pool + cmd.cmd_info.offset); + items_end = (uintptr_t)conn_info + (unsigned)conn_info->size; + + _Static_assert((unsigned)KDBUS_ITEM_CREDS == KDBUS_ITEM_CREDS, "KDBUS_ITEM_CREDS not preserved when cast to unsigned"); + _Static_assert((unsigned)KDBUS_ITEM_SECLABEL == KDBUS_ITEM_SECLABEL, "KDBUS_ITEM_SECLABEL not preserved when cast to unsigned"); + _Static_assert((unsigned)KDBUS_ITEM_OWNED_NAME == KDBUS_ITEM_OWNED_NAME, "KDBUS_ITEM_OWNED_NAME not preserved when cast to unsigned"); + + for (item = conn_info->items; (uintptr_t)item < items_end; item = (typeof(item))ALIGN8((uintptr_t)item + (unsigned)item->size)) + switch ((unsigned)item->type) + { + case KDBUS_ITEM_CREDS: + uid_n = item->creds.euid; + gid_n = item->creds.egid; + break; + case KDBUS_ITEM_SECLABEL: + label = item->str; + break; + case KDBUS_ITEM_OWNED_NAME: + empty_names = false; + if (r <= 0) + r = __internal_can_send(bus_type, g_udesc.user, g_udesc.group, g_udesc.label, item->name.name, path, interface, member, message_type); + break; + } + } if (empty_names) - rs = __internal_can_send(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, destination, path, interface, member, message_type); - - if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) { - rr = 0; - - if (!sender || !(*sender)) - rr = __internal_can_recv(p_udesc->bus_type, uid, gid, p_creds->label, sender, path, interface, member, message_type); - else - FOREACH_STRV(i, l, sender, name) { - char* source; - GET_NEXT_STR(i, name, source); - rr = __internal_can_recv(p_udesc->bus_type, uid, gid, p_creds->label, source, path, interface, member, message_type); - if (rr > 0) - break; - } + r = __internal_can_send(bus_type, g_udesc.user, g_udesc.group, g_udesc.label, destination, path, interface, member, message_type); + + if (r > 0 && message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) { + char gid[25], uid[25]; + char const *ptr; + snprintf(uid, sizeof(uid), "%lu", (unsigned long)uid_n); + snprintf(gid, sizeof(gid), "%lu", (unsigned long)gid_n); + + FOREACH_STRV_DEFAULT(ptr, sender) + if (0 < (r = __internal_can_recv(bus_type, uid, gid, label, ptr, path, interface, member, message_type))) + break; } - free(name); - kcreds_free(p_creds); + if (free_offset) + ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd.cmd_free); - if(rs > 0 && rr > 0) { r = 1; } - if(rs < 0 || rr < 0) { r = -1; } +end: + __internal_exit(); return r; } + /** * dbuspolicy1_can_send * @param: <> @@ -447,55 +392,29 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration, int reply_serial, int requested_reply) { - struct udesc* const p_udesc = (struct udesc*)configuration; - int i, rs, rr, l, r = 0; - struct kcreds* p_creds = NULL; + char const *ptr; + int r; char gid[25], uid[25]; - char* name = NULL; - - rs = 0; - rr = 1; - - snprintf(uid, 24, "%lu", (unsigned long int)sender_uid); - snprintf(gid, 24, "%lu", (unsigned long int)sender_gid); - - if (!destination || !(*destination)) - rs = __internal_can_send(p_udesc->bus_type, uid, gid, sender_label, destination, path, interface, member, message_type); - else - FOREACH_STRV(i, l, destination, name) { - char* dest; - GET_NEXT_STR(i, name, dest); - - rs = __internal_can_send(p_udesc->bus_type, uid, gid, sender_label, dest, path, interface, member, message_type); - if (rs > 0) - break; - } - free(name); - name = NULL; - - if(message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) { - rr = 0; - - if (!sender || !(*sender)) - rr = __internal_can_recv(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, sender, path, interface, member, message_type); - else - FOREACH_STRV(i, l, sender, name) { - char* source; - GET_NEXT_STR(i, name, source); - rr = __internal_can_recv(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, source, path, interface, member, message_type); - if(rr > 0) - break; - } - free(name); - } - kcreds_free(p_creds); + bool bus_type = configuration_bus_type(configuration); + + snprintf(uid, sizeof(uid), "%lu", (unsigned long)sender_uid); + snprintf(gid, sizeof(gid), "%lu", (unsigned long)sender_gid); + + __internal_enter(); - if(rs > 0 && rr > 0) { r = 1; } - if(rs < 0 || rr < 0) { r = -1; } + FOREACH_STRV_DEFAULT(ptr, destination) + if (0 < (r = __internal_can_send(bus_type, uid, gid, sender_label, ptr, path, interface, member, message_type))) + break; + + if (r > 0 && message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) + FOREACH_STRV_DEFAULT(ptr, sender) + if (0 < (r = __internal_can_recv(bus_type, g_udesc.user, g_udesc.group, g_udesc.label, ptr, path, interface, member, message_type))) + break; + + __internal_exit(); return r; } - /** * dbuspolicy1_can_send * @param: <> @@ -505,6 +424,10 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration, **/ DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service) { - struct udesc* const p_udesc = (struct udesc*)configuration; - return __internal_can_own(p_udesc->bus_type, p_udesc->user, p_udesc->group, service); + int r; + bool bus_type = configuration_bus_type(configuration); + __internal_enter(); + r = __internal_can_own(bus_type, g_udesc.user, g_udesc.group, service); + __internal_exit(); + return r; } -- 2.7.4