PKG_CHECK_MODULES(PRIVILEGE_CHECKER_DEPS REQUIRED security-privilege-manager)
PKG_CHECK_MODULES(TPK_MANIFEST_HANDLERS_DEPS REQUIRED tpk-manifest-handlers)
PKG_CHECK_MODULES(DBUS_DEPS REQUIRED dbus-1)
+PKG_CHECK_MODULES(GDBUS_DEPS REQUIRED glib-2.0 gio-2.0)
+PKG_CHECK_MODULES(GUM_DEPS REQUIRED libgum)
FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
FIND_PACKAGE(GTest REQUIRED)
BuildRequires: boost-devel
BuildRequires: cmake
+BuildRequires: libattr-devel
BuildRequires: libcap-devel
BuildRequires: gtest-devel
BuildRequires: pkgconfig(pkgmgr)
BuildRequires: pkgconfig(tpk-manifest-handlers)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(libgum)
Requires: ca-certificates-tizen
Requires: libtzplatform-config
%{_datarootdir}/app-installers/plugins_list.txt
%manifest app-installers.manifest
%{_libdir}/libapp-installers.so*
-%attr(6750,root,root) %{_bindir}/pkgdir-tool
+%attr(0750,root,root) %{_bindir}/pkgdir-tool
+%attr(0644,root,root) %{_prefix}/share/dbus-1/system-services/org.tizen.pkgdir_tool.service
+%attr(0644,root,root) %{_sysconfdir}/dbus-1/system.d/org.tizen.pkgdir_tool.conf
%{_bindir}/pkg_initdb
%license LICENSE
PRIVILEGE_CHECKER_DEPS
DELTA_MANIFEST_HANDLERS_DEPS
TPK_MANIFEST_HANDLERS_DEPS
+ GDBUS_DEPS
+ GUM_DEPS
Boost
)
# Extra
SET_TARGET_PROPERTIES(${TARGET_LIBNAME_COMMON} PROPERTIES VERSION ${VERSION})
SET_TARGET_PROPERTIES(${TARGET_LIBNAME_COMMON} PROPERTIES SOVERSION ${VERSION_MAJOR})
+TARGET_LINK_LIBRARIES(${TARGET_LIBNAME_COMMON} PRIVATE "-lattr")
# Install
INSTALL(TARGETS ${TARGET_LIBNAME_COMMON} DESTINATION ${LIB_INSTALL_DIR})
return true;
}
+bool PreparePathRequest(const std::string& pkg_id,
+ const boost::filesystem::path& path, uid_t uid, path_req* req,
+ std::string* error_message) {
+ if (pkg_id.empty() || path.empty()) {
+ LOG(ERROR) << "Pkgid or path is empty. Both values must be set";
+ return false;
+ }
+
+ int error = security_manager_path_req_set_pkg_id(req, pkg_id.c_str());
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message = security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ return false;
+ }
+
+ error = security_manager_path_req_set_uid(req, uid);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message = security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ return false;
+ }
+
+ app_install_type type =
+ (getuid() == 0) ? SM_APP_INSTALL_PRELOADED : SM_APP_INSTALL_GLOBAL;
+
+ error = security_manager_path_req_set_install_type(req, type);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message =
+ security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ return false;
+ }
+
+ for (auto& policy : kSecurityPolicies) {
+ bf::path subpath = path / policy.first;
+ if (bf::exists(subpath)) {
+ if (bf::is_symlink(subpath)) {
+ LOG(DEBUG) << "Path " << subpath << " is a symlink."
+ << "Path will not be registered";
+ continue;
+ }
+ error = security_manager_path_req_add_path(req, subpath.c_str(),
+ policy.second);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message =
+ security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
} // namespace
namespace common_installer {
return true;
}
+bool RegisterSecurityContextForPath(const std::string &pkg_id,
+ const boost::filesystem::path& path, uid_t uid,
+ std::string* error_message) {
+ path_req* req;
+ int error = security_manager_path_req_new(&req);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ LOG(ERROR)
+ << "Failed while calling security_manager_path_req_new failed "
+ << "(error code: " << error << ")";
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message = security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ return false;
+ }
+
+ if (!PreparePathRequest(pkg_id, path, uid, req, error_message)) {
+ LOG(ERROR) << "Failed while preparing security_manager_app_inst_req";
+ security_manager_path_req_free(req);
+ return false;
+ }
+
+ error = security_manager_paths_register(req);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ LOG(ERROR) << "Failed while calling security_manager_paths_register failed "
+ << "(error code: " << error << ")";
+ std::string errnum = boost::str(boost::format("%d") % error);
+ *error_message = security_manager_strerror(static_cast<lib_retcode>(error));
+ *error_message += ":<" + errnum + ">";
+ security_manager_path_req_free(req);
+ return false;
+ }
+
+ security_manager_path_req_free(req);
+
+ return true;
+}
+
} // namespace common_installer
bool UnregisterSecurityContextForPkgId(const std::string& pkg_id, uid_t uid,
std::string* error_message);
+/**
+ * Adapter interface for external Security module.
+ *
+ * Adapter interface for external Security module used for registering
+ * package path to security context
+ *
+ * \param pkg_id pkgid of given package
+ * \param path path for registering
+ * \param uid uid
+ * \param error_message extra/detailed error message
+ *
+ * \return true if success
+ */
+bool RegisterSecurityContextForPath(const std::string &pkg_id,
+ const boost::filesystem::path& path, uid_t uid,
+ std::string* error_message);
+
} // namespace common_installer
#endif // COMMON_SECURITY_REGISTRATION_H_
#include <boost/program_options.hpp>
#include <boost/system/error_code.hpp>
+#include <glib.h>
+#include <gio/gio.h>
#include <manifest_parser/utils/logging.h>
#include <vcore/Certificate.h>
#include <pkgmgr-info.h>
#include <unistd.h>
#include <tzplatform_config.h>
#include <sys/xattr.h>
-
+#include <gum/gum-user.h>
+#include <gum/gum-user-service.h>
+#include <gum/common/gum-user-types.h>
#include <algorithm>
#include <cassert>
namespace {
+typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
const std::vector<const char*> kEntries = {
{"/"},
{"cache/"},
const char kSkelAppDir[] = "/etc/skel/apps_rw";
const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
const char kExternalStorageDirPrefix[] = "SDCardA1/apps";
+const char kDBusServiceName[] = "org.tizen.pkgdir_tool";
+const char kDBusObjectPath[] = "/org/tizen/pkgdir_tool";
+const char kDBusInterfaceName[] = "org.tizen.pkgdir_tool";
+const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
+const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
bool ValidateTizenPackageId(const std::string& id) {
std::regex package_regex(kPackagePattern);
return pkgs;
}
-bool SetPackageDirectorySmackRules(const bf::path& base_dir,
- const std::string& pkgid,
- const std::string& author_id,
- const std::string& api_version,
- uid_t uid) {
- if (!pkgid.empty()) {
- std::vector<std::string> privileges;
- std::vector<std::string> appids;
- if (!common_installer::QueryPrivilegesForPkgId(pkgid,
- tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &privileges)) {
- LOG(ERROR) << "Failed to get privileges for package id";
- return false;
- }
- if (!common_installer::QueryAppidsForPkgId(pkgid, &appids,
- tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))) {
- LOG(ERROR) << "Failed to get application ids for package id";
- return false;
- }
- std::string error_message;
- for (const auto& appid : appids) {
- if (!common_installer::RegisterSecurityContext(appid, pkgid,
- author_id, api_version, ci::SecurityAppInstallType::Local,
- base_dir, uid, privileges,
- &error_message)) {
- LOG(ERROR) << "Failed to register security context";
- if (!error_message.empty()) {
- LOG(ERROR) << "error_message: " << error_message;
- }
- return false;
- }
- }
- }
- return true;
-}
-
bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
gid_t gid) {
bs::error_code error;
bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
struct passwd pwd;
struct passwd *pwd_result;
- char buf[1024] = {0, };
-
+ char buf[kPWBufSize];
int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
if (ret != 0 || pwd_result == nullptr)
return {};
bool CreateUserDirectories(uid_t user, const std::string& pkgid,
const std::string& author_id,
const std::string& apps_prefix, const bool set_permissions) {
- char buf[1024] = {0, };
-
struct passwd pwd;
struct passwd *pwd_result;
- int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
+ char buf_pw[kPWBufSize];
+ int ret = getpwuid_r(user, &pwd, buf_pw, sizeof(buf_pw), &pwd_result);
if (ret != 0 || pwd_result == nullptr) {
LOG(WARNING) << "Failed to get user for home directory: " << user;
return false;
struct group gr;
struct group *gr_result;
- ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
+ char buf_gr[kGRBufSize];
+ ret = getgrgid_r(pwd.pw_gid, &gr, buf_gr, sizeof(buf_gr), &gr_result);
if (ret != 0
|| strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
return false;
return true;
}
-bool CreateSkelDirectories(const std::string& pkgid) {
- bf::path path = bf::path(kSkelAppDir) / pkgid;
- LOG(DEBUG) << "Creating directories in: " << path;
- bs::error_code error;
- bf::create_directories(path, error);
-
- if (error) {
- LOG(ERROR) << "Failed to create directory: " << path;
- return false;
- }
-
- // TODO(jungh.yeon) : this is hotfix.
- for (auto& entry : kEntries) {
- bf::path subpath = path / entry;
- bf::create_directories(subpath, error);
- std::string label = "User::Pkg::" + pkgid;
- if (error && !bf::exists(subpath)) {
- LOG(ERROR) << "Failed to create directory: " << subpath;
- return false;
- }
-
- int r =
- lsetxattr(subpath.c_str(), "security.SMACK64TRANSMUTE", "TRUE", 4, 0);
- if (r < 0) {
- LOG(ERROR) << "Failed to apply transmute";
- return false;
- }
-
- r = lsetxattr(subpath.c_str(), "security.SMACK64",
- label.c_str(), label.length(), 0);
- if (r < 0) {
- LOG(ERROR) << "Failed to apply label";
- return false;
- }
- }
-
- return true;
-}
-
bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
bf::path base_dir = app_dir / pkgid;
bs::error_code error;
return true;
}
-bool DeletePerUserDirectories(const std::string& pkgid) {
- char buf[1024] = {0, };
-
- for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
- iter != bf::directory_iterator();
- ++iter) {
- if (!bf::is_directory(iter->path()))
- return false;
- const bf::path& home_path = iter->path();
- std::string user = home_path.filename().string();
- struct passwd pwd;
- struct passwd *pwd_result;
- int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
- if (ret != 0 || pwd_result == nullptr) {
- LOG(WARNING) << "Failed to get user for home directory: " << user;
- continue;
- }
-
- struct group gr;
- struct group *gr_result;
- ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
- if (ret != 0 || gr_result == nullptr ||
- strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
- continue;
-
- if (ci::IsPackageInstalled(pkgid, pwd.pw_uid)) continue;
+bool RequestUserDirectoryOperation(const char* method,
+ const std::string& pkgid) {
+ GError* err = nullptr;
+ GDBusConnection* con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
+ if (!con || err) {
+ LOG(WARNING) << "Failed to get dbus connection: " << err->message;
+ g_error_free(err);
+ return false;
+ }
+ GDBusProxy* proxy = g_dbus_proxy_new_sync(con, G_DBUS_PROXY_FLAGS_NONE,
+ nullptr, kDBusServiceName, kDBusObjectPath, kDBusInterfaceName, nullptr,
+ &err);
+ if (!proxy || err) {
+ LOG(ERROR) << "Failed to get dbus proxy: " << err->message;
+ g_error_free(err);
+ g_object_unref(con);
+ return false;
+ }
+ GVariant* r = g_dbus_proxy_call_sync(proxy, method,
+ g_variant_new("(s)", pkgid.c_str()), G_DBUS_CALL_FLAGS_NONE, -1, nullptr,
+ &err);
+ if (!r || err) {
+ LOG(ERROR) << "Failed to request: " << err->message;
+ g_error_free(err);
+ g_object_unref(proxy);
+ g_object_unref(con);
+ return false;
+ }
+ bool result;
+ g_variant_get(r, "(b)", &result);
- std::string error_message;
- if (!ci::UnregisterSecurityContextForPkgId(pkgid, pwd.pw_uid,
- &error_message)) {
- LOG(WARNING) << "Failure on unregistering security context for pkg: "
- << pkgid << ", uid: " << pwd.pw_uid;
- }
+ g_variant_unref(r);
+ g_object_unref(proxy);
+ g_object_unref(con);
- LOG(DEBUG) << "Deleting directories for uid: " << pwd.pw_uid << ", gid: "
- << pwd.pw_gid;
- tzplatform_set_user(pwd.pw_uid);
- bf::path apps_rw(tzplatform_getenv(TZ_USER_APP));
- tzplatform_reset_user();
- if (!DeleteDirectories(apps_rw, pkgid)) {
- return false;
- }
- }
- return true;
+ return result;
}
-bool DeleteSkelDirectories(const std::string& pkgid) {
- bf::path path = bf::path(kSkelAppDir) / pkgid;
- LOG(DEBUG) << "Deleting directories in: " << path;
- bs::error_code error;
- bf::remove_all(path, error);
- if (error) {
- LOG(ERROR) << "Failed to delete directory: " << path;
- return false;
+user_list GetUserList() {
+ GumUserService* service =
+ gum_user_service_create_sync((getuid() == 0) ? TRUE : FALSE);
+ gchar** user_type_strv = gum_user_type_to_strv(
+ GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL);
+ GumUserList* gum_user_list =
+ gum_user_service_get_user_list_sync(service, user_type_strv);
+ user_list list;
+ for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
+ uid_t uid;
+ g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
+ gid_t gid;
+ g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
+ gchar* homedir = nullptr;
+ g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
+ if (homedir == nullptr) {
+ LOG(WARNING) << "No homedir for uid: " << uid;
+ continue;
+ }
+ list.emplace_back(uid, gid, bf::path(homedir));
}
- return true;
+ g_strfreev(user_type_strv);
+ gum_user_service_list_free(gum_user_list);
+ return list;
}
} // namespace
namespace common_installer {
-bool CreateSkeletonDirectoriesForPackage(const std::string& pkgid) {
- return CreateSkelDirectories(pkgid);
-}
-
std::string GetDirectoryPathForInternalStorage() {
const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
if (internal_storage_prefix)
bool PerformInternalDirectoryCreationForAllUsers(const std::string& pkgid,
const std::string& author_id) {
- char buf[1024] = {0, };
-
- for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
- iter != bf::directory_iterator();
- ++iter) {
- if (!bf::is_directory(iter->path()))
- continue;
- const bf::path& home_path = iter->path();
- std::string user = home_path.filename().string();
-
- struct passwd pwd;
- struct passwd *pwd_result;
- int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
- if (ret != 0 || pwd_result == nullptr)
- continue;
-
- struct group gr;
- struct group *gr_result;
- ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
- if (ret != 0 ||
- strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
- continue;
-
- if (!PerformInternalDirectoryCreationForUser(pwd.pw_uid,
+ user_list list = GetUserList();
+ for (auto l : list) {
+ if (!PerformInternalDirectoryCreationForUser(std::get<0>(l),
pkgid,
author_id))
LOG(ERROR) << "Could not create internal storage directories for user: "
- << user.c_str();
+ << std::get<0>(l);
}
return true;
}
bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid,
const std::string& author_id) {
- char buf[1024] = {0, };
-
- for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
- iter != bf::directory_iterator();
- ++iter) {
- try {
- if (!bf::is_directory(iter->path())) continue;
- }
- catch (const bf::filesystem_error&) {
- continue;
- }
+ user_list list = GetUserList();
+ for (auto l : list) {
+ if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
+ pkgid,
+ author_id))
+ LOG(WARNING) << "Could not create external storage directories for user: "
+ << std::get<0>(l);
+ }
+ return true;
+}
- const bf::path& home_path = iter->path();
- std::string user = home_path.filename().string();
+bool CreateSkelDirectories(const std::string& pkgid) {
+ bf::path path = bf::path(kSkelAppDir) / pkgid;
+ LOG(DEBUG) << "Creating directories in: " << path;
+ bs::error_code error;
+ bf::create_directories(path, error);
- struct passwd pwd;
- struct passwd *pwd_result;
- int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
- if (ret != 0 || pwd_result == nullptr)
- continue;
+ if (error) {
+ LOG(ERROR) << "Failed to create directory: " << path;
+ return false;
+ }
- struct group gr;
- struct group *gr_result;
- ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
- if (ret != 0 ||
- strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
- continue;
+ for (auto& entry : kEntries) {
+ bf::path subpath = path / entry;
+ bf::create_directories(subpath, error);
+ if (error && !bf::exists(subpath)) {
+ LOG(ERROR) << "Failed to create directory: " << subpath;
+ return false;
+ }
+ }
- if (!PerformExternalDirectoryCreationForUser(pwd.pw_uid,
- pkgid,
- author_id))
- LOG(WARNING) << "Could not create external storage directories for user: "
- << user.c_str();
+ std::string error_message;
+ if (!RegisterSecurityContextForPath(pkgid, path,
+ tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &error_message)) {
+ LOG(ERROR) << "Failed to register security context for path: " << path
+ << ", error_message: " << error_message;
+ return false;
}
+
return true;
}
-bool SetPackageDirectorySmackRulesForUser(uid_t uid,
- const std::string& pkg_path,
- const std::string& pkg_id,
- const std::string& author_id,
- const std::string& api_version) {
- return SetPackageDirectorySmackRules(pkg_path,
- pkg_id,
- author_id,
- api_version,
- uid);
+
+bool DeleteSkelDirectories(const std::string& pkgid) {
+ return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
}
-bool SetPackageDirectorySmackRulesForAllUsers(const std::string& pkg_path,
- const std::string& pkg_id,
- const std::string& author_id,
- const std::string& api_version) {
- char buf[1024] = {0, };
-
- for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
- iter != bf::directory_iterator();
- ++iter) {
- if (!bf::is_directory(iter->path()))
- continue;
- const bf::path& home_path = iter->path();
- std::string user = home_path.filename().string();
-
- struct passwd pwd;
- struct passwd*pwd_result;
- int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
- if (ret != 0 || pwd_result == nullptr) {
- LOG(WARNING) << "Failed to get user for home directory: " << user;
+bool DeleteUserDirectories(const std::string& pkgid) {
+ user_list list = GetUserList();
+ for (auto l : list) {
+ if (ci::IsPackageInstalled(pkgid, std::get<0>(l))) {
+ LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
+ continue;
+ }
+
+ LOG(DEBUG) << "Deleting directories of " << pkgid
+ << ", for uid: " << std::get<0>(l);
+ bf::path apps_rw(std::get<2>(l) / "apps_rw");
+ if (!DeleteDirectories(apps_rw, pkgid)) {
return false;
}
+ }
+ return true;
+}
- std::string path = pkg_path + "/" + user + "apps_rw";
- if (!SetPackageDirectorySmackRulesForUser(pwd.pw_uid,
- path,
- pkg_id,
- author_id,
- api_version)) {
- LOG(WARNING) << "Failed to set directory smack rules for user: " << user;
+bool CopyUserDirectories(const std::string& pkgid) {
+ user_list list = GetUserList();
+ for (auto l : list) {
+ LOG(DEBUG) << "Copying directories for uid: " << std::get<0>(l);
+ bf::path apps_rw(std::get<2>(l) / "apps_rw");
+ bf::path src = bf::path(kSkelAppDir) / pkgid;
+ bf::path dst = apps_rw / pkgid;
+ if (!ci::CopyDir(src, dst))
continue;
+ if (!SetPackageDirectoryOwnerAndPermissions(dst, std::get<0>(l),
+ std::get<1>(l)))
+ return false;
+ for (bf::recursive_directory_iterator iter(dst);
+ iter != bf::recursive_directory_iterator(); ++iter) {
+ if (!SetPackageDirectoryOwnerAndPermissions(iter->path(),
+ std::get<0>(l), std::get<1>(l)))
+ return false;
}
}
return true;
}
+bool RequestCopyUserDirectories(const std::string& pkgid) {
+ if (!RequestUserDirectoryOperation("CopyUserDirs", pkgid)) {
+ LOG(INFO) << "Try to copy user directories directly";
+ return CopyUserDirectories(pkgid);
+ }
+ return true;
+}
-bool PerformDirectoryDeletionForAllUsers(const std::string& pkgid) {
- if (!DeletePerUserDirectories(pkgid))
- return false;
- if (!DeleteSkelDirectories(pkgid))
- return false;
+bool RequestDeleteUserDirectories(const std::string& pkgid) {
+ if (!RequestUserDirectoryOperation("DeleteUserDirs", pkgid)) {
+ LOG(INFO) << "Try to delete user directories directly";
+ return DeleteUserDirectories(pkgid);
+ }
return true;
}
bool PerformDirectoryDeletionForAllUsers(const std::string& pkgid);
/**
- * \brief Performs deletion of directories
+ * \brief Helper function fetching information about packages
*
- * \param uid package path
- * \param pkg_path package path
- * \param pkg_id package path
- * \param author_id package path
- * \param api_version package path
+ * \param pkgs list of packages requested to fetch information about. If list
+ * is empty, all possible pkg id's are considered.
*
+ * \return pkg_list list containing information about requested packages
*
- * \return true if succeed, false otherwise
+ */
+PkgList CreatePkgInformationList(uid_t uid = getuid(),
+ const std::vector<std::string>& pkgs =
+ std::vector<std::string>());
+
+/**
+ * \brief Create skeleton directories for package
+ *
+ * \param pkgid package id
+ *
+ * \return bool true if succeed, false otherwise
*
*/
-bool SetPackageDirectorySmackRulesForUser(uid_t uid,
- const std::string& pkg_path,
- const std::string& pkg_id,
- const std::string& author_id,
- const std::string& api_version);
+bool CreateSkelDirectories(const std::string& pkgid);
/**
* \brief Performs deletion of directories
*
- * \param pkg_path package path
- * \param pkg_id package path
- * \param author_id package path
- * \param api_version package path
+ * \param pkgid package id
*
* \return true if succeed, false otherwise
*
*/
-bool SetPackageDirectorySmackRulesForAllUsers(const std::string& pkg_path,
- const std::string& pkg_id,
- const std::string& author_id,
- const std::string& api_version);
+bool DeleteSkelDirectories(const std::string& pkgid);
/**
- * \brief Helper function fetching information about packages
+ * \brief Delete per-user directories
*
- * \param pkgs list of packages requested to fetch information about. If list
- * is empty, all possible pkg id's are considered.
+ * \param pkgid package id
*
- * \return pkg_list list containing information about requested packages
+ * \return true if succeed, false otherwise
*
*/
-PkgList CreatePkgInformationList(uid_t uid = getuid(),
- const std::vector<std::string>& pkgs =
- std::vector<std::string>());
+bool DeleteUserDirectories(const std::string& pkgid);
/**
- * \brief Returns path prefix for internal storage, typically '/home'
+ * \brief Copy per-user directories
*
- * \return path prefix
+ * \param pkgid package id
+ *
+ * \return bool true if succeed, false otherwise
*
*/
-std::string GetDirectoryPathForInternalStorage();
+bool CopyUserDirectories(const std::string& pkgid);
/**
- * \brief Returns path prefix for external storage, typically sd card mount point
+ * \brief Request to copy per-user directories
*
- * \return path prefix
+ * \param pkgid package id
+ *
+ * \return bool true if succeed, false otherwise
*
*/
-std::string GetDirectoryPathForExternalStorage();
+bool RequestCopyUserDirectories(const std::string& pkgid);
/**
- * \brief Create skeleton directories for package
+ * \brief Request to delete per-user directories
+ *
+ * \param pkgid package id
*
* \return bool true if succeed, false otherwise
*
*/
-bool CreateSkeletonDirectoriesForPackage(const std::string& pkgid);
+bool RequestDeleteUserDirectories(const std::string& pkgid);
+
+/**
+ * \brief Returns path prefix for internal storage, typically '/home'
+ *
+ * \return path prefix
+ *
+ */
+std::string GetDirectoryPathForInternalStorage();
+
+/**
+ * \brief Returns path prefix for external storage, typically sd card mount point
+ *
+ * \return path prefix
+ *
+ */
+std::string GetDirectoryPathForExternalStorage();
} // namespace common_installer
#include <string>
#include <vector>
-#include "common/utils/subprocess.h"
#include "common/step/filesystem/step_create_per_user_storage_directories.h"
#include "common/shared_dirs.h"
std::string package_id = context_->pkgid.get();
LOG(INFO) << "Creating per-user directories for package: " << package_id;
- Subprocess pkgdir_tool_process("/usr/bin/pkgdir-tool");
- pkgdir_tool_process.RunWithArgs({"--create", "--pkgid", package_id});
- int result = pkgdir_tool_process.Wait();
- if (result) {
+ if (!common_installer::CreateSkelDirectories(package_id)) {
+ LOG(ERROR) << "Failed to create skel dirs";
+ return Status::APP_DIR_ERROR;
+ }
+
+ if (!common_installer::RequestCopyUserDirectories(package_id)) {
LOG(ERROR) << "Failed to create shared dirs for users";
return Status::APP_DIR_ERROR;
}
+
return Status::OK;
}
#include <vector>
#include "common/installer_context.h"
-#include "common/pkgmgr_registration.h"
-#include "common/utils/subprocess.h"
-
+#include "common/shared_dirs.h"
namespace common_installer {
namespace filesystem {
std::string package_id = context_->pkgid.get();
- Subprocess pkgdir_tool_process("/usr/bin/pkgdir-tool");
- pkgdir_tool_process.RunWithArgs({"--delete", "--pkgid", package_id});
- int result = pkgdir_tool_process.Wait();
- if (result) {
+ if (!common_installer::DeleteSkelDirectories(package_id)) {
+ LOG(ERROR) << "Failed to delete skel dirs";
+ return Status::APP_DIR_ERROR;
+ }
+
+ if (!common_installer::RequestDeleteUserDirectories(package_id)) {
LOG(ERROR) << "Failed to delete shared dirs for users";
- return Step::Status::APP_DIR_ERROR;
+ return Status::APP_DIR_ERROR;
}
+
return Step::Status::OK;
}
#include <linux/limits.h>
#include <unzip.h>
#include <zlib.h>
+#include <attr/libattr.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
LOG(ERROR) << "Unable to create destination directory" << dst;
return false;
}
+ if (attr_copy_file(src.c_str(), dst.c_str(), NULL, NULL)) {
+ LOG(ERROR) << "attr_copy_file failed";
+ return false;
+ }
} else {
if (!(flags & FS_MERGE_DIRECTORIES)) {
LOG(ERROR) << "Destination directory " << dst.string()
continue;
bf::copy_file(current, target);
}
+ if (attr_copy_file(src.c_str(), dst.c_str(), NULL, NULL)) {
+ LOG(ERROR) << "attr_copy_file failed";
+ return false;
+ }
} catch (const bf::filesystem_error& error) {
LOG(ERROR) << "Failed to copy directory: " << error.what();
return false;
# Target - deps
APPLY_PKG_CONFIG(${TARGET_PKGDIR_TOOL} PUBLIC
PKGMGR_INSTALLER_DEPS
+ GDBUS_DEPS
)
# Target - in-package deps
TARGET_LINK_LIBRARIES(${TARGET_PKGDIR_TOOL} PUBLIC ${TARGET_LIBNAME_COMMON})
# Install
INSTALL(TARGETS ${TARGET_PKGDIR_TOOL} DESTINATION ${BINDIR})
-
-
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.pkgdir_tool.service DESTINATION ${PREFIX}/share/dbus-1/system-services/)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.pkgdir_tool.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/)
--- /dev/null
+<?xml version="1.0"?>
+<!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.pkgdir_tool"/>
+ <allow send_destination="org.tizen.pkgdir_tool"/>
+ </policy>
+ <policy user="tizenglobalapp">
+ <allow send_destination="org.tizen.pkgdir_tool"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="org.tizen.pkgdir_tool"/>
+ </policy>
+</busconfig>
--- /dev/null
+[D-BUS Service]
+User=root
+Name=org.tizen.pkgdir_tool
+Exec=/usr/bin/pkgdir-tool
// Use of this source code is governed by an apache-2.0 license that can be
// found in the LICENSE file.
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-#include <boost/program_options.hpp>
-#include <boost/system/error_code.hpp>
-
+#include <glib.h>
+#include <gio/gio.h>
#include <manifest_parser/utils/logging.h>
-#include <vcore/Certificate.h>
-#include <pkgmgr-info.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <tzplatform_config.h>
-#include <sys/xattr.h>
-
-#include <algorithm>
-#include <cassert>
-#include <cstring>
-#include <exception>
-#include <iterator>
-#include <string>
-#include <utility>
-#include <vector>
#include "common/shared_dirs.h"
-#include "common/security_registration.h"
-#include "common/pkgmgr_registration.h"
-#include "common/utils/base64.h"
-#include "common/utils/file_util.h"
-#include "common/utils/glist_range.h"
-
-namespace bf = boost::filesystem;
-namespace bpo = boost::program_options;
-namespace bs = boost::system;
+
+#define UNUSED(expr) (void)(expr)
+
namespace ci = common_installer;
namespace {
-enum class DirectoryOperation {
- NONE,
- CREATE_INTERNAL,
- DELETE
+const char kDBusInstropectionXml[] =
+ "<node>"
+ " <interface name='org.tizen.pkgdir_tool'>"
+ " <method name='CopyUserDirs'>"
+ " <arg type='s' name='pkgid' direction='in'/>"
+ " <arg type='b' name='result' direction='out'/>"
+ " </method>"
+ " <method name='DeleteUserDirs'>"
+ " <arg type='s' name='pkgid' direction='in'/>"
+ " <arg type='b' name='result' direction='out'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+const char kDBusServiceName[] = "org.tizen.pkgdir_tool";
+const char kDBusObjectPath[] = "/org/tizen/pkgdir_tool";
+
+class PkgdirToolService {
+ public:
+ PkgdirToolService();
+ ~PkgdirToolService();
+ bool Init();
+ void Run();
+
+ private:
+ void Finish();
+ void RenewTimeout(int ms);
+ void HandleMethodCall(GDBusConnection* connection,
+ const gchar* sender, const gchar* object_path,
+ const gchar* interface_name, const gchar* method_name,
+ GVariant* parameters, GDBusMethodInvocation* invocation,
+ gpointer user_data);
+ void OnBusAcquired(GDBusConnection* connection, const gchar* name,
+ gpointer user_data);
+
+ GDBusNodeInfo* node_info_;
+ guint owner_id_;
+ GMainLoop* loop_;
+ guint sid_;
};
-const char kCreateInternalMode[] = "create";
-const char kDeleteMode[] = "delete";
-const char kSinglePkgId[] = "pkgid";
-const char kAllPkgIds[] = "allglobalpkgs";
-
-template<typename ... Arguments>
-bool ExclusiveOptions(const bpo::variables_map& vm, Arguments... args) {
- std::vector<std::string> exclusive_options {args...};
- sort(exclusive_options.begin(), exclusive_options.end());
- std::vector<std::string> given_options;
- std::transform(vm.begin(), vm.end(), std::back_inserter(given_options),
- [](const bpo::variables_map::value_type& pair) {return pair.first;});
- sort(given_options.begin(), given_options.end());
-
- std::vector<std::string> options_intersection;
- std::set_intersection(exclusive_options.begin(), exclusive_options.end(),
- given_options.begin(), given_options.end(),
- back_inserter(options_intersection));
- if (options_intersection.size() > 1) {
- std::string exception = std::string("Exclusive options :") +
- options_intersection[0] + " " + options_intersection[1];
- LOG(ERROR) << exception.c_str();
- return false;
- }
- return true;
+PkgdirToolService::PkgdirToolService() :
+ node_info_(nullptr), owner_id_(0), loop_(nullptr), sid_(0) {
}
-DirectoryOperation ParseDirectoryOptions(const bpo::variables_map& opt_map) {
- if (opt_map.count(kCreateInternalMode))
- return DirectoryOperation::CREATE_INTERNAL;
+PkgdirToolService::~PkgdirToolService() {
+ Finish();
+}
+
+bool PkgdirToolService::Init() {
+ node_info_ = g_dbus_node_info_new_for_xml(kDBusInstropectionXml, nullptr);
+ if (!node_info_) {
+ LOG(ERROR) << "Failed to create DBus node info";
+ return false;
+ }
+ owner_id_ = g_bus_own_name(G_BUS_TYPE_SYSTEM, kDBusServiceName,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ [](GDBusConnection* connection, const gchar* name,
+ gpointer user_data) {
+ reinterpret_cast<PkgdirToolService*>(user_data)->OnBusAcquired(
+ connection, name, user_data);
+ },
+ nullptr, nullptr, this, nullptr);
+
+ loop_ = g_main_loop_new(nullptr, FALSE);
+ if (!loop_) {
+ LOG(ERROR) << "Failed to create main loop";
+ return false;
+ }
- if (opt_map.count(kDeleteMode))
- return DirectoryOperation::DELETE;
+ RenewTimeout(5000);
- return DirectoryOperation::NONE;
+ return true;
}
-bpo::options_description CreateProgramOptions() {
- bpo::options_description options("Allowed options");
- options.add_options()
- (kCreateInternalMode, "create per user diretories for global package")
- (kDeleteMode, "delete per user diretories for global package")
- (kAllPkgIds, "install directories for all global applications")
- (kSinglePkgId, bpo::value<std::string>(), "package ID");
- return options;
+void PkgdirToolService::Run() {
+ g_main_loop_run(loop_);
}
-ci::PkgList GetPackageListFromArgs(const bpo::variables_map& opt_map) {
- bool allglobalpkgs = opt_map.count(kAllPkgIds) != 0;
- if (allglobalpkgs) return ci::CreatePkgInformationList();
+void PkgdirToolService::Finish() {
+ if (owner_id_ > 0)
+ g_bus_unown_name(owner_id_);
+ if (node_info_)
+ g_dbus_node_info_unref(node_info_);
+ if (loop_)
+ g_main_loop_unref(loop_);
+}
- std::vector<std::string> pkgs;
- if (opt_map.count(kSinglePkgId)) {
- std::string pkgid = opt_map[kSinglePkgId].as<std::string>();
- pkgs.push_back(std::move(pkgid));
- }
- return ci::CreatePkgInformationList(getuid(), pkgs);
+void PkgdirToolService::RenewTimeout(int ms) {
+ if (sid_)
+ g_source_remove(sid_);
+ sid_ = g_timeout_add(ms,
+ [](gpointer user_data) {
+ g_main_loop_quit(
+ reinterpret_cast<PkgdirToolService*>(user_data)->loop_);
+ return FALSE;
+ },
+ this);
}
-bool ParseCommandLine(int argc, char** argv,
- const bpo::options_description& options,
- bpo::variables_map* opt_map) {
- bpo::store(bpo::parse_command_line(argc, argv, options), *opt_map);
- if (!ExclusiveOptions(*opt_map, kCreateInternalMode, kDeleteMode)) {
- LOG(ERROR) << "Could not parse arguments: incorrect directory operation";
- return false;
+void PkgdirToolService::HandleMethodCall(GDBusConnection* connection,
+ const gchar* sender, const gchar* object_path, const gchar* interface_name,
+ const gchar* method_name, GVariant* parameters,
+ GDBusMethodInvocation* invocation, gpointer user_data) {
+ UNUSED(connection);
+ UNUSED(sender);
+ UNUSED(object_path);
+ UNUSED(interface_name);
+ UNUSED(user_data);
+ char* val;
+ g_variant_get(parameters, "(s)", &val);
+ bool r = false;
+ LOG(INFO) << "Incomming method call: " << method_name;
+ if (g_strcmp0(method_name, "CopyUserDirs") == 0) {
+ r = ci::CopyUserDirectories(std::string(val));
+ } else if (g_strcmp0(method_name, "DeleteUserDirs") == 0) {
+ r = ci::DeleteUserDirectories(std::string(val));
+ } else {
+ LOG(ERROR) << "Unknown method call: " << method_name;
}
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", r));
- if (!ExclusiveOptions(*opt_map, kSinglePkgId, kAllPkgIds)) {
- LOG(ERROR) << "Could not parse arguments: incorrect pkgid or pkgid\'s";
- return false;
+ RenewTimeout(5000);
+}
+
+void PkgdirToolService::OnBusAcquired(
+ GDBusConnection* connection, const gchar* name, gpointer user_data) {
+ UNUSED(name);
+ UNUSED(user_data);
+ GError* err = nullptr;
+ GDBusInterfaceVTable vtable = {
+ [](GDBusConnection* connection, const gchar* sender,
+ const gchar* object_path, const gchar* interface_name,
+ const gchar* method_name, GVariant* parameters,
+ GDBusMethodInvocation* invocation, gpointer user_data) {
+ reinterpret_cast<PkgdirToolService*>(user_data)->HandleMethodCall(
+ connection, sender, object_path, interface_name, method_name,
+ parameters, invocation, user_data);
+ },
+ nullptr, nullptr, {0, }
+ };
+
+ guint reg_id = g_dbus_connection_register_object(connection, kDBusObjectPath,
+ node_info_->interfaces[0], &vtable, this, nullptr, &err);
+ if (reg_id == 0) {
+ LOG(ERROR) << "Register failed";
+ if (err) {
+ LOG(ERROR) << "Error message: " << err->message;
+ g_error_free(err);
+ }
+ } else {
+ LOG(INFO) << "DBus service registered";
}
- bpo::notify(*opt_map);
- return true;
}
} // namespace
-
-int main(int argc, char** argv) {
- bpo::options_description options = CreateProgramOptions();
- bpo::variables_map opt_map;
- if (!ParseCommandLine(argc, argv, options, &opt_map)) return -1;
-
- assert(setuid(0) == 0);
-
- auto dir_operation = ParseDirectoryOptions(opt_map);
- auto pkgs = GetPackageListFromArgs(opt_map);
-
- for (auto& p : pkgs) {
- switch (dir_operation) {
- case DirectoryOperation::CREATE_INTERNAL: {
- LOG(DEBUG) << "Running directory creation for package id: " << p.pkg_id;
- ci::PerformInternalDirectoryCreationForAllUsers(p.pkg_id,
- p.author_id);
- const std::string pkg_path = ci::GetDirectoryPathForInternalStorage();
- ci::SetPackageDirectorySmackRulesForAllUsers(pkg_path,
- p.pkg_id,
- p.author_id,
- p.api_version);
-
- ci::CreateSkeletonDirectoriesForPackage(p.pkg_id);
- }
- break;
- case DirectoryOperation::DELETE: {
- LOG(DEBUG) << "Running directory deletion for package id: " << p.pkg_id;
- ci::PerformDirectoryDeletionForAllUsers(p.pkg_id);
- }
- break;
- default:
- break;
- }
+int main() {
+ PkgdirToolService service;
+ if (!service.Init()) {
+ LOG(ERROR) << "Failed to initialize service";
+ return -1;
}
+ service.Run();
return 0;
}