From: Baumann Date: Mon, 8 Apr 2019 17:19:37 +0000 (+0200) Subject: added dbuspolicy-finder utility X-Git-Tag: accepted/tizen/unified/20190627.014814~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F42%2F205142%2F29;p=platform%2Fcore%2Fsystem%2Flibdbuspolicy.git added dbuspolicy-finder utility It shows filters policies and possible privilege combinations. Change-Id: Ia4078eb76a7fde3fc457280a08189208089464d2 --- diff --git a/Makefile.am b/Makefile.am index 4e1f706..bbf8203 100644 --- a/Makefile.am +++ b/Makefile.am @@ -112,7 +112,17 @@ dbuspolicy_printer_LDADD = src/libinternal.la \ EXTRA_dbuspolicy_printer_DEPENDENCIES = ${top_srcdir}/src/libdbuspolicy1.sym -bin_PROGRAMS = dbuspolicy-serializer dbuspolicy-printer +dbuspolicy_finder_SOURCES =\ + src/dbuspolicy_finder.cpp + +dbuspolicy_finder_CFLAGS="-Isrc/internal/include $(AM_CFLAGS)" + +dbuspolicy_finder_LDADD = src/libinternal.la \ + $(CYNARA_LIBS) \ + $(DLOG_LIBS) \ + -lexpat + +bin_PROGRAMS = dbuspolicy-serializer dbuspolicy-printer dbuspolicy-finder dbuspolicy_printerdir = /bin/ dist_bin_SCRIPTS = src/dbuspolicy-verifier diff --git a/packaging/libdbuspolicy.spec b/packaging/libdbuspolicy.spec index 3b1ce0a..43d32b5 100644 --- a/packaging/libdbuspolicy.spec +++ b/packaging/libdbuspolicy.spec @@ -142,6 +142,7 @@ mv %{_unitdir}/.%{name}.backup.default.target %{_unitdir}/default.target %defattr(-,root,root) %{_bindir}/dbuspolicy-serializer %{_bindir}/dbuspolicy-printer +%{_bindir}/dbuspolicy-finder %files assert-data-valid %manifest %{name}.manifest diff --git a/src/dbuspolicy_finder.cpp b/src/dbuspolicy_finder.cpp new file mode 100644 index 0000000..17e1516 --- /dev/null +++ b/src/dbuspolicy_finder.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2019 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. + */ +#include "internal/policy_containers.hpp" +#include "internal/print_content.hpp" +#include "internal/storage_backend_xml.hpp" +#include "internal/uid_gid_helpers.hpp" +#include "primary-conf-files.c" +#include +#include +#include +#include +#include + +using namespace ldp_xml_parser; +using namespace ldp_xml; + +class Print_once { + bool printing; + const std::string message; + + public: + Print_once(const std::string & _message) + : printing{true}, + message{_message} { + } + + void print() { + if (printing) + std::cout << "\t" << message << std::endl; + printing = false; + } +}; + +static const std::map types { + { "method_call", MessageType::METHOD_CALL }, + {"method_return", MessageType::METHOD_RETURN}, + { "signal", MessageType::SIGNAL }, + { "error", MessageType::ERROR } +}; + +MessageType stringToMessageType(std::string tmp) { + std::transform(tmp.begin(), tmp.end(), tmp.begin(), + [](unsigned char c) { return std::tolower(c); } ); + + const auto iter = types.find(tmp); + + if (iter == types.end()) { + std::cout << "There is no such MessageType" << std::endl; + return MessageType::ANY; + } else { + return iter->second; + } +} + +void printDecision(const Decision & di, const std::string & token, const std::string & extraText, Print_once & printer) { + if (di == Decision::ANY) + return; + printer.print(); + + if (di == Decision::ALLOW) + std::cout << "allow"; + else if (di == Decision::DENY) + std::cout << "deny"; + else if (di == Decision::CHECK) + std::cout << "check"; + std::cout << extraText << "=\"" << token << "\"" << std::endl; +} + +void checkIfMatches(const std::shared_ptr & iter, const MatchItemOwn & mio, const std::string & currentToken, bool noFilter, Print_once & printer) { + const auto & pdi = iter->getOwnPrefixDecisionItem().getDecision(); + const auto & sdi = iter->getOwnDecisionItem ().getDecision(); + static const std::string name("own"); + static const std::string prefix("own_prefix"); + + if (noFilter) { + printDecision(pdi, currentToken, name, printer); + if (iter->getChildren().empty()) + printDecision(sdi, currentToken, name, printer); + } else if (mio.getName() == currentToken) { + printDecision(sdi, currentToken, name, printer); + printDecision(pdi, "", prefix, printer); + } else if (mio.getName().substr(0, currentToken.length()) == currentToken) { + printDecision(pdi, currentToken, prefix, printer); + } else if (mio.getName().empty()) { + if (iter->getChildren().empty()) + printDecision(sdi, currentToken, name, printer); + printDecision(pdi, "", prefix, printer); + } else { + return; + } + + for (const auto & child : iter->getChildren()) { + const auto & childPointer = child.second; + checkIfMatches(childPointer, mio, currentToken + "." + childPointer->getToken(), noFilter, printer); + } +} + +template void matchPolicy(const T & policy, const typename T::item_type::match_type & mi, bool noFilter, const std::string & message) { + Print_once printer(message); + + for (const auto & iter : policy.getItems()) { + if (noFilter || mi.match(iter.getType(), iter.getInterface(), iter.getPath(), iter.getMember(), iter.getName(), iter.isNamePrefix(), Decision::ANY)) { + printer.print(); + std::cout << iter << std::endl; + } + } +} + +template <> void matchPolicy(const PolicyOwn & policy, const MatchItemOwn & mi, bool noFilter, const std::string & message) { + Print_once printer(message); + + for (const auto & child : policy.getTree().getRoot()->getChildren()) { + const auto & childPointer = child.second; + checkIfMatches(childPointer, mi, childPointer->getToken(), noFilter, printer); + } +} + +template <> void matchPolicy(const PolicyAccess & policy, const MatchItemAccess & mi, bool noFilter, const std::string & message) { + Print_once printer(message); + + for (const auto & iter : policy.getItems()) { + if (noFilter || mi.match(iter.getType(), iter.getUid(), iter.getGid())) { + printer.print(); + std::cout << iter << std::endl; + } + } +} + +template void pickPolicy(const StorageBackendXML & storage, const typename T::item_type::match_type & mi, uid_t numberUser, gid_t numberGroup, bool noFilter) { + matchPolicy(storage.getPolicyContextDefault(), mi, noFilter, "Context Default:"); + + const auto & groups = storage.getPoliciesGroup(); + const auto & users = storage.getPoliciesUser(); + + if (numberGroup == ((gid_t) -1) && numberUser == ((uid_t) -1)) { + for (const auto & gid : groups) { + matchPolicy(gid.second, mi, noFilter, std::string("Group:") + std::to_string(gid.first)); + } + for (const auto & uid : users) { + matchPolicy(uid.second, mi, noFilter, std::string("User:") + std::to_string(uid.first)); + } + } else { + if (numberGroup != (gid_t) -1) { + const auto it = groups.find(numberGroup); + if (it == groups.end()) + std::cout << "No rules for group in policy!" << std::endl; + else + matchPolicy(it->second, mi, noFilter, std::string("Group:") + std::to_string(numberGroup)); + } + if (numberUser != (uid_t) -1) { + const auto it = users.find(numberUser); + if (it == users.end()) + std::cout << "No rules for user in policy!" << std::endl; + else + matchPolicy(it->second, mi, noFilter, std::string("User:") + std::to_string(numberUser)); + } + } + matchPolicy(storage.getPolicyContextMandatory(), mi, noFilter, "Context Mandatory:"); +} + +void pickPolicy(const StorageBackendXML & storage, const MatchItemAccess & mi, bool noFilter) { + matchPolicy(storage.getPolicyContextDefault(), mi, noFilter, "Context Default:"); + matchPolicy(storage.getPolicyContextMandatory(), mi, noFilter, "Context Mandatory:"); +} + +template void handlePolicy(const std::string & interface, const std::string & member, const std::string & path, MessageType type, + const std::string & serviceName, const StorageBackendXML & storage, uid_t numberUser, gid_t numberGroup) { + KdbusBusNames names; + typename T::item_type::match_type mi(interface.c_str(), member.c_str(), path.c_str(), type, names.addSpaceSeparatedNames(serviceName.c_str())); + pickPolicy(storage, mi, numberUser, numberGroup, interface.empty() && member.empty() && path.empty() && (type == MessageType::ANY) && serviceName.empty()); +} + +int showHelp() { + std::cout << "\nUsage:\n" + "dbuspolicy-filter {send|receive|access|own} [options]\n" + "\n" + " -c, --configuration {file name} | --session | --system\n" + " -h, --help \thelp\n" + "\n" + "Options for 'send':\n" + " -t, --type=TYPE \ttype {method_call|method_return|signal|error}\n" + " -g, --group=GROUP \tgroup {group_name|gid}\n" + " -u, --user=USER \tuser {username|uid}\n" + " -n, --name \tdestination\n" + " -i, --interface \tinterface\n" + " -p, --path \tpath\n" + " -m, --member \tmember\n" + "Options for 'receive':\n" + " -t, --type=TYPE \ttype {method_call|method_return|signal|error}\n" + " -g, --group=GROUP \tgroup {group_name|gid}\n" + " -u, --user=USER \tuser {username|uid}\n" + " -n, --name \tsender\n" + " -i, --interface \tinterface\n" + " -p, --path \tpath\n" + " -m, --member \tmember\n" + "Options for 'access':\n" + " -g, --group=GROUP \tgroup {group_name|gid}\n" + " -u, --user=USER \tuser {username|uid}\n" + "Options for 'own':\n" + " -g, --group=GROUP \tgroup {group_name|gid}\n" + " -u, --user=USER \tuser {username|uid}\n" + " -n, --name \ta well-known bus name" << std::endl; + return EXIT_SUCCESS; +} + +int bailOut(const std::string & error) { + std::cout << error << std::endl; + showHelp(); + return EXIT_FAILURE; +} + +int main(int argc, char *argv[]) { + tslog::init(); + + int opt; + gid_t numberGroup = (gid_t) -1; + uid_t numberUser = (uid_t) -1; + std::string serviceName = ""; + std::string interface = ""; + std::string path = ""; + std::string member = ""; + MessageType type = MessageType::ANY; + const char * file_name = nullptr; + constexpr int SESSION = 1; + constexpr int SYSTEM = 2; + + const char * const short_opts = ":t:g:u:n:i:p:m:h:c:"; + const option long_opts[] = { + {"type" , required_argument, nullptr, 't'}, + {"group" , required_argument, nullptr, 'g'}, + {"user" , required_argument, nullptr, 'u'}, + {"name" , required_argument, nullptr, 'n'}, + {"interface" , required_argument, nullptr, 'i'}, + {"path" , required_argument, nullptr, 'p'}, + {"member" , required_argument, nullptr, 'm'}, + {"help" , no_argument, nullptr, 'h'}, + {"configuration", required_argument, nullptr, 'c'}, + {"session" , no_argument, nullptr, SESSION}, + {"system" , no_argument, nullptr, SYSTEM}, + {nullptr , 0, nullptr, '\0'} + }; + + while ((opt = getopt_long(argc, argv, short_opts, long_opts, nullptr)) != -1) { + switch (opt) { + case 't': + type = stringToMessageType(optarg); + break; + case 'g': + try { + numberGroup = std::stoi(optarg, nullptr, 10); + } catch (std::invalid_argument & e) { + numberGroup = convertToGid(optarg); + } + break; + case 'u': + try { + numberUser = std::stoi(optarg, nullptr, 10); + } catch (std::invalid_argument & e) { + numberUser = convertToUid(optarg); + } + break; + case 'n': + serviceName = optarg; + break; + case 'i': + interface = optarg; + break; + case 'p': + path = optarg; + break; + case 'm': + member = optarg; + break; + case 'h': + return showHelp(); + case 'c': + if (file_name != nullptr) + return bailOut("Choose only one configuration file!"); + file_name = optarg; + break; + case SESSION: + if (file_name != nullptr) + return bailOut("Choose only one configuration file!"); + file_name = session_bus_conf_file_primary(); + break; + case SYSTEM: + if (file_name != nullptr) + return bailOut("Choose only one configuration file!"); + file_name = system_bus_conf_file_primary(); + break; + case '?': + return bailOut("Unknown parameter!"); + } + } + + std::string mandatory = ""; + + if (optind < argc) { + static const std::array options {{"send", "receive", "own", "access"}}; + std::string tmp(argv[optind]); + std::transform(tmp.begin(), tmp.end(), tmp.begin(), + [](unsigned char c) { return std::tolower(c);}); + + const auto iter = std::find(options.begin(), options.end(), tmp); + + if (iter != options.end()) + mandatory = *iter; + } + if (mandatory.empty()) + return bailOut("Wrong format - mandatory argument is missing, type either 'send', 'receive', 'access' or 'own'!"); + + if (file_name == nullptr) + return bailOut("Please provide configuration file!"); + + StorageBackendXML storage; + storage.init(file_name); + + if (mandatory == "send") { + handlePolicy(interface, member, path, type, serviceName, storage, numberUser, numberGroup); + } else if (mandatory == "receive") { + handlePolicy(interface, member, path, type, serviceName, storage, numberUser, numberGroup); + } else if (mandatory == "access") { + if (!((type == MessageType::ANY) && (serviceName == "") && (interface == "") && (path == "") && (member == ""))) { + return bailOut("Invalid set of arguments"); + } + std::vector gids(1, numberGroup); + MatchItemAccess mia(numberUser, gids); + bool noFilter = (numberUser == ((uid_t) -1)) && gids.empty(); + pickPolicy(storage, mia, noFilter); + } else if (mandatory == "own") { + if (!((type == MessageType::ANY) && (interface == "") && (path == "") && (member == ""))) { + return bailOut("Invalid set of arguments"); + } + MatchItemOwn mio(serviceName.c_str()); + bool noFilter = serviceName.empty(); + pickPolicy(storage, mio, numberUser, numberGroup, noFilter); + } else { + assert(false); + } + return EXIT_SUCCESS; +}