The implementation is changed to c++.
Change-Id: I92cbd3288c77c5e6465b49f2187087bf97353fa0
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
-AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src AMD_MOD_RPC_PORT_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} AMD_MOD_RPC_PORT_SRCS)
ADD_LIBRARY(${TARGET_AMD_MOD_RPC_PORT} ${AMD_MOD_RPC_PORT_SRCS})
--- /dev/null
+/*
+ * Copyright (c) 2018 - 2021 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 <amd.h>
+#include <amd_mod_common.h>
+#include <aul.h>
+#include <aul_cmd.h>
+#include <aul_rpc_port.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <bundle_cpp.h>
+#include <bundle_internal.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <vconf.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "log_private.hh"
+
+namespace {
+
+class MetadataInfo {
+ public:
+ MetadataInfo(std::string value) : value_(std::move(value)) {
+ }
+
+ ~MetadataInfo() = default;
+
+ bool Match(const std::string& value) {
+ if (value == value_) {
+ exist_ = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool Exist() {
+ return exist_;
+ }
+
+ private:
+ std::string value_;
+ bool exist_ = false;
+};
+
+constexpr const char kPrivilegeDataSharing[] =
+ "http://tizen.org/privilege/datasharing";
+constexpr const char kPrivilegeCheckBypass[] =
+ "http://tizen.org/rpc-port/privilege-check-bypass";
+
+std::unordered_map<int, int> pid_map;
+std::string tts_engine_default;
+std::string tts_engine_noti_default;
+std::string tts_engine_sr_default;
+std::string tts_engine_interrupt_default;
+
+void SetTTSEngineDefault(std::string tts_engine) {
+ tts_engine_default = std::move(tts_engine);
+ tts_engine_noti_default = tts_engine_default + "-noti";
+ tts_engine_sr_default = tts_engine_default + "-sr";
+ tts_engine_interrupt_default = tts_engine_default + "-interrupt";
+}
+
+bool IsDefaultTTSEngine(const std::string& app_id) {
+ if (tts_engine_default.empty())
+ return false;
+
+ if (tts_engine_default == app_id)
+ return true;
+
+ if (tts_engine_noti_default == app_id)
+ return true;
+
+ if (tts_engine_sr_default == app_id)
+ return true;
+
+ if (tts_engine_interrupt_default == app_id)
+ return true;
+
+ return false;
+}
+
+void RpcRef(int pid) {
+ auto found = pid_map.find(pid);
+ if (found == pid_map.end()) {
+ pid_map[pid] = 1;
+ amd_suspend_remove_timer(pid);
+ amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_EXCLUDE);
+ } else {
+ found->second++;
+ }
+}
+
+void RpcUnref(int pid) {
+ auto found = pid_map.find(pid);
+ if (found == pid_map.end())
+ return;
+
+ found->second--;
+ if (found->second == 0) {
+ pid_map.erase(found);
+ amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_INCLUDE);
+ amd_app_status_h app_status = amd_app_status_find_by_pid(pid);
+ if (app_status) {
+ int status = amd_app_status_get_status(app_status);
+ if (status != STATUS_VISIBLE && status != STATUS_DYING)
+ amd_suspend_add_timer(pid);
+ }
+ }
+}
+
+void RpcRemove(int pid) {
+ auto found = pid_map.find(pid);
+ if (found == pid_map.end())
+ return;
+
+ pid_map.erase(found);
+}
+
+void SetRealAppId(uid_t uid, tizen_base::Bundle& b) {
+ std::string alias_appid = b.GetString(AUL_K_APPID);
+ if (alias_appid.empty())
+ return;
+
+ std::string alias_info = b.GetString(AUL_SVC_K_ALIAS_INFO);
+ if (alias_info == "disable")
+ return;
+
+ amd_app_property_h app_property = amd_app_property_find(uid);
+ if (app_property == nullptr)
+ return;
+
+ const char* appid = amd_app_property_get_real_appid(app_property,
+ alias_appid.c_str());
+ if (appid == nullptr)
+ return;
+
+ _D("alias_appid(%s), appid(%s)", alias_appid.c_str(), appid);
+ b.Delete(AUL_K_ORG_APPID);
+ b.Add(AUL_K_ORG_APPID, alias_appid);
+ b.Delete(AUL_K_APPID);
+ b.Add(AUL_K_APPID, appid);
+}
+
+int PassFds(int fd, const int (*fds)[2]) {
+#define MAX_NR_OF_DESCRIPTORS 2
+ union {
+ /*
+ * ancillary data buffer, wrapped in a union in order to ensure
+ * it is suitably aligned
+ */
+ char buf[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)];
+ struct cmsghdr align;
+ } u;
+ char iobuf[1];
+ struct iovec io = { .iov_base = iobuf, .iov_len = sizeof(iobuf) };
+ struct msghdr msg = { 0, };
+ msg.msg_iov = &io;
+ msg.msg_iovlen = 1;
+ msg.msg_control = u.buf;
+ msg.msg_controllen = sizeof(u.buf);
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == nullptr) {
+ _E("Failed to get the first cmsghdr");
+ return -EINVAL;
+ }
+
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * MAX_NR_OF_DESCRIPTORS);
+
+ /* Initialize the payload: */
+ int* fdptr = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ memcpy(fdptr, *fds, sizeof(int) * MAX_NR_OF_DESCRIPTORS);
+
+ int ret = sendmsg(fd, &msg, 0);
+ if (ret < 0) {
+ _E("Failed to send message. errno(%d)", errno);
+ return ret;
+ }
+
+ _D("[__RPC_PORT__] sendmsg result(%d)", ret);
+ return ret;
+}
+
+} // namespace
+
+static int DispatchRpcPortPrepareStub(amd_request_h req) {
+ bundle* kb = amd_request_get_bundle(req);
+ if (kb == nullptr) {
+ _E("Failed to get bundle");
+ amd_request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ tizen_base::Bundle b(kb, false, false);
+ uid_t target_uid = amd_request_get_target_uid(req);
+ SetRealAppId(target_uid, b);
+ std::string app_id = b.GetString(AUL_K_APPID);
+ if (app_id.empty()) {
+ _E("Failed to get appid");
+ amd_request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ std::string port_name = b.GetString(AUL_K_RPC_PORT);
+ if (port_name.empty()) {
+ _E("Failed to get port name");
+ amd_request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ amd_appinfo_h ai = amd_appinfo_find(target_uid, app_id.c_str());
+ if (ai == nullptr) {
+ _E("Failed to find appinfo. %s:%u", app_id.c_str(), target_uid);
+ amd_request_send_result(req, -ENOENT);
+ return -1;
+ }
+
+ amd_noti_send(AMD_NOTI_MSG_LAUNCH_APP_START_START, 0, 0, req,
+ b.GetHandle());
+
+ amd_request_set_request_type(req, "rpc-port");
+ amd_request_set_cmd(req, APP_START_ASYNC);
+
+ bool dummy_pending = false;
+ bool dummy_bg_launch = false;
+ int pid = amd_launch_start_app(app_id.c_str(), req,
+ &dummy_pending, &dummy_bg_launch, false);
+ if (pid < 0) {
+ _E("Failed to send launch request. %s:%s, error(%d)",
+ app_id.c_str(), port_name.c_str(), pid);
+ amd_noti_send(AMD_NOTI_MSG_LAUNCH_FAIL, pid, 0, nullptr, nullptr);
+ return -1;
+ }
+
+ amd_noti_send(AMD_NOTI_MSG_LAUNCH_APP_START_END, pid,
+ dummy_bg_launch, req, b.GetHandle());
+ RpcRef(pid);
+
+ int caller_pid = amd_request_get_pid(req);
+ _I("[__RPC_PORT__] app_id(%s), pid(%d), port_name(%s), caller_pid(%d)",
+ app_id.c_str(), pid, port_name.c_str(), caller_pid);
+ return 0;
+}
+
+static int DispatchRpcPortCreateSocketPair(amd_request_h req) {
+ int fds[2] = { 0, };
+ int ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
+ if (ret != 0) {
+ _E("socketpair() is failed. error(%d)", ret);
+ amd_request_send_result(req, -1);
+ return -1;
+ }
+
+ if (fds[0] == -1) {
+ _E("Failed to open socket");
+ amd_request_send_result(req, -1);
+ return -1;
+ }
+
+ _I("[__RPC_PORT__] A Pair of sockets: %d:%d", fds[0], fds[1]);
+ ret = PassFds(amd_request_get_fd(req), &fds);
+ if (ret < 0) {
+ _E("Failed to pass file descriptors");
+ amd_request_send_result(req, ret);
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ return 0;
+}
+
+static int DispatchRpcPortNotifyRpcFinished(amd_request_h req) {
+ pid_t pid = amd_request_get_pid(req);
+ if (pid <= 0) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ RpcUnref(pid);
+ _I("[__RPC_PORT__] pid(%d)", pid);
+ return 0;
+}
+
+static int ForeachMetadataCb(const char* value, void* user_data) {
+ char* str = strdup(value);
+ if (str == nullptr) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ std::unique_ptr<char, decltype(std::free)*> str_auto(str, std::free);
+
+ auto* info = static_cast<MetadataInfo*>(user_data);
+ char* saveptr = nullptr;
+ char* token = strtok_r(str, "|", &saveptr);
+ while (token) {
+ if (info->Match(token))
+ return -1; // To break metadata iteration
+
+ token = strtok_r(nullptr, "|", &saveptr);
+ }
+
+ return 0;
+}
+
+static int VerifyPrivilegeCheckBypass(amd_request_h req) {
+ bundle* kb = amd_request_get_bundle(req);
+ if (kb == nullptr) {
+ _E("Invalid request");
+ return AMD_CYNARA_RET_ERROR;
+ }
+
+ tizen_base::Bundle b(kb, false, false);
+ std::string app_id = b.GetString(AUL_K_APPID);
+ if (app_id.empty()) {
+ _E("Failed to get appid");
+ return AMD_CYNARA_RET_ERROR;
+ }
+
+ if (IsDefaultTTSEngine(app_id)) {
+ SECURE_LOGD("Bypass privilege check");
+ return AMD_CYNARA_RET_ALLOWED;
+ }
+
+ std::string port_name = b.GetString(AUL_K_RPC_PORT);
+ if (port_name.empty()) {
+ _E("Failed to get port name");
+ return AMD_CYNARA_RET_ERROR;
+ }
+
+ uid_t target_uid = amd_request_get_target_uid(req);
+ if (amd_appinfo_is_platform_app(app_id.c_str(), target_uid)) {
+ amd_app_property_h app_property = amd_app_property_find(target_uid);
+ if (app_property) {
+ MetadataInfo info(port_name);
+ int ret = amd_app_property_metadata_foreach(app_property,
+ app_id.c_str(), kPrivilegeCheckBypass, ForeachMetadataCb, &info);
+ if (ret != 0) {
+ _E("Failed to retrieve metadata");
+ return AMD_CYNARA_RET_ERROR;
+ }
+
+ if (info.Exist()) {
+ SECURE_LOGD("Bypass privilege check");
+ return AMD_CYNARA_RET_ALLOWED;
+ }
+ }
+ }
+
+ return AMD_CYNARA_RET_UNKNOWN;
+}
+
+static int CynaraCheckerPrepareStub(amd_cynara_caller_info_h info,
+ amd_request_h req, void* data) {
+ int ret = VerifyPrivilegeCheckBypass(req);
+ if (ret != AMD_CYNARA_RET_UNKNOWN)
+ return ret;
+
+ ret = amd_cynara_simple_checker(info, req,
+ const_cast<char*>(PRIVILEGE_APPMANAGER_LAUNCH));
+ if (ret <= AMD_CYNARA_RET_DENIED)
+ return ret;
+
+ return amd_cynara_simple_checker(info, req,
+ const_cast<char*>(kPrivilegeDataSharing));
+}
+
+static int CynaraCheckerCreateSocketPair(amd_cynara_caller_info_h info,
+ amd_request_h req, void* data) {
+ int ret = VerifyPrivilegeCheckBypass(req);
+ if (ret != AMD_CYNARA_RET_UNKNOWN)
+ return ret;
+
+ return amd_cynara_simple_checker(info, req,
+ const_cast<char*>(kPrivilegeDataSharing));
+}
+
+static int OnAppStatusCleanup(const char* msg, int arg1, int arg2, void* arg3,
+ bundle* data) {
+ RpcRemove(arg1);
+ return AMD_NOTI_CONTINUE;
+}
+
+static amd_request_cmd_dispatch dispatch_table[] = {
+ {
+ .cmd = RPC_PORT_PREPARE_STUB,
+ .callback = DispatchRpcPortPrepareStub
+ },
+ {
+ .cmd = RPC_PORT_CREATE_SOCKET_PAIR,
+ .callback = DispatchRpcPortCreateSocketPair
+ },
+ {
+ .cmd = RPC_PORT_NOTIFY_RPC_FINISHED,
+ .callback = DispatchRpcPortNotifyRpcFinished
+ },
+};
+
+static amd_cynara_checker cynara_checkers[] = {
+ {
+ .cmd = RPC_PORT_PREPARE_STUB,
+ .checker = CynaraCheckerPrepareStub,
+ .data = nullptr,
+ .priority = 10
+ },
+ {
+ .cmd = RPC_PORT_CREATE_SOCKET_PAIR,
+ .checker = CynaraCheckerCreateSocketPair,
+ .data = nullptr,
+ .priority = 10
+ },
+};
+
+static void TTSEngineDefaultVconfCb(keynode_t* key, void* data) {
+ char* str = vconf_keynode_get_str(key);
+ if (str == nullptr)
+ return;
+
+ _W("TTS Engine Default %s => %s", tts_engine_default.c_str(), str);
+ SetTTSEngineDefault(str);
+}
+
+extern "C" EXPORT int AMD_MOD_INIT() {
+ _D("RPC_PORT_INIT");
+ int ret = amd_app_property_metadata_add_filter(kPrivilegeCheckBypass,
+ nullptr);
+ if (ret < 0) {
+ _E("Failed to add metadata filter");
+ return -1;
+ }
+
+ ret = amd_request_register_cmds(dispatch_table, ARRAY_SIZE(dispatch_table));
+ if (ret < 0) {
+ _E("Failed to register cmds");
+ return -1;
+ }
+
+ ret = amd_cynara_register_checkers(cynara_checkers,
+ ARRAY_SIZE(cynara_checkers));
+ if (ret < 0) {
+ _E("Failed to register cynara checkers");
+ return -1;
+ }
+
+ char* str = vconf_get_str(VCONFKEY_TTS_ENGINE_DEFAULT);
+ if (str != nullptr) {
+ SetTTSEngineDefault(str);
+ std::free(str);
+ }
+
+ ret = vconf_notify_key_changed(VCONFKEY_TTS_ENGINE_DEFAULT,
+ TTSEngineDefaultVconfCb, nullptr);
+ if (ret != 0)
+ _E("vconf_notify_key_changed() is failed. error(%d)", ret);
+
+ amd_noti_listen(AMD_NOTI_MSG_APP_STATUS_CLEANUP,
+ OnAppStatusCleanup);
+ return 0;
+}
+
+extern "C" EXPORT void AMD_MOD_FINI() {
+ _D("RPC_PORT_FINI");
+ vconf_ignore_key_changed(VCONFKEY_TTS_ENGINE_DEFAULT,
+ TTSEngineDefaultVconfCb);
+ amd_app_property_metadata_remove_filter(kPrivilegeCheckBypass, nullptr);
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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 RPC_PORT_LOG_PRIVATE_HH_
+#define RPC_PORT_LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "AMD_RPC_PORT"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif // RPC_PORT_LOG_PRIVATE_HH_
+++ /dev/null
-/*
- * Copyright (c) 2018 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.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <glib.h>
-#include <gio/gio.h>
-#include <aul.h>
-#include <aul_cmd.h>
-#include <aul_rpc_port.h>
-#include <aul_svc.h>
-#include <aul_sock.h>
-#include <bundle_internal.h>
-#include <cert-svc/ccert.h>
-#include <cert-svc/cinstance.h>
-#include <amd.h>
-#include <amd_mod_common.h>
-#include <vconf.h>
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "AMD_RPC_PORT"
-
-#define MAX_NR_OF_DESCRIPTORS 2
-#define PRIVILEGE_DATASHARING "http://tizen.org/privilege/datasharing"
-#define KEY_PRIVILEGE_CHECK_BYPASS \
- "http://tizen.org/rpc-port/privilege-check-bypass"
-
-struct metadata_info_s {
- const char *port_name;
- bool exist;
-};
-
-static GHashTable *__pid_table;
-static char *__tts_engine_default;
-
-static void __rpc_unref(int pid)
-{
- gpointer value;
- int count;
- amd_app_status_h app_status;
- int status;
-
- value = g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid));
- if (!value) {
- _E("Critical error");
- return;
- }
-
- count = GPOINTER_TO_INT(value);
- count--;
- if (count == 0) {
- g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
- amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_INCLUDE);
- app_status = amd_app_status_find_by_pid(pid);
- if (app_status) {
- status = amd_app_status_get_status(app_status);
- if (status != STATUS_DYING)
- amd_suspend_add_timer(pid);
- }
- } else {
- g_hash_table_replace(__pid_table, GINT_TO_POINTER(pid),
- GINT_TO_POINTER(count));
- }
-}
-
-static void __rpc_ref(int pid)
-{
- gpointer value;
- int count;
-
- value = g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid));
- if (value) {
- count = GPOINTER_TO_INT(value);
- count++;
- g_hash_table_replace(__pid_table, GINT_TO_POINTER(pid),
- GINT_TO_POINTER(count));
- } else {
- count = 1;
- g_hash_table_insert(__pid_table, GINT_TO_POINTER(pid),
- GINT_TO_POINTER(count));
- amd_suspend_remove_timer(pid);
- amd_suspend_update_status(pid, AMD_SUSPEND_STATUS_EXCLUDE);
- }
-}
-
-static void __set_real_appid(uid_t uid, bundle *kb)
-{
- const char *alias_appid;
- const char *appid;
- const char *alias_info;
- amd_app_property_h app_property;
-
- alias_appid = bundle_get_val(kb, AUL_K_APPID);
- if (alias_appid == NULL)
- return;
-
- alias_info = bundle_get_val(kb, AUL_SVC_K_ALIAS_INFO);
- if (alias_info && strcmp(alias_info, "disable") == 0)
- return;
-
- app_property = amd_app_property_find(uid);
- if (app_property == NULL)
- return;
-
- appid = amd_app_property_get_real_appid(app_property, alias_appid);
- if (appid == NULL)
- return;
-
- _D("alias_appid(%s), appid(%s)", alias_appid, appid);
- bundle_del(kb, AUL_K_ORG_APPID);
- bundle_add(kb, AUL_K_ORG_APPID, alias_appid);
- bundle_del(kb, AUL_K_APPID);
- bundle_add(kb, AUL_K_APPID, appid);
-}
-
-static int __dispatch_rpc_port_prepare_stub(amd_request_h req)
-{
- bundle *b = amd_request_get_bundle(req);
- pid_t caller_pid = amd_request_get_pid(req);
- uid_t target_uid = amd_request_get_target_uid(req);
- amd_appinfo_h ai;
- const char *appid;
- const char *port_name;
- int pid;
- bool dummy_pending = false;
- bool dummy_bg_launch = false;
-
- if (!b) {
- _E("Invalid parameter");
- amd_request_send_result(req, -EINVAL);
- return -1;
- }
-
- __set_real_appid(target_uid, b);
-
- appid = bundle_get_val(b, AUL_K_APPID);
- if (!appid) {
- _E("Failed to get appid");
- amd_request_send_result(req, -EINVAL);
- return -1;
- }
-
- port_name = bundle_get_val(b, AUL_K_RPC_PORT);
- if (!port_name) {
- _E("Failed to get port name");
- amd_request_send_result(req, -EINVAL);
- return -1;
- }
-
- ai = amd_appinfo_find(target_uid, appid);
- if (!ai) {
- _E("Failed to find %s:%u", appid, target_uid);
- amd_request_send_result(req, -ENOENT);
- return -1;
- }
-
- amd_noti_send(AMD_NOTI_MSG_LAUNCH_APP_START_START, 0, 0, req, b);
-
- amd_request_set_request_type(req, "rpc-port");
- amd_request_set_cmd(req, APP_START_ASYNC);
- pid = amd_launch_start_app(appid, req,
- &dummy_pending, &dummy_bg_launch,
- false);
- if (pid < 0) {
- _E("Failed to send launch request(%s:%s)",
- appid, port_name);
- amd_noti_send(AMD_NOTI_MSG_LAUNCH_FAIL, pid, 0, NULL, NULL);
- return -1;
- }
- amd_noti_send(AMD_NOTI_MSG_LAUNCH_APP_START_END,
- pid, dummy_bg_launch, req, b);
-
- __rpc_ref(pid);
-
- _I("[__RPC_PORT__] appid(%s), pid(%d), port_name(%s), caller_pid(%d)",
- appid, pid, port_name, caller_pid);
-
- return 0;
-}
-
-static int __pass_fds(int fd, const int (*fds)[2])
-{
- struct msghdr msg = { 0, };
- struct cmsghdr *cmsg;
- union {
- /*
- * ancillary data buffer, wrapped in a union in order to ensure
- * it is suitably aligned
- */
- char buf[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)];
- struct cmsghdr align;
- } u;
- int *fdptr;
- char iobuf[1];
- struct iovec io = {
- .iov_base = iobuf,
- .iov_len = sizeof(iobuf)
- };
- int r;
-
- msg.msg_iov = &io;
- msg.msg_iovlen = 1;
- msg.msg_control = u.buf;
- msg.msg_controllen = sizeof(u.buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg) {
- _E("Failed to get the first cmsghdr");
- return -EINVAL;
- }
-
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int) * MAX_NR_OF_DESCRIPTORS);
-
- /* Initialize the payload: */
- fdptr = (int *)CMSG_DATA(cmsg);
- memcpy(fdptr, *fds, sizeof(int) * MAX_NR_OF_DESCRIPTORS);
-
- r = sendmsg(fd, &msg, 0);
- if (r < 0) {
- _E("Failed to send message. errno(%d)", errno);
- return r;
- }
-
- _D("[__RPC_PORT__] sendmsg result(%d)", r);
-
- return r;
-}
-
-static int __dispatch_rpc_port_create_socket_pair(amd_request_h req)
-{
- int fds[2] = { 0, };
- int r;
-
- r = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
- if (r != 0) {
- _E("Failed to create socket pair. err = %d", r);
- amd_request_send_result(req, -1);
- return -1;
- }
-
- if (fds[0] == -1) {
- _E("Failed to open socket");
- amd_request_send_result(req, -1);
- return -1;
- }
-
- _I("[__RPC_PORT__] A Pair of sockets: %d:%d", fds[0], fds[1]);
-
- r = __pass_fds(amd_request_get_fd(req), &fds);
- if (r < 0) {
- _E("Failed to pass file descriptors");
- amd_request_send_result(req, r);
- }
-
- close(fds[0]);
- close(fds[1]);
-
- return 0;
-}
-
-static int __dispatch_rpc_port_notify_rpc_finished(amd_request_h req)
-{
- pid_t pid = amd_request_get_pid(req);
-
- if (pid <= 0) {
- _E("Invalid parameter");
- return -1;
- }
-
- __rpc_unref(pid);
- _I("[__RPC_PORT__] pid(%d)", pid);
-
- return 0;
-}
-
-static int __foreach_metadata_cb(const char *value, void *user_data)
-{
- struct metadata_info_s *info = (struct metadata_info_s *)user_data;
- char *str;
- char *token;
- char *saveptr = NULL;
-
- str = strdup(value);
- if (!str) {
- _E("Out of memory");
- return -1;
- }
-
- token = strtok_r(str, "|", &saveptr);
- while (token) {
- if (!strcmp(token, info->port_name)) {
- info->exist = true;
- free(str);
- return -1; /* To break metadata iteration */
- }
- token = strtok_r(NULL, "|", &saveptr);
- }
-
- free(str);
-
- return 0;
-}
-
-static bool __is_default_tts_engine(const char* appid)
-{
- char buf[256];
-
- if (!__tts_engine_default)
- return false;
-
- if (!strcmp(__tts_engine_default, appid))
- return true;
-
- snprintf(buf, sizeof(buf), "%s-noti", __tts_engine_default);
- if (!strcmp(buf, appid))
- return true;
-
- snprintf(buf, sizeof(buf), "%s-sr", __tts_engine_default);
- if (!strcmp(buf, appid))
- return true;
-
- snprintf(buf, sizeof(buf), "%s-interrupt", __tts_engine_default);
- if (!strcmp(buf, appid))
- return true;
-
- return false;
-}
-
-static int __verify_privilege_check_bypass(amd_request_h req)
-{
- int r;
- bundle *b;
- const char *appid;
- struct metadata_info_s info = { 0, };
- amd_app_property_h app_property;
- uid_t uid = amd_request_get_target_uid(req);
-
- b = amd_request_get_bundle(req);
- if (!b) {
- _E("Invalid request");
- return AMD_CYNARA_RET_ERROR;
- }
-
- appid = bundle_get_val(b, AUL_K_APPID);
- if (!appid) {
- _E("Failed to get appid");
- return AMD_CYNARA_RET_ERROR;
- }
-
- if (__is_default_tts_engine(appid)) {
- SECURE_LOGD("Bypass privilege check");
- return AMD_CYNARA_RET_ALLOWED;
- }
-
- info.port_name = bundle_get_val(b, AUL_K_RPC_PORT);
- if (!info.port_name) {
- _E("Failed to get port name");
- return AMD_CYNARA_RET_ERROR;
- }
-
- app_property = amd_app_property_find(uid);
- if (app_property) {
- r = amd_app_property_metadata_foreach(app_property,
- appid, KEY_PRIVILEGE_CHECK_BYPASS,
- __foreach_metadata_cb, &info);
- if (r != 0) {
- _E("Failed to retrieve metadata");
- return AMD_CYNARA_RET_ERROR;
- }
-
- if (info.exist && amd_appinfo_is_platform_app(appid, uid)) {
- SECURE_LOGD("Bypass privilege check");
- return AMD_CYNARA_RET_ALLOWED;
- }
- }
-
- return AMD_CYNARA_RET_UNKNOWN;
-}
-
-static int __prepare_stub_cynara_checker(amd_cynara_caller_info_h info,
- amd_request_h req, void *data)
-{
- int r;
-
- r = __verify_privilege_check_bypass(req);
- if (r != AMD_CYNARA_RET_UNKNOWN)
- return r;
-
- r = amd_cynara_simple_checker(info, req, PRIVILEGE_APPMANAGER_LAUNCH);
- if (r <= AMD_CYNARA_RET_DENIED)
- return r;
-
- return amd_cynara_simple_checker(info, req, PRIVILEGE_DATASHARING);
-}
-
-static int __create_socket_pair_cynara_checker(amd_cynara_caller_info_h info,
- amd_request_h req, void *data)
-{
- int r;
-
- r = __verify_privilege_check_bypass(req);
- if (r != AMD_CYNARA_RET_UNKNOWN)
- return r;
-
- return amd_cynara_simple_checker(info, req, PRIVILEGE_DATASHARING);
-}
-
-static int __on_app_status_cleanup(const char *msg, int arg1, int arg2,
- void *arg3, bundle *b)
-{
- int pid = arg1;
-
- if (g_hash_table_contains(__pid_table, GINT_TO_POINTER(pid)))
- g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
-
- return 0;
-}
-
-static amd_request_cmd_dispatch __dispatch_table[] = {
- {
- .cmd = RPC_PORT_PREPARE_STUB,
- .callback = __dispatch_rpc_port_prepare_stub
- },
- {
- .cmd = RPC_PORT_CREATE_SOCKET_PAIR,
- .callback = __dispatch_rpc_port_create_socket_pair
- },
- {
- .cmd = RPC_PORT_NOTIFY_RPC_FINISHED,
- .callback = __dispatch_rpc_port_notify_rpc_finished
- },
-};
-
-static amd_cynara_checker __cynara_checkers[] = {
- {
- .cmd = RPC_PORT_PREPARE_STUB,
- .checker = __prepare_stub_cynara_checker,
- .data = NULL,
- .priority = 10
- },
- {
- .cmd = RPC_PORT_CREATE_SOCKET_PAIR,
- .checker = __create_socket_pair_cynara_checker,
- .data = NULL,
- .priority = 10
- },
-};
-
-static void __tts_engine_default_vconf_cb(keynode_t *key, void *data)
-{
- char *str;
-
- str = vconf_keynode_get_str(key);
- if (!str)
- return;
-
- if (__tts_engine_default)
- free(__tts_engine_default);
-
- _W("TTS Engine Default %s => %s", __tts_engine_default, str);
- __tts_engine_default = strdup(str);
-}
-
-EXPORT int AMD_MOD_INIT(void)
-{
- int r;
-
- _D("rpc port init");
-
- r = amd_app_property_metadata_add_filter(KEY_PRIVILEGE_CHECK_BYPASS,
- NULL);
- if (r < 0) {
- _E("Failed to add metadata filter");
- return -1;
- }
-
- r = amd_request_register_cmds(__dispatch_table,
- ARRAY_SIZE(__dispatch_table));
- if (r < 0) {
- _E("Failed to register cmds");
- return -1;
- }
-
- r = amd_cynara_register_checkers(__cynara_checkers,
- ARRAY_SIZE(__cynara_checkers));
- if (r < 0) {
- _E("Failed to register cynara checkers");
- return -1;
- }
-
- __pid_table = g_hash_table_new(g_direct_hash, g_direct_equal);
- if (!__pid_table) {
- _E("Failed to create pid table");
- return -1;
- }
-
- __tts_engine_default = vconf_get_str(VCONFKEY_TTS_ENGINE_DEFAULT);
- r = vconf_notify_key_changed(VCONFKEY_TTS_ENGINE_DEFAULT,
- __tts_engine_default_vconf_cb, NULL);
- if (r != 0)
- _E("vconf_notify_key_changed() is failed");
-
- amd_noti_listen(AMD_NOTI_MSG_APP_STATUS_CLEANUP,
- __on_app_status_cleanup);
-
- return 0;
-}
-
-EXPORT void AMD_MOD_FINI(void)
-{
- _D("rpc port finish");
-
- if (__tts_engine_default)
- free(__tts_engine_default);
-
- if (__pid_table)
- g_hash_table_destroy(__pid_table);
-
- amd_app_property_metadata_remove_filter(KEY_PRIVILEGE_CHECK_BYPASS,
- NULL);
-}