+
+// TODO: Create utility namespace for DBus, maybe?
+DBusConnectionPtr createDBusConnection(const std::string &name) {
+ DBusError err;
+
+ dbus_error_init(&err);
+ DBusConnection *conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
+ RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != 1, "Error in dbus_bus_get: " << err.message);
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+
+ DBusConnectionPtr ret(conn, [] (DBusConnection *conn) {
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ });
+
+ if (name.empty() == false) {
+ dbus_bus_request_name(conn, name.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
+ RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != TRUE,
+ "Error in dbus_bus_request_name: " << err.message);
+ }
+
+ return ret;
+}
+
+void dbusServer(SynchronizationPipe &pipe, const std::string &requestedName,
+ const ProcessCredentials &peerCredentials) {
+ // for DBus connection, System must have access to our peer creds as well.
+ SecurityServer::AccessProvider systemAp("System");
+ systemAp.addObjectRule(peerCredentials.label(), "rwx");
+ systemAp.apply();
+
+ SecurityServer::AccessProvider ap(peerCredentials.label());
+ ap.addObjectRule("System", "w");
+ ap.addObjectRule("System::Run", "x");
+ ap.addObjectRule("System::Shared", "x"); // for GDB
+ ap.addObjectRule("User", "r"); // for /usr/lib/debug access
+ ap.applyAndSwithToUser(peerCredentials.uid(), peerCredentials.gid());
+ pipe.claimChildEp();
+
+ auto conn = createDBusConnection(requestedName);
+ pipe.post();
+ pipe.wait();
+}
+
+typedef std::function<void(DBusConnectionPtr conn, pid_t pid,
+ const std::string &requestedName,
+ const ProcessCredentials &peerCredentials)> DBusAssertionFn;
+
+void dbusTestTemplate(DBusAssertionFn assertion, const std::string &/*scope*/) {
+ std::string requestedName = "tests.dbus.cynara";
+ const ProcessCredentials peerCredentials;
+
+ SynchronizationPipe pipe;
+ pid_t pid = runInChild(std::bind(dbusServer, std::ref(pipe), std::cref(requestedName),
+ std::cref(peerCredentials)));
+
+ pipe.claimParentEp();
+ pipe.wait();
+
+ auto conn = createDBusConnection("");
+ assertion(std::move(conn), pid, requestedName, peerCredentials);
+ pipe.post();
+}
+
+RUNNER_TEST_GROUP_INIT(cynara_creds_dbus)
+
+RUNNER_TEST_SMACK(tccd01_dbus_credentials_client_pid) {
+ dbusTestTemplate([] (DBusConnectionPtr conn, pid_t pid, const std::string &requestedName,
+ const ProcessCredentials &) {
+ CStringPtr clientPidStr(CynaraHelperCredentials::dbusGetClient(std::move(conn),
+ requestedName.c_str(), CLIENT_METHOD_PID, CYNARA_API_SUCCESS));
+ pid_t clientPid = std::stoi(clientPidStr.get());
+ RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
+ << "; expected = " << pid);
+ }, "tccd01");
+}
+
+RUNNER_TEST_SMACK(tccd02_dbus_credentials_client_smack) {
+ dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
+ const ProcessCredentials &peerCredentials) {
+ CStringPtr label(CynaraHelperCredentials::dbusGetClient(std::move(conn),
+ requestedName.c_str(), CLIENT_METHOD_SMACK, CYNARA_API_SUCCESS));
+ RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
+ "Labels don't match ret = " << label.get()
+ << "; expected = " << peerCredentials.label());
+ }, "tccd02");
+}
+
+RUNNER_TEST_SMACK(tccd03_dbus_credentials_user_uid) {
+ dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
+ const ProcessCredentials &peerCredentials) {
+ CStringPtr uidStr(CynaraHelperCredentials::dbusGetUser(std::move(conn),
+ requestedName.c_str(), USER_METHOD_UID, CYNARA_API_SUCCESS));
+ uid_t uid = std::stoul(uidStr.get());
+ RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
+ << "; expected = "<< peerCredentials.uid());
+ }, "tccd03");
+}
+
+RUNNER_TEST_SMACK(tccd04_dbus_credentials_pid) {
+ dbusTestTemplate([] (DBusConnectionPtr conn, pid_t expectedPid,
+ const std::string &requestedName, const ProcessCredentials &) {
+ auto helperPid = CynaraHelperCredentials::dbusGetPid(std::move(conn),
+ requestedName.c_str(), CYNARA_API_SUCCESS);
+ RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
+ << "; expected = " << expectedPid);
+ }, "tccd04");
+}