${CMAKE_SOURCE_DIR}/src
)
-SET(${this_target}_requires "dlog bundle glib-2.0 gio-2.0 aul capi-base-common pkgmgr-info gio-unix-2.0")
+SET(${this_target}_requires "dlog bundle glib-2.0 gio-2.0 aul capi-base-common pkgmgr-info gio-unix-2.0 cynara-client cynara-creds-gdbus")
INCLUDE(FindPkgConfig)
pkg_check_modules(${this_target} REQUIRED ${${this_target}_requires})
int rpc_port_stub_create(rpc_port_stub_h *h, const char *port_name);
int rpc_port_stub_destroy(rpc_port_stub_h h);
int rpc_port_stub_listen(rpc_port_stub_h h);
+int rpc_port_stub_add_privilege(rpc_port_stub_h h, const char *privilege);
int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h,
rpc_port_stub_connected_event_cb cb, void *data);
int rpc_port_stub_add_disconnected_event_cb(rpc_port_stub_h h,
BuildRequires: pkgconfig(pkgmgr)
BuildRequires: pkgconfig(pkgmgr-info)
BuildRequires: pkgconfig(gmock)
+BuildRequires: pkgconfig(cynara-client)
+BuildRequires: pkgconfig(cynara-creds-gdbus)
Requires(post): /sbin/ldconfig
Requires(post): coreutils
--- /dev/null
+/*
+ * Copyright (c) 2017 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 _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <dlog.h>
+#include <cynara-error.h>
+#include <cynara-creds-gdbus.h>
+
+#include "ac-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+namespace rpc_port {
+namespace internal {
+
+AccessController::~AccessController() {}
+
+void AccessController::AddPrivilege(const std::string& privilege) {
+ privileges_.push_back(privilege);
+}
+
+int AccessController::CheckPrivilege(GDBusConnection *connection, const char* sender_appid) {
+ Cynara c;
+
+ if (c.FetchCredsFromDBus(connection, sender_appid) != 0 )
+ return -1;
+
+ for (auto& privilege : privileges_) {
+ if (c.Check(privilege) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int AccessController::SetCache(const std::string& sender) {
+ return -1;
+}
+
+AccessController::Cynara::Cynara() {
+ cynara_ = nullptr;
+ client_ = nullptr;
+ user_ = nullptr;
+
+ if (cynara_initialize(&cynara_, NULL) != CYNARA_API_SUCCESS) {
+ LOGE("cynara_initialize() is failed");
+ }
+}
+
+AccessController::Cynara::~Cynara() {
+ if (client_)
+ free(client_);
+ if (user_)
+ free(user_);
+ if (cynara_)
+ cynara_finish(cynara_);
+}
+
+int AccessController::Cynara::FetchCredsFromDBus(GDBusConnection *connection, const char *sender_appid) {
+ int ret;
+
+ if (client_) {
+ free(client_);
+ client_ = nullptr;
+ }
+
+ if (user_) {
+ free(user_);
+ user_ = nullptr;
+ }
+
+ ret = cynara_creds_gdbus_get_user(connection, sender_appid, USER_METHOD_DEFAULT, &user_);
+ if (ret != CYNARA_API_SUCCESS) {
+ LOGE("cynara_creds_gdbus_get_user() is failed : %d", ret);
+ return -1;
+ }
+
+ ret = cynara_creds_gdbus_get_client(connection, sender_appid, CLIENT_METHOD_DEFAULT, &client_);
+ if (ret != CYNARA_API_SUCCESS) {
+ LOGE("cynara_creds_gdbus_get_client() is failed : %d", ret);
+ return -1;
+ }
+
+ LOGD("cred client : %s, cred user : %s", client_, user_);
+ return 0;
+}
+
+int AccessController::Cynara::Check(const std::string& privilege) {
+ LOGD("check %s", privilege.c_str());
+ if (cynara_check(cynara_, client_, "", user_, privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) {
+ LOGE("cynara_check() is failed : %s", privilege.c_str());
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace internal
+} // namespace rpc_port
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 AC_INTERNAL_H_
+#define AC_INTERNAL_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+#include <cynara-client.h>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace rpc_port {
+namespace internal {
+
+class AccessController {
+ public:
+ virtual ~AccessController();
+
+ void AddPrivilege(const std::string& privilege);
+ int CheckPrivilege(GDBusConnection *connection, const char* sender_appid);
+
+ private:
+ int SetCache(const std::string& sender);
+
+ class Cynara {
+ public:
+ Cynara();
+ ~Cynara();
+
+ int FetchCredsFromDBus(GDBusConnection *connection, const char *sender_appid);
+ int Check(const std::string& privilege);
+
+ private:
+ cynara *cynara_;
+ char *client_;
+ char *user_;
+ };
+
+ private:
+ std::vector<std::string> privileges_;
+ std::map<std::string, bool> cache_;
+};
+
+} // namespace internal
+} // namespace rpc_port
+
+#endif // AC_INTERNAL_H_
char c_buf[interface_name.length() * 2 + 1] = {0};
char* temp = &c_buf[0];
- for (int index = 0; index < interface_name.length(); index++) {
+ for (unsigned int index = 0; index < interface_name.length(); index++) {
snprintf(temp, 3, "%02x", interface_name[index]);
temp += 2;
}
const std::string& port_name) {
std::string interface_name = GetInterfaceName(target_appid, port_name);
GDBusMessage *msg;
+ GDBusMessage *reply;
GError *err = nullptr;
GVariant *body;
+ GVariant *reply_body;
SocketPair sock_pair(mock_);
FdList fd_list;
char sender_appid[255];
+ int ret;
if (!mock_ && aul_app_get_appid_bypid(getpid(),
sender_appid, sizeof(sender_appid)) < 0) {
body = g_variant_new("(s)", sender_appid);
g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw());
g_dbus_message_set_body(msg, body);
- g_dbus_connection_send_message(DBusConnectionManager::GetInst().GetConnection(),
- msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
- nullptr, &err);
- if (err != nullptr) {
+ reply = g_dbus_connection_send_message_with_reply_sync(DBusConnectionManager::GetInst().GetConnection(),
+ msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 500,
+ nullptr, nullptr, &err);
+ if (reply == nullptr) {
LOGE("No reply. error = %s", err->message);
g_error_free(err);
g_object_unref(msg);
return -1;
}
+ reply_body = g_dbus_message_get_body(reply);
+ if (reply_body == nullptr) {
+ LOGE("g_dbus_message_get_body() is failed");
+ g_object_unref(msg);
+ return -1;
+ }
+
+ g_variant_get(reply_body, "(i)", &ret);
+
+ if (ret != 0) {
+ LOGE("Access Denied[sender_appid : %s]", sender_appid);
+ g_object_unref(msg);
+ g_object_unref(reply);
+ return -1;
+ }
+
+ LOGD("[Reply : %d]", ret);
+
int fd = sock_pair.Detach(SocketPair::SENDER);
g_object_unref(msg);
GVariant *parameters, GDBusMethodInvocation *invocation,
gpointer user_data) {
FdBroker* broker = static_cast<FdBroker*>(user_data);
+ int ret;
- broker->ReceiveMessage(parameters, invocation);
- g_dbus_method_invocation_return_value(invocation, nullptr);
+ AccessController& ac = broker->GetAccessController();
+ ret = ac.CheckPrivilege(conn, sender);
+ if (ret == 0)
+ broker->ReceiveMessage(parameters, invocation);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
}
int FdBroker::GetOwnerId(const std::string& interface_name) {
"'>"
" <method name='send_message'>"
" <arg type='s' name='sender_appid' direction='in'/>"
+ " <arg type='i' name='response' direction='out'/>"
" </method>"
" </interface>"
"</node>";
return 0;
}
+AccessController& FdBroker::GetAccessController() {
+ return ac_;
+}
+
} // namespace internal
-} // namespace rpc_port
\ No newline at end of file
+} // namespace rpc_port
#include <map>
#include <memory>
+#include "ac-internal.h"
+
namespace rpc_port {
namespace internal {
int Send(const std::string& target_appid, const std::string& port_name);
int Listen(IEventListener* ev, const std::string& port_name);
+ AccessController& GetAccessController();
private:
class DBusConnectionManager {
IEventListener* listener_ = nullptr;
int registration_id_ = 0;
bool mock_;
+ AccessController ac_;
};
} // namespace internal
return 0;
}
+RPC_API int rpc_port_stub_add_privilege(rpc_port_stub_h h,
+ const char* privilege) {
+ if (h == nullptr)
+ return -1;
+
+ auto p = static_cast<::StubExt*>(h);
+ p->AddPrivilege(privilege);
+ return 0;
+}
+
RPC_API int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h,
rpc_port_stub_connected_event_cb cb, void* data) {
if (h == nullptr)
fd_broker_.Listen(this, port_name_);
}
+void Stub::AddPrivilege(const std::string& privilege) {
+ AccessController& ac = fd_broker_.GetAccessController();
+ ac.AddPrivilege(privilege);
+}
+
gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond,
gpointer data) {
Stub* stub = static_cast<Stub*>(data);
}
} // namespace internal
-} // namespace rpc_port
\ No newline at end of file
+} // namespace rpc_port
virtual ~Stub();
void Listen(IEventListener* ev);
+ void AddPrivilege(const std::string& privilege);
private:
class AcceptedPort : public Port {
}, this);
ASSERT_EQ(ret, 0);
+ ret = rpc_port_stub_add_privilege(stub_handle_,
+ "http://tizen.org/privilege/appmanager.launch");
+ ASSERT_EQ(ret, 0);
+
ret = rpc_port_stub_listen(stub_handle_);
ASSERT_EQ(ret, 0);
}