SET(TARGET_LIBNAME_TPK "tpk-installer")
SET(TARGET_WGT_BACKEND "wgt-backend")
SET(TARGET_TPK_BACKEND "tpk-backend")
-SET(TARGET_PKGDIR_MAKER "pkgdir_maker.py")
+SET(TARGET_PKGDIR_TOOL "pkgdir-tool")
ADD_DEFINITIONS("-Wall")
ADD_DEFINITIONS("-Wextra")
PKG_CHECK_MODULES(ENCRYPTION_DEPS REQUIRED libwebappenc)
PKG_CHECK_MODULES(APPMANAGER_DEPS REQUIRED capi-appfw-app-manager)
-FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex)
+FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
FIND_PACKAGE(GTest REQUIRED)
ADD_SUBDIRECTORY(src)
<manifest>
- <request>
- <domain name="_"/>
- </request>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/pkgdir-tool" exec_label="User" />
+ </assign>
</manifest>
ln -s %{_bindir}/tpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/tpk
%post
-chown root:users %{_bindir}/pkgdir_maker
-chmod 4750 %{_bindir}/pkgdir_maker
-chmod 0700 %{_bindir}/pkgdir_maker_impl.sh
+ln -sf %{_bindir}/pkgdir-tool %{_bindir}/pkgdir_maker
%postun
/sbin/ldconfig
%defattr(-,root,root)
%manifest app-installers.manifest
%{_libdir}/libcommon-installer.so*
-%{_bindir}/pkgdir_maker_impl.sh
-%{_bindir}/pkgdir_maker
+%attr(6750,root,users) %{_bindir}/pkgdir-tool
%license LICENSE
%files -n wgt-backend
ADD_SUBDIRECTORY(common)
ADD_SUBDIRECTORY(wgt)
ADD_SUBDIRECTORY(tpk)
-ADD_SUBDIRECTORY(pkgdir_maker)
+ADD_SUBDIRECTORY(pkgdir_tool)
ADD_SUBDIRECTORY(unit_tests)
return PMINFO_R_OK;
}
+int PkgmgrForeachPrivilegeCallback(const char* privilege_name,
+ void* user_data) {
+ auto* data = static_cast<std::vector<std::string>*>(user_data);
+ data->emplace_back(privilege_name);
+ return PMINFO_R_OK;
+}
+
} // anonymous namespace
namespace common_installer {
return ret;
}
+bool QueryPrivilegesForPkgId(const std::string& pkg_id, uid_t uid,
+ std::vector<std::string>* result) {
+ pkgmgrinfo_pkginfo_h package_info;
+ if (pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_id.c_str(), uid, &package_info)
+ != PMINFO_R_OK) {
+ return false;
+ }
+
+ bool ret = pkgmgrinfo_pkginfo_foreach_privilege(package_info,
+ &PkgmgrForeachPrivilegeCallback, result) == PMINFO_R_OK;
+ pkgmgrinfo_pkginfo_destroy_pkginfo(package_info);
+ return ret;
+}
+
bool IsPackageInstalled(const std::string& pkg_id, RequestMode request_mode) {
pkgmgrinfo_pkginfo_h handle;
int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_id.c_str(), getuid(),
std::vector<std::string>* result, uid_t uid);
/**
+ * \brief Adapter interface for external PkgMgr module used for getting
+ * list of privileges for given package
+ *
+ * \param pkg_id id of package
+ * \param uid user id
+ * \param result result - privileges
+ *
+ * \return true if success
+ */
+bool QueryPrivilegesForPkgId(const std::string& pkg_id, uid_t uid,
+ std::vector<std::string>* result);
+
+/**
* \brief Adapter interface for external PkgMgr module used for checking
* if given package is installed/registered
*
};
bool PrepareRequest(const std::string& app_id, const std::string& pkg_id,
- const boost::filesystem::path& path, manifest_x* manifest,
+ const boost::filesystem::path& path, uid_t uid,
+ const std::vector<std::string>& privileges,
app_inst_req* req) {
if (app_id.empty() || pkg_id.empty()) {
LOG(ERROR) << "Appid or pkgid is empty. Both values must be set";
return false;
}
+ error = security_manager_app_inst_req_set_uid(req, uid);
+ if (error != SECURITY_MANAGER_SUCCESS) {
+ return false;
+ }
+
if (!path.empty()) {
for (auto& policy : kSecurityPolicies) {
bf::path subpath = path / policy.first;
}
}
- if (manifest) {
- for (const char* priv : GListRange<char*>(manifest->privileges)) {
- security_manager_app_inst_req_add_privilege(req, priv);
- }
+ for (auto& priv : privileges) {
+ security_manager_app_inst_req_add_privilege(req, priv.c_str());
}
-
return true;
}
+} // namespace
+
+namespace common_installer {
+
bool RegisterSecurityContext(const std::string& app_id,
- const std::string& pkg_id, const boost::filesystem::path& path,
- manifest_x* manifest) {
+ const std::string& pkg_id, const boost::filesystem::path& path, uid_t uid,
+ const std::vector<std::string>& privileges) {
app_inst_req* req;
int error = security_manager_app_inst_req_new(&req);
return false;
}
- if (!PrepareRequest(app_id, pkg_id, path, manifest, req)) {
+ if (!PrepareRequest(app_id, pkg_id, path, uid, privileges, req)) {
LOG(ERROR) << "Failed while preparing security_manager_app_inst_req";
security_manager_app_inst_req_free(req);
return false;
return true;
}
-
bool UnregisterSecurityContext(const std::string& app_id,
- const std::string& pkg_id) {
+ const std::string& pkg_id, uid_t uid) {
app_inst_req* req;
int error = security_manager_app_inst_req_new(&req);
return false;
}
- if (!PrepareRequest(app_id, pkg_id, bf::path(), nullptr, req)) {
+ if (!PrepareRequest(app_id, pkg_id, bf::path(), uid, {}, req)) {
LOG(ERROR) << "Failed while preparing security_manager_app_inst_req";
security_manager_app_inst_req_free(req);
return false;
return true;
}
-} // namespace
-
-namespace common_installer {
-
-bool RegisterSecurityContextForApps(
+bool RegisterSecurityContextForManifest(
const std::string& pkg_id, const boost::filesystem::path& path,
- manifest_x* manifest) {
+ uid_t uid, manifest_x* manifest) {
+ std::vector<std::string> priv_vec;
+ for (const char* priv : GListRange<char*>(manifest->privileges)) {
+ priv_vec.emplace_back(priv);
+ }
for (application_x* app : GListRange<application_x*>(manifest->application)) {
if (!app->appid) {
return false;
}
if (!RegisterSecurityContext(app->appid, pkg_id,
- path, manifest)) {
+ path, uid, priv_vec)) {
return false;
}
}
return true;
}
-bool UnregisterSecurityContextForApps(
- const std::string& pkg_id, manifest_x* manifest) {
+bool UnregisterSecurityContextForManifest(const std::string& pkg_id,
+ uid_t uid, manifest_x* manifest) {
for (application_x* app : GListRange<application_x*>(manifest->application)) {
if (!app->appid) {
return false;
}
- if (!UnregisterSecurityContext(app->appid, pkg_id)) {
+ if (!UnregisterSecurityContext(app->appid, pkg_id, uid)) {
return false;
}
}
#include <sys/types.h>
#include <string>
+#include <vector>
#include "common/installer_context.h"
* Adapter interface for external Security module used for registering
* application to security context
*
- * \param pkg_id pkdid of given package
+ * \param app_id id of given application
+ * \param pkg_id id of given package
* \param path path of installed package
- * \param manifest pointer to manifest structure
+ * \param uid uid
+ * \param privileges pointer to manifest structure
*
* \return true if success
*/
-bool RegisterSecurityContextForApps(const std::string& pkg_id,
- const boost::filesystem::path& path, manifest_x* manifest);
+bool RegisterSecurityContext(const std::string& app_id,
+ const std::string& pkg_id, const boost::filesystem::path& path, uid_t uid,
+ const std::vector<std::string>& privileges);
/**
* Adapter interface for external Security module.
* Adapter interface for external Security module used for unregistering
* application from security context
*
- * \param pkg_id pkdid of given package
+ * \param app_id id of given application
+ * \param pkg_id id of given package
+ * \param uid uid
+ *
+ * \return true if success
+ */
+bool UnregisterSecurityContext(const std::string& app_id,
+ const std::string& pkg_id, uid_t uid);
+
+/**
+ * Adapter interface for external Security module.
+ *
+ * Adapter interface for external Security module used for registering
+ * package to security context
+ *
+ * \param pkg_id pkgid of given package
+ * \param path path of installed package
+ * \param uid uid
+ * \param manifest pointer to manifest structure
+ *
+ * \return true if success
+ */
+bool RegisterSecurityContextForManifest(const std::string& pkg_id,
+ const boost::filesystem::path& path, uid_t uid, manifest_x* manifest);
+
+/**
+ * Adapter interface for external Security module.
+ *
+ * Adapter interface for external Security module used for unregistering
+ * package from security context
+ *
+ * \param pkg_id pkgid of given package
+ * \param uid uid
* \param manifest pointer to manifest structure
*
* \return true if success
*/
-bool UnregisterSecurityContextForApps(const std::string& pkg_id,
+bool UnregisterSecurityContextForManifest(const std::string& pkg_id, uid_t uid,
manifest_x* manifest);
} // namespace common_installer
namespace {
+const char kCache[] = "cache";
const char kDataLocation[] = "data";
const char kSharedLocation[] = "shared";
return Status::ERROR;
}
+ if (!CacheDir())
+ return Status::ERROR;
+
return Status::OK;
}
return ret;
}
+bool StepCopyStorageDirectories::CacheDir() {
+ bs::error_code error_code;
+ bf::path cache_path = context_->pkg_path.get() / kCache;
+ bf::create_directory(cache_path, error_code);
+ if (error_code) {
+ LOG(ERROR) << "Failed to create cache directory for package";
+ return false;
+ }
+ return true;
+}
+
} // namespace filesystem
} // namespace common_installer
bool MoveAppStorage(const boost::filesystem::path& in_src,
const boost::filesystem::path& in_dst,
const char *key);
-
+ bool CacheDir();
boost::filesystem::path backup_path_;
-
SCOPE_LOG_TAG(CopyStorageDirectories)
};
namespace {
+const char kCache[] = "cache";
const char kData[] = "data";
const char kShared[] = "shared";
const char kSharedData[] = "data";
return Status::ERROR;
if (!PrivateDir())
return Status::ERROR;
+ if (!CacheDir())
+ return Status::ERROR;
return Status::OK;
}
bool StepCreateStorageDirectories::PrivateDir() {
bs::error_code error_code;
bf::path data_path = context_->pkg_path.get() / kData;
+
+ // compatibility for old tpk packages
+ if (bf::exists(data_path)) {
+ LOG(DEBUG) << "Data directory already exists";
+ return true;
+ }
+
bf::create_directory(data_path, error_code);
if (error_code) {
LOG(ERROR) << "Failed to create private directory for package";
return true;
}
+bool StepCreateStorageDirectories::CacheDir() {
+ bs::error_code error_code;
+ bf::path cache_path = context_->pkg_path.get() / kCache;
+ bf::create_directory(cache_path, error_code);
+ if (error_code) {
+ LOG(ERROR) << "Failed to create cache directory for package";
+ return false;
+ }
+ return true;
+}
+
} // namespace filesystem
} // namespace common_installer
bool ShareDir();
bool SubShareDir();
bool PrivateDir();
+ bool CacheDir();
SCOPE_LOG_TAG(CreateStorageDirectories)
};
Step::Status StepRecoverSecurity::RecoveryNew() {
if (!Check())
return Status::OK;
- UnregisterSecurityContextForApps(
- context_->pkgid.get(), context_->manifest_data.get());
+ UnregisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->uid.get(),
+ context_->manifest_data.get());
return Status::OK;
}
LOG(ERROR) << "Invalid parameters";
return Status::ERROR;
}
- if (!RegisterSecurityContextForApps(
- context_->pkgid.get(), context_->pkg_path.get(),
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
context_->manifest_data.get())) {
LOG(ERROR) << "Unsuccessful update";
return Status::ERROR;
}
Step::Status StepRegisterSecurity::process() {
- if (!RegisterSecurityContextForApps(
- context_->pkgid.get(), context_->pkg_path.get(),
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
context_->manifest_data.get())) {
return Status::ERROR;
}
}
Step::Status StepRevokeSecurity::clean() {
- if (!UnregisterSecurityContextForApps(
- context_->pkgid.get(), context_->manifest_data.get())) {
+ if (!UnregisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->uid.get(),
+ context_->manifest_data.get())) {
LOG(ERROR) << "Failure on unregistering security context for app "
<< context_->pkgid.get();
return Status::ERROR;
}
Step::Status StepRollbackDeinstallationSecurity::undo() {
- if (!RegisterSecurityContextForApps(
- context_->pkgid.get(), context_->pkg_path.get(),
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
context_->manifest_data.get())) {
LOG(ERROR) << "Failure on re-installing security context for app "
<< context_->pkgid.get();
}
Step::Status StepRollbackInstallationSecurity::undo() {
- if (!UnregisterSecurityContextForApps(
- context_->pkgid.get(), context_->manifest_data.get())) {
+ if (!UnregisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->uid.get(),
+ context_->manifest_data.get())) {
return Status::ERROR;
}
LOG(DEBUG) << "Security context uninstalled";
namespace security {
Step::Status StepUpdateSecurity::process() {
- if (!RegisterSecurityContextForApps(
- context_->pkgid.get(), context_->pkg_path.get(),
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
context_->manifest_data.get())) {
return Status::ERROR;
}
}
Step::Status StepUpdateSecurity::undo() {
- if (!RegisterSecurityContextForApps(
- context_->pkgid.get(), context_->pkg_path.get(),
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
context_->old_manifest_data.get())) {
return Status::ERROR;
}
+++ /dev/null
-add_executable(pkgdir_maker "pkgdir_maker.cc")
-
-INSTALL(FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/pkgdir_maker_impl.sh
- ${CMAKE_CURRENT_BINARY_DIR}/pkgdir_maker
- DESTINATION ${BINDIR})
-
+++ /dev/null
-/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
-
-/* pkgdir_maker.cc
- * A tool creating/deleting data directories of global app packages.
- *
- * Global apps are installed in /usr/apps/, but this path is not allowed for
- * users to write their data. To store app data of global apps, the data and
- * cache directories have to be created.
- *
- * This tool does two things:
- * 1. creates the global app package's data and cache directories
- * ({pkgid}/data, {pkgid}/cache) into all user's apps_rw/ directories.
- * Proper owner, group, permission and SMACK labels are set for those dirs.
- * 2. For new users in the future, the same directories are create into the
- * user home template, /etc/skel/.
- *
- * NOTE: For prototyping, actual implementation is made as a bash script
- * (pkgdir_maker_impl.sh), but later it is to be replaced with native code.
- */
-
-#include <errno.h>
-#include <libgen.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define BUFSIZE 1024
-
-int main(int argc, char** argv) {
- char cmd[BUFSIZE] = {0, };
- char tmp[BUFSIZE] = {0, };
- int i;
-
- snprintf(cmd, BUFSIZE, "pkgdir_maker_impl.sh");
-
- for (i=1; i < argc; i++) {
- snprintf(tmp, BUFSIZE, "%s %s", cmd, argv[i]);
- snprintf(cmd, BUFSIZE, "%s", tmp);
- }
-
- // set uid to root
- // NOTE: Even the setuid permission is set to the executable,
- // this routine is needed.
- setuid(0);
- seteuid(0);
-
- return system(cmd);
-}
+++ /dev/null
-#!/bin/bash
-# Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file
-VERSION="0.1.0"
-
-### CONFIG
-CONFIG_HomeDir="/home"
-CONFIG_UserAppDir="${CONFIG_HomeDir}/_USERID_/apps_rw"
-CONFIG_UserGroup="users"
-CONFIG_SkelAppDir="/etc/skel/apps_rw"
-CONFIG_SkelOwner="root"
-CONFIG_SkelGroup="root"
-
-
-### Directories to be created
-DIRS=( DIR_root DIR_data DIR_cache )
-# path type owner group permission SMACK_label SMACK_transmute SMACK_exec
-DIR_root=( "_PKGID_" "d" "_USERNAME_" "_USERGROUP_" 750 "User::Home" 1 0 )
-DIR_data=( "_PKGID_/data" "d" "_USERNAME_" "_USERGROUP_" 750 "User::Pkg::_PKGID_" 1 0 )
-DIR_cache=( "_PKGID_/cache" "d" "_USERNAME_" "_USERGROUP_" 750 "User::Pkg::_PKGID_" 1 0 )
-
-
-### Utils
-## Print log
-function LOG
-{
- LABEL=$1
- MSG="[${LABEL}] $2"
- # Skip printing debug log without OPTION_verbose
- if [[ ${LABEL} == "DEBUG" && ! -n ${OPTION_verbose} ]]; then
- return 0
- fi
- # Print log
- echo -e "${MSG}"
- # Exit if error log is given
- if [[ "${LABEL}" == "ERROR" ]]; then
- exit 1
- fi
- return 0
-}
-
-## Get valid user list
-# Returns: return_getUserList (the user list array)
-function getUserList
-{
- return_getUserList=( ) # return variable(array)
- local homeDirList=`ls ${CONFIG_HomeDir}`
- for userName in ${homeDirList}; do
- # if $HOME/apps_rw exists, it is assumed that the user exists.
- local appDir=${CONFIG_UserAppDir/_USERID_/$userName}
- if [[ -d "$appDir" ]]; then
- LOG DEBUG "Check if $appDir/ exists... Found. user $userName is added."
- # Append new item into array
- return_getUserList[${#return_getUserList[*]}]="$userName"
- else
- LOG DEBUG "Check if $appDir/ exists... Not found."
- fi
- done
-}
-
-
-## Get real dirinfo
-# Returns: return_getDirInfo (Directory info array)
-function getDirInfo
-{
- local dirname=$1
- local pkgid=$2
- local username=$3
- local usergroup=$4
- return_getDirInfo=( )
-
- # NOTE: indirect reference + array copy
- eval dirinfo_template=\( \${${dirname}[@]} \)
-
- for value in "${dirinfo_template[@]}"; do
- value=${value//_PKGID_/$pkgid}
- value=${value//_USERNAME_/$username}
- value=${value//_USERGROUP_/$usergroup}
- return_getDirInfo[${#return_getDirInfo[*]}]=$value
- done
-
- return 0
-}
-
-
-## Create directory
-function createDir
-{
- local path=$1
- local pathtype=$2
- local owner=$3
- local group=$4
- local permission=$5
-
- mkdir -p $path || LOG ERROR "Directory creation failure: $path"
- chown $owner:$group $path || LOG ERROR "chown failure: $path to $owner:$group"
- chmod $permission $path || LOG ERROR "chmod failure: $path to $permission"
-
- LOG DEBUG "Created directory: $path ($owner:$group, $permission)"
-
- return 0
-}
-
-
-## Set SMACK
-function setSmackToPath
-{
- local path=$1
- local smack_label=$2
- local smack_transmute=$3
- local smack_exec=$4
-
- chsmack -a $smack_label $path || LOG ERROR "SMACK labeling failure"
- if [[ "${smack_transmute}" == "1" ]]; then
- chsmack -t $path || LOG ERROR "SMACK transmute tagging failure"
- fi
- if [[ "${smack_exec}" == "1" ]]; then
- chsmack -e $path || LOG ERROR "SMACK exec tagging failure"
- fi
- LOG DEBUG "Set SMACK to ${path}: label=${smack_label}, transmute=${smack_transmute}, exec=${smack_exec}"
- return 0
-}
-
-
-## Create pkg dirs
-function createPkgDir
-{
- local pkgid=$1
- local username=$2
- local usergroup=$3
- local parentdir=$4
-
- LOG INFO "Create package directory ${pkgid} into ${parentdir}"
- for dirname in "${DIRS[@]}"; do
- getDirInfo $dirname $pkgid $username $usergroup
- local dirinfo=( "${return_getDirInfo[@]}" )
-
- # Get each values
- local path="${parentdir}/${dirinfo[0]}"
- local pathtype=${dirinfo[1]}
- local owner=${dirinfo[2]}
- local group=${dirinfo[3]}
- local permission=${dirinfo[4]}
- local smack_label=${dirinfo[5]}
- local smack_transmute=${dirinfo[6]}
- local smack_exec=${dirinfo[7]}
-
- createDir $path $pathtype $owner $group $permission
- setSmackToPath $path $smack_label $smack_transmute $smack_exec
-
- done
-}
-
-
-## Create pkg directories into given user's home directory
-function createPkgDirForUser
-{
- local pkgid=$1
- local username=$2
- local group=$3
-
- local parentdir=${CONFIG_UserAppDir/_USERID_/$username}
-
- LOG DEBUG "createPkgDirForUser: pkgid=${pkgid}, parentdir=${parentdir}"
- createPkgDir $pkgid $username $group $parentdir
-
- return 0
-}
-
-
-## Create pkg directory into the skeleton
-function createPkgDirToSkeleton
-{
- local pkgid=$1
-
- local owner=${CONFIG_SkelOwner}
- local group=${CONFIG_SkelGroup}
- local parentdir=${CONFIG_SkelAppDir}
-
- createPkgDir $pkgid $owner $group $parentdir
-
- return 0
-}
-
-### create dirs
-function createDirs
-{
- local pkgid=$1
-
- # Get user list
- getUserList
- # NOTE: This return value is an array, so array copy is used.
- local userList=( "${return_getUserList[@]}" )
-
- echo "userList: ${userList[@]}"
-
- for user in ${userList[@]}; do
- createPkgDirForUser $pkgid $user $CONFIG_UserGroup
- done
-
- createPkgDirToSkeleton $pkgid
-
- return 0
-}
-
-function deletePkgDirForUser
-{
- local pkgid=$1
- local username=$2
-
- local parentdir=${CONFIG_UserAppDir/_USERID_/$username}
- local appdir="${parentdir}/${pkgid}"
-
- rm -rf $appdir || LOG ERROR "Removing directory failure: $appdir"
- LOG INFO "${appdir} is removed"
-}
-
-function deletePkgDirFromSkeleton
-{
- local pkgid=$1
- local parentdir=${CONFIG_SkelAppDir}
- local appdir="${parentdir}/${pkgid}"
-
- rm -rf $appdir || LOG ERROR "Removing directory failure: $appdir"
- LOG INFO "${appdir} is removed"
-}
-
-
-### delete dirs
-function deleteDirs
-{
- local pkgid=$1
-
- getUserList
- local userList=( "${return_getUserList[@]}" )
-
- for user in "${userList[@]}"; do
- deletePkgDirForUser $pkgid $user
- done
- deletePkgDirFromSkeleton
-
- return 0
-}
-
-
-### Option processing
-_valid_option_list=( "--create" "--delete" "--pkgid=" "--verbose" "--allglobalpkgs" "--help" )
-for option in $@
-do
- found_option=0
- for _valid_option in ${_valid_option_list[@]}
- do
- if [ "$_valid_option" == "${option:0:${#_valid_option}}" ]; then
- if [ ${_valid_option:${#_valid_option}-1} == "=" ]; then
- eval "export OPTION_${option#--}"
- else
- eval "export OPTION_${option#--}=1"
- fi
- found_option=1
- break
- fi
- done
- if [[ $found_option == 0 ]]; then
- LOG ERROR "Invalid option: ${option}\nUsage: `basename $0` --help"
- fi
-done
-if test -n "${OPTION_help}"; then
- echo -e "`basename $0` ${VERSION}"
- echo -e " Creates or deletes package data directories of given global apps"
- echo -e " into all users' hone directories."
- echo -e "Usage:"
- echo -e " `basename $0` --create --pkgid=<pkgid> : Create package dirs"
- echo -e " `basename $0` --delete --pkgid=<pkgid> : Delete package dirs"
- echo -e " `basename $0` --create --allglobalpkgs : Create package dirs for all global packages"
- exit 0
-fi
-if [[ -n "${OPTION_create}" && -n "${OPTION_delete}" ]]; then
- LOG ERROR "--create and --delete cannot be used together"
-fi
-if [[ ! -n "${OPTION_pkgid}" && ! -n "${OPTION_allglobalpkgs}" ]]; then
- LOG ERROR "pkgid is not given"
-fi
-
-
-### main
-if [[ -n "${OPTION_create}" ]]; then
- if [[ -n "${OPTION_allglobalpkgs}" ]]; then
- ls /usr/share/packages/*.xml | while read xmlfile;
- do
- pkgid=`cat $xmlfile | grep -aPzo '<manifest..*?>' | grep -Pzo 'package="..*?"' | sed -e 's/package="\(..*\)"/\1/'`
- if [[ -n "${pkgid}" ]]; then
- createDirs ${pkgid}
- fi
- done
- else
- createDirs ${OPTION_pkgid}
- fi
-elif [[ -n "${OPTION_delete}" ]]; then
- deleteDirs ${OPTION_pkgid}
-fi
-
-
-echo "Done."
-exit 0
--- /dev/null
+# Target - sources
+SET(SRCS
+ pkgdir_tool.cc
+)
+
+# Target - definition
+ADD_EXECUTABLE(${TARGET_PKGDIR_TOOL} "pkgdir_tool.cc")
+# Target - includes
+TARGET_INCLUDE_DIRECTORIES(${TARGET_PKGDIR_TOOL} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
+# Target - deps
+APPLY_PKG_CONFIG(${TARGET_PKGDIR_TOOL} PUBLIC
+ PKGMGR_INSTALLER_DEPS
+)
+# Target - in-package deps
+TARGET_LINK_LIBRARIES(${TARGET_PKGDIR_TOOL} PUBLIC ${TARGET_LIBNAME_COMMON})
+
+# Install
+INSTALL(TARGETS ${TARGET_PKGDIR_TOOL} DESTINATION ${BINDIR})
+
+
--- /dev/null
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// 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 <pkgmgr-info.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <tzplatform_config.h>
+
+#include <cassert>
+#include <cstring>
+#include <exception>
+#include <regex>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "common/security_registration.h"
+#include "common/pkgmgr_registration.h"
+#include "common/utils/file_util.h"
+#include "common/utils/glist_range.h"
+#include "common/utils/logging.h"
+
+namespace bf = boost::filesystem;
+namespace bpo = boost::program_options;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+enum class Action {
+ CREATE,
+ COPY_OR_CREATE
+};
+
+const std::vector<std::pair<const char*, Action>> kEntries = {
+ {"/", Action::CREATE},
+ {"cache/", Action::CREATE},
+ {"data/", Action::COPY_OR_CREATE} // compatibility -> copy data/ dir for tpk
+};
+
+const char kSkelAppDir[] = "/etc/skel/apps_rw";
+const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
+
+bool ValidateTizenPackageId(const std::string& id) {
+ std::regex package_regex(kPackagePattern);
+ return std::regex_match(id, package_regex);
+}
+
+int PkgmgrListCallback(const pkgmgrinfo_pkginfo_h handle, void *user_data) {
+ auto pkgids = reinterpret_cast<std::vector<std::string>*>(user_data);
+ char* pkgid = nullptr;
+ if (pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid) != PMINFO_R_OK) {
+ return -1;
+ }
+ pkgids->emplace_back(pkgid);
+ return 0;
+}
+
+std::vector<std::string> GetAllGlobalApps() {
+ std::vector<std::string> pkgids;
+ if (pkgmgrinfo_pkginfo_get_usr_list(&PkgmgrListCallback,
+ &pkgids, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) != PMINFO_R_OK) {
+ LOG(ERROR) << "Failed to query global application list";
+ return {};
+ }
+ return pkgids;
+}
+
+bool SetPackageDirectorySmackRules(const bf::path& base_dir,
+ const std::string& pkgid,
+ 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;
+ }
+ for (const auto& appid : appids) {
+ if (!common_installer::RegisterSecurityContext(appid, pkgid, base_dir,
+ uid, privileges)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
+ gid_t gid) {
+ bs::error_code error;
+ bf::perms perms = bf::owner_read |
+ bf::owner_write |
+ bf::group_read;
+ if (bf::is_directory(subpath)) {
+ perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
+ }
+ bf::permissions(subpath, perms, error);
+ if (error) {
+ LOG(ERROR) << "Failed to set permissions for: " << subpath;
+ return false;
+ }
+ int ret = chown(subpath.c_str(), uid, gid);
+ if (ret != 0) {
+ LOG(ERROR) << "Failed to change owner of: " << subpath;
+ return false;
+ }
+ return true;
+}
+
+bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
+ uid_t uid, gid_t gid) {
+ bf::path base_dir = app_dir / pkgid;
+ if (bf::exists(base_dir)) {
+ LOG(DEBUG) << "Directory for user already exist: " << base_dir;
+ return true;
+ }
+
+ bs::error_code error;
+ for (auto& pair : kEntries) {
+ bf::path subpath = base_dir / pair.first;
+ switch (pair.second) {
+ case Action::COPY_OR_CREATE: {
+ bf::path global_directory =
+ bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid / pair.first;
+ if (bf::exists(global_directory)) {
+ if (!ci::CopyDir(global_directory, subpath)) {
+ LOG(ERROR) << "Failed to copy directory: " << global_directory;
+ return false;
+ }
+ break;
+ }
+ }
+ case Action::CREATE: {
+ bf::create_directories(subpath, error);
+ if (error) {
+ LOG(ERROR) << "Failed to create directory: " << subpath;
+ return false;
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+
+ if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
+ return false;
+
+ // for content
+ for (bf::recursive_directory_iterator iter(subpath);
+ iter != bf::recursive_directory_iterator(); ++iter) {
+ if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
+ return false;
+ }
+ }
+
+ if (!SetPackageDirectorySmackRules(base_dir, pkgid, uid))
+ return false;
+
+ return true;
+}
+
+bool CreatePerUserDirectories(const std::string& pkgid) {
+ for (bf::directory_iterator iter("/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 = getpwnam(user.c_str()); // NOLINT
+ if (!pwd) {
+ LOG(WARNING) << "Failed to get user for home directory: " << user;
+ continue;
+ }
+ LOG(DEBUG) << "Creating directories for uid: " << pwd->pw_uid << ", gid: "
+ << pwd->pw_gid << ", home: " << home_path;
+ tzplatform_set_user(pwd->pw_uid);
+ bf::path apps_rw(tzplatform_getenv(TZ_USER_APP));
+ tzplatform_reset_user();
+ if (!CreateDirectories(apps_rw, pkgid, pwd->pw_uid, pwd->pw_gid)) {
+ 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;
+ }
+ return true;
+}
+
+bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
+ bf::path base_dir = app_dir / pkgid;
+ bs::error_code error;
+ bf::remove_all(base_dir, error);
+ if (error) {
+ LOG(ERROR) << "Failed to delete directory: " << base_dir;
+ return false;
+ }
+ return true;
+}
+
+bool DeletePerUserDirectories(const std::string& pkgid) {
+ for (bf::directory_iterator iter("/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 = getpwnam(user.c_str()); // NOLINT
+ if (!pwd) {
+ LOG(WARNING) << "Failed to get user for home directory: " << user;
+ continue;
+ }
+ 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;
+}
+
+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;
+ }
+ return true;
+}
+
+bool PerformDirectoryCreation(const std::string& pkgid) {
+ if (!CreatePerUserDirectories(pkgid))
+ return false;
+ if (!CreateSkelDirectories(pkgid))
+ return false;
+ return true;
+}
+
+bool PerformDirectoryDeletion(const std::string& pkgid) {
+ if (!DeletePerUserDirectories(pkgid))
+ return false;
+ if (!DeleteSkelDirectories(pkgid))
+ return false;
+ return true;
+}
+
+void ExclusiveOptions(const bpo::variables_map& vm,
+ const std::string& opt1, const std::string& opt2) {
+ if ((vm.count(opt1) && vm.count(opt2)) ||
+ (!vm.count(opt1) && !vm.count(opt2))) {
+ throw std::logic_error(std::string("Exclusive options '") +
+ opt1 + "' and '" + opt2 + "'.");
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ bpo::options_description options("Allowed options");
+ options.add_options()
+ ("create", "create per user diretories for global package")
+ ("delete", "delete per user diretories for global package")
+ ("allglobalpkgs", "install directories for all global applications")
+ ("pkgid", bpo::value<std::string>(), "package ID");
+ bpo::variables_map opt_map;
+ try {
+ bpo::store(bpo::parse_command_line(argc, argv, options), opt_map);
+ ExclusiveOptions(opt_map, "create", "delete");
+ ExclusiveOptions(opt_map, "pkgid", "allglobalpkgs");
+ bpo::notify(opt_map);
+ } catch(const std::exception& error) {
+ LOG(ERROR) << error.what();
+ return -1;
+ }
+
+ bool create_mode = opt_map.count("create") != 0;
+ bool delete_mode = opt_map.count("delete") != 0;
+ bool allglobalpkgs = opt_map.count("allglobalpkgs") != 0;
+ std::string pkgid;
+ if (opt_map.count("pkgid")) {
+ pkgid = opt_map["pkgid"].as<std::string>();
+ if (!ValidateTizenPackageId(pkgid)) {
+ LOG(ERROR) << "Pkgid is invalid";
+ return -1;
+ }
+ }
+ std::vector<std::string> pkgids;
+ if (allglobalpkgs) {
+ pkgids = GetAllGlobalApps();
+ } else {
+ pkgids.push_back(pkgid);
+ }
+
+ assert(setuid(0) == 0);
+
+ if (create_mode) {
+ for (auto& package_id : pkgids) {
+ LOG(DEBUG) << "Running for package id: " << package_id;
+ if (!PerformDirectoryCreation(package_id))
+ return -1;
+ }
+ } else if (delete_mode) {
+ for (auto& package_id : pkgids) {
+ LOG(DEBUG) << "Running for package id: " << package_id;
+ if (!PerformDirectoryDeletion(package_id))
+ return -1;
+ }
+ }
+ return 0;
+}
bf::path binary_path = package_path / "bin" / appid;
bf::path data_path = package_path / "data";
bf::path shared_path = package_path / "shared";
+ bf::path cache_path = package_path / "cache";
ASSERT_TRUE(bf::exists(root_path));
ASSERT_TRUE(bf::exists(package_path));
ASSERT_TRUE(bf::exists(binary_path));
ASSERT_TRUE(bf::exists(data_path));
ASSERT_TRUE(bf::exists(shared_path));
+ ASSERT_TRUE(bf::exists(cache_path));
bf::path manifest_path =
bf::path(getUserManifestPath(getuid())) / (pkgid + ".xml");
ASSERT_TRUE(bf::exists(config_path));
bf::path private_tmp_path = package_path / "tmp";
- bf::path cache_path = package_path / "cache";
ASSERT_TRUE(bf::exists(private_tmp_path));
- ASSERT_TRUE(bf::exists(cache_path));
}
// backups should not exist
const char kSharedTrustedLocation[] = "shared/trusted";
const char kResWgtSubPath[] = "res/wgt";
const char kTemporaryData[] = "tmp";
-const char kCacheDir[] = "cache";
-
} // namespace
namespace wgt {
Status status = CreatePrivateTmpDir();
if (status != Status::OK)
return status;
- status = CreateCacheDir();
- if (status != Status::OK)
- return status;
+ if (!CacheDir())
+ return Status::ERROR;
int version = context_->manifest_data.get()->api_version[0] - '0';
if (version < 3) {
return Status::OK;
}
-common_installer::Step::Status
-StepWgtCopyStorageDirectories::CreateCacheDir() {
- bs::error_code error_code;
- bf::path cache_path = context_->pkg_path.get() / kCacheDir;
- bf::create_directory(cache_path, error_code);
- if (error_code) {
- LOG(ERROR) << "Failed to create cache directory for package";
- return Status::ERROR;
- }
- return Status::OK;
-}
-
} // namespace filesystem
} // namespace wgt
void UndoSharedDirectory();
void UndoDataDirectory();
Status CreatePrivateTmpDir();
- Status CreateCacheDir();
SCOPE_LOG_TAG(CopyWgtStorageDirectories)
};
const char kSharedLocation[] = "shared";
const char kResWgtSubPath[] = "res/wgt";
const char kTemporaryData[] = "tmp";
-const char kCacheDir[] = "cache";
} // namespace
if (!CreatePrivateTmpDir())
return Status::ERROR;
- if (!CreateCacheDir())
+ if (!CacheDir())
return Status::ERROR;
return Status::OK;
return true;
}
-bool StepWgtCreateStorageDirectories::CreateCacheDir() {
- bs::error_code error_code;
- bf::path cache_path = context_->pkg_path.get() / kCacheDir;
- bf::create_directory(cache_path, error_code);
- if (error_code) {
- LOG(ERROR) << "Failed to create cache directory for package";
- return false;
- }
- return true;
-}
-
} // namespace filesystem
} // namespace wgt
bool ShareDirFor3x();
bool CreatePrivateTmpDir();
- bool CreateCacheDir();
SCOPE_LOG_TAG(CreateWgtStorageDirectories)
};