--- /dev/null
+/*
+ * 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 <cassert>
+#include <getopt.h>
+#include <iostream>
+#include <string>
+#include <vector>
+
+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<std::string, MessageType> 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<TreeNode> & 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 <typename T> 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<PolicyOwn>(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<PolicyAccess>(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 <typename T> void pickPolicy(const StorageBackendXML & storage, const typename T::item_type::match_type & mi, uid_t numberUser, gid_t numberGroup, bool noFilter) {
+ matchPolicy<T>(storage.getPolicyContextDefault<T>(), mi, noFilter, "Context Default:");
+
+ const auto & groups = storage.getPoliciesGroup<T>();
+ const auto & users = storage.getPoliciesUser<T>();
+
+ if (numberGroup == ((gid_t) -1) && numberUser == ((uid_t) -1)) {
+ for (const auto & gid : groups) {
+ matchPolicy<T>(gid.second, mi, noFilter, std::string("Group:") + std::to_string(gid.first));
+ }
+ for (const auto & uid : users) {
+ matchPolicy<T>(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<T>(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<T>(it->second, mi, noFilter, std::string("User:") + std::to_string(numberUser));
+ }
+ }
+ matchPolicy<T>(storage.getPolicyContextMandatory<T>(), mi, noFilter, "Context Mandatory:");
+}
+
+void pickPolicy(const StorageBackendXML & storage, const MatchItemAccess & mi, bool noFilter) {
+ matchPolicy<PolicyAccess>(storage.getPolicyContextDefault<PolicyAccess>(), mi, noFilter, "Context Default:");
+ matchPolicy<PolicyAccess>(storage.getPolicyContextMandatory<PolicyAccess>(), mi, noFilter, "Context Mandatory:");
+}
+
+template <typename T> 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<T>(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<const std::string, 4> 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<PolicySend>(interface, member, path, type, serviceName, storage, numberUser, numberGroup);
+ } else if (mandatory == "receive") {
+ handlePolicy<PolicyReceive>(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<gid_t> 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<PolicyOwn>(storage, mio, numberUser, numberGroup, noFilter);
+ } else {
+ assert(false);
+ }
+ return EXIT_SUCCESS;
+}