%{script_dir}/sc_test_parser.py
%{_datadir}/security-containers
%{python_sitelib}/sc_integration_tests
+/etc/dbus-1/system.d/org.tizen.containers.tests.conf
"device" : "gpio-keys",
"code" : 139,
"numberOfEvents" : 3,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
mFileMoveRequestCallback = callback;
}
+void ContainerConnection::setProxyCallCallback(const ProxyCallCallback& callback)
+{
+ mProxyCallCallback = callback;
+}
+
void ContainerConnection::onMessageCall(const std::string& objectPath,
const std::string& interface,
const std::string& methodName,
mFileMoveRequestCallback(destination, path, result);
}
}
+
+ if (methodName == api::METHOD_PROXY_CALL) {
+ const gchar* target = NULL;
+ const gchar* targetBusName = NULL;
+ const gchar* targetObjectPath = NULL;
+ const gchar* targetInterface = NULL;
+ const gchar* targetMethod = NULL;
+ GVariant* rawArgs = NULL;
+ g_variant_get(parameters,
+ "(&s&s&s&s&sv)",
+ &target,
+ &targetBusName,
+ &targetObjectPath,
+ &targetInterface,
+ &targetMethod,
+ &rawArgs);
+ dbus::GVariantPtr args(rawArgs, g_variant_unref);
+
+ if (mProxyCallCallback) {
+ mProxyCallCallback(target,
+ targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod,
+ args.get(),
+ result);
+ }
+ }
}
void ContainerConnection::onSignalReceived(const std::string& senderBusName,
parameters);
}
+void ContainerConnection::proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback)
+{
+ mDbusConnection->callMethodAsync(busName,
+ objectPath,
+ interface,
+ method,
+ parameters,
+ std::string(),
+ callback);
+}
+
} // namespace security_containers
dbus::MethodResultBuilder::Pointer result
)> FileMoveRequestCallback;
+ typedef std::function<void(const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod,
+ GVariant* parameters,
+ dbus::MethodResultBuilder::Pointer result
+ )> ProxyCallCallback;
+
/**
* Register notification request callback
*/
void setFileMoveRequestCallback(const FileMoveRequestCallback& callback);
/**
+ * Register proxy call callback
+ */
+ void setProxyCallCallback(const ProxyCallCallback& callback);
+
+ /**
* Send notification signal to this container
*/
void sendNotification(const std::string& container,
const std::string& application,
const std::string& message);
+ /**
+ * Make a proxy call
+ */
+ void proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback);
+
private:
dbus::DbusConnection::Pointer mDbusConnection;
std::mutex mNameMutex;
NotifyActiveContainerCallback mNotifyActiveContainerCallback;
DisplayOffCallback mDisplayOffCallback;
FileMoveRequestCallback mFileMoveRequestCallback;
+ ProxyCallCallback mProxyCallCallback;
void onNameAcquired();
void onNameLost();
const std::string METHOD_NOTIFY_ACTIVE_CONTAINER = "NotifyActiveContainer";
const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest";
+const std::string METHOD_PROXY_CALL = "ProxyCall";
const std::string SIGNAL_NOTIFICATION = "Notification";
const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND";
" <arg type='s' name='path' direction='in'/>"
" <arg type='s' name='result' direction='out'/>"
" </method>"
+ " <method name='" + METHOD_PROXY_CALL + "'>"
+ " <arg type='s' name='target' direction='in'/>"
+ " <arg type='s' name='busName' direction='in'/>"
+ " <arg type='s' name='objectPath' direction='in'/>"
+ " <arg type='s' name='interface' direction='in'/>"
+ " <arg type='s' name='method' direction='in'/>"
+ " <arg type='v' name='parameters' direction='in'/>"
+ " <arg type='v' name='result' direction='out'/>"
+ " </method>"
" <signal name='" + SIGNAL_NOTIFICATION + "'>"
" <arg type='s' name='container'/>"
" <arg type='s' name='application'/>"
if (mFileMoveCallback) {
mConnection->setFileMoveRequestCallback(mFileMoveCallback);
}
+ if (mProxyCallCallback) {
+ mConnection->setProxyCallCallback(mProxyCallCallback);
+ }
// Send to the background only after we're connected,
// otherwise it'd take ages.
}
}
+void Container::setProxyCallCallback(const ProxyCallCallback& callback)
+{
+ Lock lock(mReconnectMutex);
+
+ mProxyCallCallback = callback;
+ if (mConnection) {
+ mConnection->setProxyCallCallback(callback);
+ }
+}
+
+void Container::proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback)
+{
+ Lock lock(mReconnectMutex);
+ if (mConnection) {
+ mConnection->proxyCallAsync(busName,
+ objectPath,
+ interface,
+ method,
+ parameters,
+ callback);
+ } else {
+ LOGE(getId() << ": Can't do a proxy call, no connection to DBUS");
+ }
+}
+
} // namespace security_containers
typedef ContainerConnection::NotifyActiveContainerCallback NotifyActiveContainerCallback;
typedef ContainerConnection::DisplayOffCallback DisplayOffCallback;
typedef ContainerConnection::FileMoveRequestCallback FileMoveRequestCallback;
+ typedef ContainerConnection::ProxyCallCallback ProxyCallCallback;
/**
* Returns a vector of regexps defining files permitted to be
void setDisplayOffCallback(const DisplayOffCallback& callback);
/**
+ * Register proxy call callback
+ */
+ void setProxyCallCallback(const ProxyCallCallback& callback);
+
+ /**
* Send notification signal to this container
*
* @param container name of container in which the notification occurred
*/
void setFileMoveRequestCallback(const FileMoveRequestCallback& callback);
+ /**
+ * Make a proxy call
+ */
+ void proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback);
+
private:
ContainerConfig mConfig;
std::vector<boost::regex> mPermittedToSend;
NotifyActiveContainerCallback mNotifyCallback;
DisplayOffCallback mDisplayOffCallback;
FileMoveRequestCallback mFileMoveCallback;
+ ProxyCallCallback mProxyCallCallback;
std::string mRunMountPoint;
void onNameLostCallback();
#include "config/fields.hpp"
#include "input-monitor-config.hpp"
+#include "proxy-call-config.hpp"
#include <string>
#include <vector>
*/
std::string runMountPointPrefix;
+ /**
+ * Proxy call rules.
+ */
+ std::vector<ProxyCallRule> proxyCallRules;
+
CONFIG_REGISTER
(
containerConfigs,
defaultId,
containersPath,
inputConfig,
- runMountPointPrefix
+ runMountPointPrefix,
+ proxyCallRules
)
};
#include "utils/paths.hpp"
#include "log/logger.hpp"
#include "config/manager.hpp"
+#include "dbus/exception.hpp"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
return false;
}
+const std::string HOST_ID = "host";
+const std::string DBUS_ERROR_NAME_FORBIDDEN = "org.tizen.containers.Error.Forbidden";
+const std::string DBUS_ERROR_NAME_FORWARDED = "org.tizen.containers.Error.Forwarded";
+const std::string DBUS_ERROR_NAME_UNKNOWN_TARGET = "org.tizen.containers.Error.UnknownTarget";
+
} // namespace
ContainersManager::ContainersManager(const std::string& managerConfigPath): mDetachOnExit(false)
LOGD("Instantiating ContainersManager object...");
config::loadFromFile(managerConfigPath, mConfig);
+ mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
+
+ using namespace std::placeholders;
+ mHostConnection.setProxyCallCallback(bind(&ContainersManager::handleProxyCall,
+ this, HOST_ID, _1, _2, _3, _4, _5, _6, _7));
+
for (auto& containerConfig : mConfig.containerConfigs) {
std::string containerConfigPath;
LOGD("Creating Container " << containerConfigPath);
std::unique_ptr<Container> c(new Container(containerConfigPath,
mConfig.runMountPointPrefix));
- std::string id = c->getId();
- using namespace std::placeholders;
+ const std::string id = c->getId();
+ if (id == HOST_ID) {
+ throw ContainerOperationException("Cannot use reserved container ID");
+ }
+
c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler,
this, id, _1, _2));
c->setFileMoveRequestCallback(std::bind(&ContainersManager::handleContainerMoveFileRequest,
this, id, _1, _2, _3));
+ c->setProxyCallCallback(bind(&ContainersManager::handleProxyCall,
+ this, id, _1, _2, _3, _4, _5, _6, _7));
+
mContainers.insert(ContainerMap::value_type(id, std::move(c)));
}
}
}
+void ContainersManager::handleProxyCall(const std::string& caller,
+ const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod,
+ GVariant* parameters,
+ dbus::MethodResultBuilder::Pointer result)
+{
+ if (!mProxyCallPolicy->isProxyCallAllowed(caller,
+ target,
+ targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod)) {
+ LOGW("Forbidden proxy call; " << caller << " -> " << target << "; " << targetBusName
+ << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
+ result->setError(DBUS_ERROR_NAME_FORBIDDEN, "Proxy call forbidden");
+ return;
+ }
+
+ LOGI("Proxy call; " << caller << " -> " << target << "; " << targetBusName
+ << "; " << targetObjectPath << "; " << targetInterface << "; " << targetMethod);
+
+ auto asyncResultCallback = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
+ try {
+ GVariant* targetResult = asyncMethodCallResult.get();
+ result->set(g_variant_new("(v)", targetResult));
+ } catch (dbus::DbusException& e) {
+ result->setError(DBUS_ERROR_NAME_FORWARDED, e.what());
+ }
+ };
+
+ if (target == HOST_ID) {
+ mHostConnection.proxyCallAsync(targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod,
+ parameters,
+ asyncResultCallback);
+ return;
+ }
+
+ ContainerMap::const_iterator targetIter = mContainers.find(target);
+ if (targetIter == mContainers.end()) {
+ LOGE("Target container '" << target << "' not found");
+ result->setError(DBUS_ERROR_NAME_UNKNOWN_TARGET, "Unknown proxy call target");
+ return;
+ }
+
+ Container& targetContainer = *targetIter->second;
+ targetContainer.proxyCallAsync(targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod,
+ parameters,
+ asyncResultCallback);
+}
+
} // namespace security_containers
#include "containers-manager-config.hpp"
#include "host-connection.hpp"
#include "input-monitor.hpp"
+#include "proxy-call-policy.hpp"
#include <string>
#include <unordered_map>
HostConnection mHostConnection;
// to hold InputMonitor pointer to monitor if container switching sequence is recognized
std::unique_ptr<InputMonitor> mSwitchingSequenceMonitor;
+ std::unique_ptr<ProxyCallPolicy> mProxyCallPolicy;
typedef std::unordered_map<std::string, std::unique_ptr<Container>> ContainerMap;
ContainerMap mContainers; // map of containers, id is the key
bool mDetachOnExit;
const std::string& dstContainerId,
const std::string& path,
dbus::MethodResultBuilder::Pointer result);
+ void handleProxyCall(const std::string& caller,
+ const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod,
+ GVariant* parameters,
+ dbus::MethodResultBuilder::Pointer result);
+
};
-}
+} // namespace security_containers
#endif // SERVER_CONTAINERS_MANAGER_HPP
}
}
-void HostConnection::setTestCallback(const TestCallback& callback)
+void HostConnection::setProxyCallCallback(const ProxyCallCallback& callback)
{
- mTestCallback = callback;
+ mProxyCallCallback = callback;
}
void HostConnection::onMessageCall(const std::string& objectPath,
const std::string& interface,
const std::string& methodName,
- GVariant* /*parameters*/,
+ GVariant* parameters,
dbus::MethodResultBuilder::Pointer result)
{
if (objectPath != hostapi::OBJECT_PATH || interface != hostapi::INTERFACE) {
return;
}
- if (methodName == hostapi::METHOD_TEST) {
- if (mTestCallback) {
- mTestCallback();
- result->setVoid();
+ if (methodName == hostapi::METHOD_PROXY_CALL) {
+ const gchar* target = NULL;
+ const gchar* targetBusName = NULL;
+ const gchar* targetObjectPath = NULL;
+ const gchar* targetInterface = NULL;
+ const gchar* targetMethod = NULL;
+ GVariant* rawArgs = NULL;
+ g_variant_get(parameters,
+ "(&s&s&s&s&sv)",
+ &target,
+ &targetBusName,
+ &targetObjectPath,
+ &targetInterface,
+ &targetMethod,
+ &rawArgs);
+ dbus::GVariantPtr args(rawArgs, g_variant_unref);
+
+ if (mProxyCallCallback) {
+ mProxyCallCallback(target,
+ targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod,
+ args.get(),
+ result);
}
}
}
+void HostConnection::proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback)
+{
+ mDbusConnection->callMethodAsync(busName,
+ objectPath,
+ interface,
+ method,
+ parameters,
+ std::string(),
+ callback);
+}
+
} // namespace security_containers
// ------------- API --------------
- typedef std::function<void()> TestCallback;
+ typedef std::function<void(const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod,
+ GVariant* parameters,
+ dbus::MethodResultBuilder::Pointer result)> ProxyCallCallback;
/**
- * Register test callback
+ * Register proxy call callback
*/
- void setTestCallback(const TestCallback& callback);
+ void setProxyCallCallback(const ProxyCallCallback& callback);
+
+ /**
+ * Make a proxy call
+ */
+ void proxyCallAsync(const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters,
+ const dbus::DbusConnection::AsyncMethodCallCallback& callback);
private:
dbus::DbusConnection::Pointer mDbusConnection;
std::condition_variable mNameCondition;
bool mNameAcquired;
bool mNameLost;
- TestCallback mTestCallback;
+ ProxyCallCallback mProxyCallCallback;
void onNameAcquired();
void onNameLost();
const std::string BUS_NAME = "org.tizen.containers.host";
const std::string OBJECT_PATH = "/org/tizen/containers/host";
-const std::string INTERFACE = "org.tizen.containers.host.test";
+const std::string INTERFACE = "org.tizen.containers.host.manager";
-const std::string METHOD_TEST = "Test";
+const std::string METHOD_PROXY_CALL = "ProxyCall";
const std::string DEFINITION =
"<node>"
" <interface name='" + INTERFACE + "'>"
- " <method name='" + METHOD_TEST + "'>"
+ " <method name='" + METHOD_PROXY_CALL + "'>"
+ " <arg type='s' name='target' direction='in'/>"
+ " <arg type='s' name='busName' direction='in'/>"
+ " <arg type='s' name='objectPath' direction='in'/>"
+ " <arg type='s' name='interface' direction='in'/>"
+ " <arg type='s' name='method' direction='in'/>"
+ " <arg type='v' name='parameters' direction='in'/>"
+ " <arg type='v' name='result' direction='out'/>"
" </method>"
" </interface>"
"</node>";
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Declaration of the struct for storing proxy call configuration
+ */
+
+
+#ifndef SERVER_PROXY_CALL_CONFIG_HPP
+#define SERVER_PROXY_CALL_CONFIG_HPP
+
+
+#include "config/fields.hpp"
+
+#include <string>
+
+
+namespace security_containers {
+
+/**
+ * A single allow rule for proxy call dispatching.
+ */
+struct ProxyCallRule {
+
+ std::string caller; ///< caller id (container id or host)
+ std::string target; ///< target id (container id or host)
+ std::string targetBusName; ///< target dbus bus name
+ std::string targetObjectPath; ///< target dbus object path
+ std::string targetInterface; ///< target dbus interface
+ std::string targetMethod; ///< target dbus method
+
+ CONFIG_REGISTER
+ (
+ caller,
+ target,
+ targetBusName,
+ targetObjectPath,
+ targetInterface,
+ targetMethod
+ )
+
+};
+
+} // namespace security_containers
+
+#endif /* SERVER_PROXY_CALL_CONFIG_HPP */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Implementation of a class for checking permissions of proxy calls
+ */
+
+
+#include "config.hpp"
+
+#include "proxy-call-policy.hpp"
+
+
+namespace security_containers {
+
+namespace {
+const std::string ANY = "*";
+
+inline bool match(const std::string& rule, const std::string& value) {
+ // simple matching, change to regex if it turns out to be insufficient
+ return rule == ANY || rule == value;
+}
+
+} // namespace
+
+
+ProxyCallPolicy::ProxyCallPolicy(const std::vector<ProxyCallRule>& proxyCallRules)
+ : mProxyCallRules(proxyCallRules)
+{
+}
+
+bool ProxyCallPolicy::isProxyCallAllowed(const std::string& caller,
+ const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod)
+{
+ for (const ProxyCallRule& rule : mProxyCallRules) {
+ if (match(rule.caller, caller)
+ && match(rule.target, target)
+ && match(rule.targetBusName, targetBusName)
+ && match(rule.targetObjectPath, targetObjectPath)
+ && match(rule.targetInterface, targetInterface)
+ && match(rule.targetMethod, targetMethod)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+} // namespace security_containers
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Declaration of a class for checking permissions of proxy calls
+ */
+
+
+#ifndef SERVER_PROXY_CALL_POLICY_HPP
+#define SERVER_PROXY_CALL_POLICY_HPP
+
+#include "proxy-call-config.hpp"
+
+#include <vector>
+
+
+namespace security_containers {
+
+
+class ProxyCallPolicy {
+
+public:
+ ProxyCallPolicy(const std::vector<ProxyCallRule>& proxyCallRules);
+
+ bool isProxyCallAllowed(const std::string& caller,
+ const std::string& target,
+ const std::string& targetBusName,
+ const std::string& targetObjectPath,
+ const std::string& targetInterface,
+ const std::string& targetMethod);
+
+private:
+ std::vector<ProxyCallRule> mProxyCallRules;
+};
+
+
+} // namespace security_containers
+
+
+#endif // SERVER_PROXY_CALL_POLICY_HPP
INSTALL(FILES ${connection_CONF}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-container-connection)
+
+INSTALL(FILES dbus-1/system.d/org.tizen.containers.tests.conf
+ DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/)
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<busconfig>
+ <policy user="root">
+ <allow own="org.tizen.containers.tests"/>
+ <allow send_destination="org.tizen.containers.tests"/>
+ <allow receive_sender="org.tizen.containers.tests"/>
+ </policy>
+ <policy context="default">
+ <allow send_destination="org.tizen.containers.tests"/>
+ <allow receive_sender="org.tizen.containers.tests"/>
+ </policy>
+</busconfig>
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : [{"caller" : "*",
+ "target" : "*",
+ "targetBusName" : "org.tizen.containers.tests",
+ "targetObjectPath" : "*",
+ "targetInterface" : "*",
+ "targetMethod" : "*"}]
}
"device" : "/dev/doesnotexist",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
"device" : "gpio-keys.4",
"code" : 139,
"numberOfEvents" : 2,
- "timeWindowMs" : 500}
+ "timeWindowMs" : 500},
+ "proxyCallRules" : []
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Common definitions for dbus tests
+ */
+
+#ifndef UNIT_TESTS_SERVER_TEST_DBUS_DEFINITIONS_HPP
+#define UNIT_TESTS_SERVER_TEST_DBUS_DEFINITIONS_HPP
+
+#include <string>
+
+
+namespace security_containers {
+namespace testapi {
+
+
+const std::string BUS_NAME = "org.tizen.containers.tests";
+const std::string OBJECT_PATH = "/org/tizen/containers/tests";
+const std::string INTERFACE = "tests.api";
+const std::string METHOD = "Method";
+
+const std::string DEFINITION =
+ "<node>"
+ " <interface name='" + INTERFACE + "'>"
+ " <method name='" + METHOD + "'>"
+ " <arg type='s' name='argument' direction='in'/>"
+ " <arg type='s' name='response' direction='out'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+
+} // namespace testapi
+} // namespace security_containers
+
+
+#endif // UNIT_TESTS_SERVER_TEST_DBUS_DEFINITIONS_HPP
#include "containers-manager.hpp"
#include "container-dbus-definitions.hpp"
+#include "host-dbus-definitions.hpp"
+#include "test-dbus-definitions.hpp"
// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager
#include "fake-power-manager-dbus-definitions.hpp"
#include "exception.hpp"
class DbusAccessory {
public:
+ typedef std::function<void(const std::string& argument,
+ MethodResultBuilder::Pointer result
+ )> TestApiMethodCallback;
+
DbusAccessory(int id)
: mId(id),
mClient(DbusConnection::create(acquireAddress())),
return std::string(retcode);
}
+ void registerTestApiObject(const TestApiMethodCallback& callback)
+ {
+ auto handler = [callback](const std::string& objectPath,
+ const std::string& interface,
+ const std::string& methodName,
+ GVariant* parameters,
+ MethodResultBuilder::Pointer result) {
+ if (objectPath == testapi::OBJECT_PATH &&
+ interface == testapi::INTERFACE &&
+ methodName == testapi::METHOD) {
+ const gchar* argument = NULL;
+ g_variant_get(parameters, "(&s)", &argument);
+ if (callback) {
+ callback(argument, result);
+ }
+ }
+ };
+ mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler);
+ }
+
+ std::string testApiProxyCall(const std::string& target, const std::string& argument)
+ {
+ GVariant* parameters = g_variant_new("(s)", argument.c_str());
+ GVariantPtr result = proxyCall(target,
+ testapi::BUS_NAME,
+ testapi::OBJECT_PATH,
+ testapi::INTERFACE,
+ testapi::METHOD,
+ parameters);
+ const gchar* ret = NULL;
+ g_variant_get(result.get(), "(&s)", &ret);
+ return ret;
+ }
+
+
+ GVariantPtr proxyCall(const std::string& target,
+ const std::string& busName,
+ const std::string& objectPath,
+ const std::string& interface,
+ const std::string& method,
+ GVariant* parameters)
+ {
+ GVariant* packedParameters = g_variant_new("(sssssv)",
+ target.c_str(),
+ busName.c_str(),
+ objectPath.c_str(),
+ interface.c_str(),
+ method.c_str(),
+ parameters);
+ GVariantPtr result = mClient->callMethod(isHost() ? hostapi::BUS_NAME : api::BUS_NAME,
+ isHost() ? hostapi::OBJECT_PATH : api::OBJECT_PATH,
+ isHost() ? hostapi::INTERFACE : api::INTERFACE,
+ isHost() ? hostapi::METHOD_PROXY_CALL : api::METHOD_PROXY_CALL,
+ packedParameters,
+ "(v)");
+ GVariant* unpackedResult = NULL;
+ g_variant_get(result.get(), "(v)", &unpackedResult);
+ return GVariantPtr(unpackedResult, g_variant_unref);
+ }
private:
const int mId;
DbusConnection::Pointer mClient;
std::mutex mMutex;
std::condition_variable mNameCondition;
+ bool isHost() const {
+ return mId == 0;
+ }
+
std::string acquireAddress() const
{
+ if (isHost()) {
+ return "unix:path=/var/run/dbus/system_bus_socket";
+ }
return "unix:path=/tmp/ut-containers-manager/console" + std::to_string(mId) +
"-dbus/dbus/system_bus_socket";
}
};
+std::function<bool(const std::exception&)> expectedMessage(const std::string& message) {
+ return [=](const std::exception& e) {
+ return e.what() == message;
+ };
+}
struct Fixture {
utils::ScopedGlibLoop mLoop;
}
}
+BOOST_AUTO_TEST_CASE(ProxyCallTest)
+{
+ ContainersManager cm(TEST_DBUS_CONFIG_PATH);
+ cm.startAll();
+
+ std::map<int, std::unique_ptr<DbusAccessory>> dbuses;
+ for (int i = 0; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
+ dbuses[i] = std::unique_ptr<DbusAccessory>(new DbusAccessory(i));
+ }
+
+ for (auto& dbus : dbuses) {
+ dbus.second->setName(testapi::BUS_NAME);
+
+ const int id = dbus.first;
+ auto handler = [id](const std::string& argument, MethodResultBuilder::Pointer result) {
+ if (argument.empty()) {
+ result->setError("org.tizen.containers.Error.Test", "Test error");
+ } else {
+ std::string ret = "reply from " + std::to_string(id) + ": " + argument;
+ result->set(g_variant_new("(s)", ret.c_str()));
+ }
+ };
+ dbus.second->registerTestApiObject(handler);
+ }
+
+ // host -> container2
+ BOOST_CHECK_EQUAL("reply from 2: param1",
+ dbuses.at(0)->testApiProxyCall("ut-containers-manager-console2-dbus",
+ "param1"));
+
+ // host -> host
+ BOOST_CHECK_EQUAL("reply from 0: param2",
+ dbuses.at(0)->testApiProxyCall("host",
+ "param2"));
+
+ // container1 -> host
+ BOOST_CHECK_EQUAL("reply from 0: param3",
+ dbuses.at(1)->testApiProxyCall("host",
+ "param3"));
+
+ // container1 -> container2
+ BOOST_CHECK_EQUAL("reply from 2: param4",
+ dbuses.at(1)->testApiProxyCall("ut-containers-manager-console2-dbus",
+ "param4"));
+
+ // container2 -> container2
+ BOOST_CHECK_EQUAL("reply from 2: param5",
+ dbuses.at(2)->testApiProxyCall("ut-containers-manager-console2-dbus",
+ "param5"));
+
+ // host -> unknown
+ BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("unknown", "param"),
+ DbusCustomException,
+ expectedMessage("Unknown proxy call target"));
+
+ // forwarding error
+ BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("host", ""),
+ DbusCustomException,
+ expectedMessage("Test error"));
+
+ // forbidden call
+ BOOST_CHECK_EXCEPTION(dbuses.at(0)->proxyCall("host",
+ "org.fake",
+ "/a/b",
+ "c.d",
+ "foo",
+ g_variant_new("(s)", "arg")),
+ DbusCustomException,
+ expectedMessage("Proxy call forbidden"));
+}
+
BOOST_AUTO_TEST_SUITE_END()