From 41b7ac5c6c5d55423a249a688a5dcded3a8c7b59 Mon Sep 17 00:00:00 2001 From: Sangyoon Jang Date: Fri, 29 Apr 2016 17:10:31 +0900 Subject: [PATCH] Rework pkgdir-tool For several issue(performace, code consistency, ...), the pkgdir-tool is reworked. The app-installer calls security-manager api just once for labeling skel directories, not for each users. And the pkgdir-tool copies those labeled directories to each user's home directory. The pkgdir-tool doesn't have setuid bit no more(because of security issue), so it will be launched by dbus activation. (It still needs root privilege for writing permission to user directories) Requires: - https://review.tizen.org/gerrit/68140 - https://review.tizen.org/gerrit/68294 Change-Id: Ib96c41f08d681443c5993bedd3fcf4f1c91db8c3 Signed-off-by: Sangyoon Jang --- CMakeLists.txt | 2 + packaging/app-installers.spec | 6 +- src/common/CMakeLists.txt | 3 + src/common/security_registration.cc | 96 +++++ src/common/security_registration.h | 17 + src/common/shared_dirs.cc | 388 +++++++++------------ src/common/shared_dirs.h | 87 +++-- .../step_create_per_user_storage_directories.cc | 12 +- .../step_remove_per_user_storage_directories.cc | 17 +- src/common/utils/file_util.cc | 9 + src/pkgdir_tool/CMakeLists.txt | 5 +- src/pkgdir_tool/org.tizen.pkgdir_tool.conf | 16 + src/pkgdir_tool/org.tizen.pkgdir_tool.service | 4 + src/pkgdir_tool/pkgdir_tool.cc | 276 ++++++++------- 14 files changed, 527 insertions(+), 411 deletions(-) create mode 100644 src/pkgdir_tool/org.tizen.pkgdir_tool.conf create mode 100644 src/pkgdir_tool/org.tizen.pkgdir_tool.service diff --git a/CMakeLists.txt b/CMakeLists.txt index ff80564..ab9e6fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ PKG_CHECK_MODULES(LIBXML_DEPS REQUIRED libxml-2.0) 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) diff --git a/packaging/app-installers.spec b/packaging/app-installers.spec index 588cd75..a0419b3 100644 --- a/packaging/app-installers.spec +++ b/packaging/app-installers.spec @@ -13,6 +13,7 @@ Source1001: app-installers-tests.manifest BuildRequires: boost-devel BuildRequires: cmake +BuildRequires: libattr-devel BuildRequires: libcap-devel BuildRequires: gtest-devel BuildRequires: pkgconfig(pkgmgr) @@ -33,6 +34,7 @@ BuildRequires: pkgconfig(security-privilege-manager) BuildRequires: pkgconfig(tpk-manifest-handlers) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(libgum) Requires: ca-certificates-tizen Requires: libtzplatform-config @@ -79,7 +81,9 @@ make %{?_smp_mflags} %{_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 diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 9b853b2..68e510a 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -98,12 +98,15 @@ APPLY_PKG_CONFIG(${TARGET_LIBNAME_COMMON} PUBLIC 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}) diff --git a/src/common/security_registration.cc b/src/common/security_registration.cc index 7935a64..16208e0 100644 --- a/src/common/security_registration.cc +++ b/src/common/security_registration.cc @@ -163,6 +163,65 @@ bool PrepareRequest(const std::string& app_id, const std::string& pkg_id, 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(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(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(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(error)); + *error_message += ":<" + errnum + ">"; + return false; + } + } + } + + return true; +} + } // namespace namespace common_installer { @@ -298,4 +357,41 @@ bool UnregisterSecurityContextForPkgId(const std::string &pkg_id, 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(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(error)); + *error_message += ":<" + errnum + ">"; + security_manager_path_req_free(req); + return false; + } + + security_manager_path_req_free(req); + + return true; +} + } // namespace common_installer diff --git a/src/common/security_registration.h b/src/common/security_registration.h index cc7a231..924b9ba 100644 --- a/src/common/security_registration.h +++ b/src/common/security_registration.h @@ -109,6 +109,23 @@ bool UnregisterSecurityContextForManifest(const std::string& pkg_id, uid_t uid, 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_ diff --git a/src/common/shared_dirs.cc b/src/common/shared_dirs.cc index 4e78a60..e911484 100644 --- a/src/common/shared_dirs.cc +++ b/src/common/shared_dirs.cc @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -18,7 +20,9 @@ #include #include #include - +#include +#include +#include #include #include @@ -44,6 +48,7 @@ namespace ci = common_installer; namespace { +typedef std::vector> user_list; const std::vector kEntries = { {"/"}, {"cache/"}, @@ -56,6 +61,11 @@ const char kTrustedDir[] = "shared/trusted"; 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); @@ -136,41 +146,6 @@ ci::PkgList GetPkgInformation(uid_t uid, const std::string& pkgid) { 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 privileges; - std::vector 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; @@ -233,8 +208,7 @@ bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid, 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 {}; @@ -248,11 +222,10 @@ bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) { 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; @@ -260,7 +233,8 @@ bool CreateUserDirectories(uid_t user, const std::string& pkgid, 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; @@ -281,45 +255,6 @@ bool CreateUserDirectories(uid_t user, const std::string& pkgid, 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; @@ -331,72 +266,74 @@ bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) { 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(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) @@ -440,132 +377,121 @@ bool PerformExternalDirectoryCreationForUser(uid_t user, 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; } diff --git a/src/common/shared_dirs.h b/src/common/shared_dirs.h index 7904c1f..b93a4f7 100644 --- a/src/common/shared_dirs.h +++ b/src/common/shared_dirs.h @@ -90,76 +90,93 @@ bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid, 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& pkgs = + std::vector()); + +/** + * \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& pkgs = - std::vector()); +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 diff --git a/src/common/step/filesystem/step_create_per_user_storage_directories.cc b/src/common/step/filesystem/step_create_per_user_storage_directories.cc index 327a051..39b630b 100644 --- a/src/common/step/filesystem/step_create_per_user_storage_directories.cc +++ b/src/common/step/filesystem/step_create_per_user_storage_directories.cc @@ -5,7 +5,6 @@ #include #include -#include "common/utils/subprocess.h" #include "common/step/filesystem/step_create_per_user_storage_directories.h" #include "common/shared_dirs.h" @@ -21,13 +20,16 @@ common_installer::Step::Status StepCreatePerUserStorageDirectories::process() { 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; } diff --git a/src/common/step/filesystem/step_remove_per_user_storage_directories.cc b/src/common/step/filesystem/step_remove_per_user_storage_directories.cc index 99546e1..c42594a 100644 --- a/src/common/step/filesystem/step_remove_per_user_storage_directories.cc +++ b/src/common/step/filesystem/step_remove_per_user_storage_directories.cc @@ -8,9 +8,7 @@ #include #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 { @@ -20,13 +18,16 @@ Step::Status StepRemovePerUserStorageDirectories::process() { 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; } diff --git a/src/common/utils/file_util.cc b/src/common/utils/file_util.cc index e996614..1c71dca 100644 --- a/src/common/utils/file_util.cc +++ b/src/common/utils/file_util.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -133,6 +134,10 @@ bool CopyDir(const bf::path& src, const bf::path& dst, FSFlag flags) { 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() @@ -166,6 +171,10 @@ bool CopyDir(const bf::path& src, const bf::path& dst, FSFlag flags) { 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; diff --git a/src/pkgdir_tool/CMakeLists.txt b/src/pkgdir_tool/CMakeLists.txt index 12b2343..f233610 100644 --- a/src/pkgdir_tool/CMakeLists.txt +++ b/src/pkgdir_tool/CMakeLists.txt @@ -10,11 +10,12 @@ TARGET_INCLUDE_DIRECTORIES(${TARGET_PKGDIR_TOOL} PUBLIC "${CMAKE_CURRENT_SOURCE_ # 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/) diff --git a/src/pkgdir_tool/org.tizen.pkgdir_tool.conf b/src/pkgdir_tool/org.tizen.pkgdir_tool.conf new file mode 100644 index 0000000..83c616a --- /dev/null +++ b/src/pkgdir_tool/org.tizen.pkgdir_tool.conf @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/src/pkgdir_tool/org.tizen.pkgdir_tool.service b/src/pkgdir_tool/org.tizen.pkgdir_tool.service new file mode 100644 index 0000000..2a0bcc2 --- /dev/null +++ b/src/pkgdir_tool/org.tizen.pkgdir_tool.service @@ -0,0 +1,4 @@ +[D-BUS Service] +User=root +Name=org.tizen.pkgdir_tool +Exec=/usr/bin/pkgdir-tool diff --git a/src/pkgdir_tool/pkgdir_tool.cc b/src/pkgdir_tool/pkgdir_tool.cc index 55aed4a..9375842 100644 --- a/src/pkgdir_tool/pkgdir_tool.cc +++ b/src/pkgdir_tool/pkgdir_tool.cc @@ -2,162 +2,180 @@ // Use of this source code is governed by an apache-2.0 license that can be // found in the LICENSE file. -#include -#include -#include -#include - +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include #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[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; +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 -bool ExclusiveOptions(const bpo::variables_map& vm, Arguments... args) { - std::vector exclusive_options {args...}; - sort(exclusive_options.begin(), exclusive_options.end()); - std::vector 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 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(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(), "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 pkgs; - if (opt_map.count(kSinglePkgId)) { - std::string pkgid = opt_map[kSinglePkgId].as(); - 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(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(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; } -- 2.7.4