Rework pkgdir-tool 33/67933/26
authorSangyoon Jang <s89.jang@samsung.com>
Fri, 29 Apr 2016 08:10:31 +0000 (17:10 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Mon, 23 May 2016 07:46:59 +0000 (16:46 +0900)
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 <s89.jang@samsung.com>
14 files changed:
CMakeLists.txt
packaging/app-installers.spec
src/common/CMakeLists.txt
src/common/security_registration.cc
src/common/security_registration.h
src/common/shared_dirs.cc
src/common/shared_dirs.h
src/common/step/filesystem/step_create_per_user_storage_directories.cc
src/common/step/filesystem/step_remove_per_user_storage_directories.cc
src/common/utils/file_util.cc
src/pkgdir_tool/CMakeLists.txt
src/pkgdir_tool/org.tizen.pkgdir_tool.conf [new file with mode: 0644]
src/pkgdir_tool/org.tizen.pkgdir_tool.service [new file with mode: 0644]
src/pkgdir_tool/pkgdir_tool.cc

index ff80564..ab9e6fc 100644 (file)
@@ -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)
index 588cd75..a0419b3 100644 (file)
@@ -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
 
index 9b853b2..68e510a 100644 (file)
@@ -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})
index 7935a64..16208e0 100644 (file)
@@ -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<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 {
@@ -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<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
index cc7a231..924b9ba 100644 (file)
@@ -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_
index 4e78a60..e911484 100644 (file)
@@ -9,6 +9,8 @@
 #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>
@@ -18,7 +20,9 @@
 #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>
@@ -44,6 +48,7 @@ namespace ci = common_installer;
 
 namespace {
 
+typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
 const std::vector<const char*> 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<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;
@@ -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<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)
@@ -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;
 }
 
index 7904c1f..b93a4f7 100644 (file)
@@ -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<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
 
index 327a051..39b630b 100644 (file)
@@ -5,7 +5,6 @@
 #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"
@@ -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;
 }
 
index 99546e1..c42594a 100644 (file)
@@ -8,9 +8,7 @@
 #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 {
@@ -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;
 }
 
index e996614..1c71dca 100644 (file)
@@ -7,6 +7,7 @@
 #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>
@@ -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;
index 12b2343..f233610 100644 (file)
@@ -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 (file)
index 0000000..83c616a
--- /dev/null
@@ -0,0 +1,16 @@
+<?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>
diff --git a/src/pkgdir_tool/org.tizen.pkgdir_tool.service b/src/pkgdir_tool/org.tizen.pkgdir_tool.service
new file mode 100644 (file)
index 0000000..2a0bcc2
--- /dev/null
@@ -0,0 +1,4 @@
+[D-BUS Service]
+User=root
+Name=org.tizen.pkgdir_tool
+Exec=/usr/bin/pkgdir-tool
index 55aed4a..9375842 100644 (file)
 // 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;
 }