1 // Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include "common/shared_dirs.h"
7 #include <manifest_parser/utils/logging.h>
8 #include <manifest_parser/utils/version_number.h>
10 #include <boost/filesystem/operations.hpp>
11 #include <boost/filesystem/path.hpp>
12 #include <boost/program_options.hpp>
13 #include <boost/system/error_code.hpp>
17 #include <vcore/Certificate.h>
18 #include <pkgmgr-info.h>
19 #include <sys/types.h>
22 #include <tzplatform_config.h>
23 #include <sys/xattr.h>
37 #include "common/paths.h"
38 #include "common/security_registration.h"
39 #include "common/pkgmgr_query.h"
40 #include "common/utils/base64.h"
41 #include "common/utils/file_util.h"
42 #include "common/utils/user_util.h"
43 #include "common/utils/glist_range.h"
45 namespace bf = boost::filesystem;
46 namespace bpo = boost::program_options;
47 namespace bs = boost::system;
48 namespace ci = common_installer;
52 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
53 const utils::VersionNumber ver30("3.0");
55 const std::vector<const char*> kEntries = {
60 const std::vector<std::string> kReadOnlyEntries = {
67 const char kSharedResDir[] = "shared/res";
68 const char kSharedCacheDir[] = "shared/cache";
69 const char kSharedDataDir[] = "shared/data";
70 const char kSharedTrustedDir[] = "shared/trusted";
71 const char kSkelAppDir[] = "skel/apps_rw";
72 const char kExternalStoragePrivilege[] =
73 "http://tizen.org/privilege/externalstorage.appdata";
74 const char kSystemShareGroupName[] = "system_share";
76 bool SetDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
78 bf::perms perms = bf::owner_read |
81 // symlink will be skipped
82 if (bf::is_symlink(symlink_status(subpath)))
85 // non directory will be skipped
87 if (bf::is_directory(subpath)) {
88 perms |= bf::owner_exe | bf::group_exe | bf::others_read | bf::others_exe;
89 if (subpath.filename() == "data" || subpath.filename() == "cache") {
90 perms |= bf::group_write | bf::set_gid_on_exe;
91 boost::optional<gid_t> system_share =
92 ci::GetGidByGroupName(kSystemShareGroupName);
97 result = common_installer::SetDirOwnershipAndPermissions(subpath, perms,
104 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
105 uid_t uid, gid_t gid, const bool set_permissions,
106 const std::vector<const char*>
107 additional_dirs = std::vector<const char*>()) {
108 bf::path base_dir = app_dir / pkgid;
109 if (bf::exists(base_dir)) {
110 LOG(DEBUG) << "Directory for user already exist: " << base_dir;
113 bs::error_code error;
114 bf::create_directories(base_dir, error);
116 LOG(ERROR) << "Failed to create directory: " << base_dir;
121 bs::error_code error;
122 std::vector<const char*> dirs(kEntries);
123 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
125 dirs.push_back(kSharedTrustedDir);
126 for (auto& entry : dirs) {
127 bf::path subpath = base_dir / entry;
128 bf::create_directories(subpath, error);
130 LOG(ERROR) << "Failed to create directory: " << subpath;
134 if (set_permissions) {
135 if (!SetDirectoryOwnerAndPermissions(subpath, uid, gid))
139 for (bf::recursive_directory_iterator iter(subpath);
140 iter != bf::recursive_directory_iterator(); ++iter) {
141 if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, gid))
150 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
151 std::string username = ci::GetUsernameByUid(user);
152 if (username.empty())
156 apps_rw = bf::path(apps_prefix.c_str()) / username / "apps_rw";
160 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
161 const std::string& apps_prefix, const bool set_permissions) {
162 boost::optional<gid_t> gid = ci::GetGidByUid(user);
166 std::string group_name = ci::GetGroupNameByGid(*gid);
167 if (group_name != tzplatform_getenv(TZ_SYS_USER_GROUP))
170 LOG(DEBUG) << "Creating directories for uid: " << user << ", gid: "
173 bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
174 if (apps_rw.empty()) {
175 LOG(DEBUG) << "Directory not exists: " << apps_rw;
179 if (!CreateDirectories(apps_rw, pkgid,
180 user, *gid, set_permissions)) {
186 bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
187 bf::path base_dir = app_dir / pkgid;
188 return ci::RemoveAll(base_dir);
192 bool CreateSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
193 std::vector<std::string> rofiles(kReadOnlyEntries);
194 for (bf::directory_iterator file(src_dir);
195 file != bf::directory_iterator();
197 if (bf::is_regular_file(file->path())) {
198 bf::path current(file->path());
199 bf::path file_name = current.filename();
200 LOG(DEBUG) << "file_name: " << file_name;
201 rofiles.push_back(file_name.string());
205 bs::error_code error;
206 for (auto& entry : rofiles) {
207 bf::path src_path = src_dir / entry;
208 bf::path dst_path = dst_dir / entry;
209 if (!bf::exists(src_path)) {
210 // check if symlink for .mmc/bin,lib,res, then do not skip
211 if (!bf::is_symlink(symlink_status(src_path))) {
212 LOG(INFO) << "src_path not exist : " << src_path;
216 if (bf::exists(dst_path) || bf::is_symlink(symlink_status(dst_path))) {
217 LOG(WARNING) << "dst_path exist, skip : " << dst_path;
220 bf::create_symlink(src_path, dst_path, error);
222 LOG(ERROR) << "Symlink creation failure src_path: " << src_path
223 << " dst_path: " << dst_path;
224 LOG(ERROR) << "error: " << error.message();
231 bool DeleteSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
232 bs::error_code error;
233 for (bf::directory_iterator file(dst_dir);
234 file != bf::directory_iterator();
236 bf::path current(file->path());
237 if (bf::is_symlink(symlink_status(current))) {
238 bf::path resolved_path = bf::read_symlink(current, error);
240 LOG(ERROR) << "Getting resolved path of symlink: " << current;
241 LOG(ERROR) << "resolved_path: " << resolved_path;
242 LOG(ERROR) << "error: " << error.message();
245 LOG(DEBUG) << "resolved_path: " << resolved_path;
246 bf::path parent = resolved_path.parent_path();
247 if (!parent.empty() && (parent == src_dir)) {
248 bf::remove(current, error);
250 LOG(ERROR) << "Symlink deletion failure for: " << current
251 << ", error: " << error.message();
254 LOG(DEBUG) << "removed: " << current;
256 LOG(WARNING) << "Parent is empty or not equal to src, parenet: ("
261 bf::path shared_res = dst_dir / kSharedResDir;
262 if (bf::is_symlink(symlink_status(shared_res))) {
263 bf::remove(shared_res, error);
265 LOG(ERROR) << "Symlink deletion failure for: " << shared_res
266 << ", error: " << error.message();
273 bool CreateStorageDirectories(const boost::filesystem::path& path,
274 const std::string& api_version,
275 bool trusted, bool shareddata,
276 const std::vector<const char*> additional_dirs) {
277 if (!bf::exists(path)) {
278 LOG(DEBUG) << "Creating directories in: " << path;
279 bs::error_code error;
280 bf::create_directories(path, error);
282 LOG(ERROR) << "Failed to create directory: " << path;
287 utils::VersionNumber api_ver(api_version);
288 std::vector<const char*> dirs(kEntries);
289 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
291 dirs.push_back(kSharedTrustedDir);
292 if (api_ver < ver30 || shareddata) {
293 dirs.push_back(kSharedDataDir);
295 bf::path shared_data_path = path / kSharedDataDir;
296 // remove shared/data (deprecated)
297 if (!ci::RemoveAll(shared_data_path))
300 for (auto& entry : dirs) {
301 bs::error_code error;
302 bf::path subpath = path / entry;
303 bf::create_directories(subpath, error);
304 if (error && !bf::exists(subpath)) {
305 LOG(ERROR) << "Failed to create directory: " << subpath;
310 bf::path shared_cache_path = path / kSharedCacheDir;
311 // remove shared/cache (do not support)
312 if (!ci::RemoveAll(shared_cache_path))
320 namespace common_installer {
322 std::string GetDirectoryPathForInternalStorage() {
323 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
324 if (internal_storage_prefix)
325 return std::string(internal_storage_prefix);
326 return tzplatform_getenv(TZ_SYS_HOME);
329 std::string GetDirectoryPathForExternalStorage() {
330 return GetExternalCardPath().string();
333 bool PerformExternalDirectoryCreationForUser(uid_t user,
334 const std::string& pkgid) {
335 bf::path storage_path = GetExternalCardPath();
337 const bool set_permissions = false;
338 if (!bf::exists(storage_path)) {
339 LOG(WARNING) << "External storage (SD Card) is not mounted.";
343 bf::path storage_apps_path = storage_path / "apps";
344 if (!bf::exists(storage_apps_path)) {
345 bs::error_code error;
346 bf::create_directories(storage_apps_path, error);
348 LOG(ERROR) << "Failed to create directory: "
349 << storage_apps_path.c_str();
354 CreateUserDirectories(user, pkgid,
355 storage_apps_path.c_str(), set_permissions);
359 bool PerformExternalDirectoryDeletionForUser(uid_t user,
360 const std::string& pkgid) {
361 bf::path storage_path = GetExternalCardPath();
362 if (!bf::exists(storage_path)) {
363 LOG(WARNING) << "External storage (SD Card) is not mounted. "
364 << "It will be ignored";
368 bf::path storage_apps_path = bf::path(storage_path) / "apps";
369 return DeleteDirectories(
370 GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
373 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
374 UserList list = ci::GetUserList();
375 for (auto l : list) {
376 if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
378 LOG(WARNING) << "Could not create external storage directories for user: "
384 bool PerformExternalDirectoryCreationForAllPkgs() {
385 UserList list = ci::GetUserList();
386 for (auto l : list) {
387 uid_t uid = std::get<0>(l);
388 pkgmgrinfo_pkginfo_filter_h filter_handle = nullptr;
389 int ret = pkgmgrinfo_pkginfo_filter_create(&filter_handle);
390 if (ret != PMINFO_R_OK)
392 ret = pkgmgrinfo_pkginfo_filter_add_string(filter_handle,
393 PMINFO_PKGINFO_PROP_PACKAGE_PRIVILEGE, kExternalStoragePrivilege);
394 if (ret != PMINFO_R_OK) {
395 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
399 ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(filter_handle,
400 [](const pkgmgrinfo_pkginfo_h handle, void* user_data) -> int {
402 static_cast<uid_t>(reinterpret_cast<uintptr_t>(user_data));
403 char* pkgid = nullptr;
405 int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
406 if (ret != PMINFO_R_OK)
408 if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
413 reinterpret_cast<void*>(static_cast<uintptr_t>(uid)));
414 if (ret != PMINFO_R_OK) {
415 LOG(DEBUG) << "Failed to create external directoy";
416 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
419 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
425 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
426 UserList list = ci::GetUserList();
427 for (auto l : list) {
428 uid_t uid = std::get<0>(l);
429 ci::PkgQueryInterface pkg_query(pkgid, uid);
430 LOG(DEBUG) << "Deleting directories for user: " << uid;
431 if (pkg_query.IsPackageInstalled()) {
432 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
433 << " still exists. Skipping";
437 if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
438 LOG(WARNING) << "Could not delete external storage directories for user: "
444 bool CreateStorageDirectories(const boost::filesystem::path& path,
445 const std::string& api_version,
446 bool trusted, bool shareddata) {
447 return ::CreateStorageDirectories(path, api_version, trusted, shareddata,
448 std::vector<const char*>());
451 bool DeleteStorageDirectories(const boost::filesystem::path& path) {
452 std::vector<const char*> dirs;
453 dirs.assign(kEntries.begin() + 1, kEntries.end());
454 dirs.push_back(kSharedTrustedDir);
455 dirs.push_back(kSharedDataDir);
456 dirs.push_back(kSharedCacheDir);
457 for (auto& entry : dirs) {
458 bf::path subpath = path / entry;
459 if (!ci::RemoveAll(subpath))
465 bool CreateSkelDirectories(const std::string& pkgid,
466 const std::string& api_version,
467 bool trusted, bool shareddata, bool is_readonly,
468 const std::vector<const char*> additional_dirs) {
469 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
470 bf::path(kSkelAppDir) / pkgid;
471 LOG(DEBUG) << "Creating directories in: " << path;
473 if (!::CreateStorageDirectories(path, api_version, trusted, shareddata,
475 LOG(ERROR) << "Failed to create storage directory for path: " << path;
479 std::string error_message;
480 if (!RegisterSecurityContextForPath(pkgid, path, kGlobalUserUid,
481 is_readonly, &error_message)) {
482 LOG(ERROR) << "Failed to register security context for path: " << path
483 << ", error_message: " << error_message;
489 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
490 result = CreateSymlinkFiles(src_dir, path);
496 bool UpdateSkelDirectories(const std::string& pkgid,
497 bool is_remove_shareddata) {
498 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
499 bf::path(kSkelAppDir) / pkgid;
500 bf::path shared_data_path = path / kSharedDataDir;
501 LOG(DEBUG) << ((is_remove_shareddata) ? "Removing" : "Creating")
502 << " directory : " << shared_data_path;
504 if (!is_remove_shareddata) {
505 if (!CreateDir(shared_data_path))
508 std::string error_message;
509 if (!RegisterSecurityContextForPath(pkgid, path, kGlobalUserUid,
510 false, &error_message)) {
511 LOG(ERROR) << "Failed to register security context for path: " << path
512 << ", error_message: " << error_message;
516 return ci::RemoveAll(shared_data_path);
521 bool DeleteSkelDirectories(const std::string& pkgid) {
522 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
523 bf::path(kSkelAppDir);
524 return DeleteDirectories(path, pkgid);
528 bool DeleteUserDirectories(const std::string& pkgid) {
529 UserList list = ci::GetUserList();
530 for (auto l : list) {
531 uid_t uid = std::get<0>(l);
532 ci::PkgQueryInterface pkg_query(pkgid, uid);
533 if (pkg_query.IsPackageInstalled()) {
534 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
538 LOG(DEBUG) << "Deleting directories of " << pkgid
539 << ", for uid: " << std::get<0>(l);
540 bf::path apps_rw(std::get<2>(l) / "apps_rw");
541 if (!DeleteDirectories(apps_rw, pkgid)) {
548 bool DeleteUserExternalDirectories(const std::string& pkgid) {
549 UserList list = ci::GetUserList();
550 for (auto l : list) {
551 uid_t uid = std::get<0>(l);
552 ci::PkgQueryInterface pkg_query(pkgid, uid);
553 if (pkg_query.IsPackageInstalled()) {
554 LOG(INFO) << pkgid << " is installed for user " << uid;
558 LOG(DEBUG) << "Deleting external directories of " << pkgid
559 << ", for uid: " << uid;
560 bf::path apps_rw(std::get<2>(l) / "apps_rw");
561 if (!DeleteDirectories(apps_rw, pkgid)) {
569 bool CopyUserDirectories(const std::string& pkgid) {
570 UserList list = ci::GetUserList();
571 for (auto l : list) {
572 uid_t uid = std::get<0>(l);
573 LOG(DEBUG) << "Copying directories for uid: " << uid;
574 bf::path apps_rw(std::get<2>(l) / "apps_rw");
575 bf::path src = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
576 bf::path(kSkelAppDir) / pkgid;
577 bf::path dst = apps_rw / pkgid;
578 if (!ci::CopyDir(src, dst, FSFlag::FS_NONE, true))
580 gid_t gid = std::get<1>(l);
581 if (!SetDirectoryOwnerAndPermissions(dst, uid, gid))
583 for (bf::recursive_directory_iterator iter(dst);
584 iter != bf::recursive_directory_iterator(); ++iter) {
585 if (!SetDirectoryOwnerAndPermissions(iter->path(),
589 std::string error_message;
590 if (!RegisterSecurityContextForPath(pkgid, dst, uid,
591 false, &error_message)) {
592 LOG(ERROR) << "Failed to register security context for path: " << dst
593 << ", error_message: " << error_message;
600 bool UpdateUserDirectory(const std::string& pkgid, bool is_remove_shareddata) {
601 UserList list = ci::GetUserList();
602 for (auto l : list) {
603 bf::path apps_rw(std::get<2>(l) / "apps_rw");
604 bf::path root_dst = apps_rw / pkgid;
605 bf::path shareddir_dst = root_dst / kSharedDataDir;
606 uid_t uid = std::get<0>(l);
607 LOG(DEBUG) << ((is_remove_shareddata) ? "Deleting" : "Adding")
608 << " shareddata directory for uid: " << uid;
610 if (!is_remove_shareddata) {
611 bs::error_code error;
612 bf::create_directories(shareddir_dst, error);
613 if (error && !bf::exists(shareddir_dst)) {
614 LOG(ERROR) << "Failed to create directory: " << shareddir_dst;
618 gid_t gid = std::get<1>(l);
619 if (!SetDirectoryOwnerAndPermissions(root_dst, uid, gid))
621 for (bf::recursive_directory_iterator iter(root_dst);
622 iter != bf::recursive_directory_iterator(); ++iter) {
623 if (!SetDirectoryOwnerAndPermissions(iter->path(),
628 std::string error_message;
629 if (!RegisterSecurityContextForPath(pkgid, root_dst, uid,
630 false, &error_message)) {
631 LOG(ERROR) << "Failed to register security context for path: "
632 << root_dst << ", error_message: " << error_message;
636 return ci::RemoveAll(shareddir_dst);
642 bool CreateGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
643 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
644 if (!bf::exists(src_dir)) {
645 LOG(ERROR) << "src_dir not exists";
650 UserList list = ci::GetUserList();
651 for (auto l : list) {
652 uid_t uid = std::get<0>(l);
653 LOG(DEBUG) << "Creating symlinks for uid: " << uid;
654 // check installed user private app.
655 ci::PkgQueryInterface pkg_query(pkgid, uid);
656 if (pkg_query.IsPackageInstalled())
658 bf::path apps_rw(std::get<2>(l) / "apps_rw");
659 bf::path dst_dir = apps_rw / pkgid;
660 if (!bf::exists(dst_dir)) {
661 LOG(WARNING) << "dst_dir not exists";
664 result = CreateSymlinkFiles(src_dir, dst_dir);
669 bool CreateGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
670 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
671 if (!bf::exists(src_dir)) {
672 LOG(WARNING) << "src_dir(" << src_dir << ") not exists";
676 tzplatform_set_user(uid);
677 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
678 tzplatform_reset_user();
679 if (!bf::exists(dst_dir)) {
680 LOG(WARNING) << "dst_dir not exists";
683 bool result = CreateSymlinkFiles(src_dir, dst_dir);
688 bool DeleteGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
689 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
690 if (!bf::exists(src_dir)) {
691 LOG(WARNING) << "src_dir(" << src_dir << ") not exists";
696 UserList list = ci::GetUserList();
697 for (auto l : list) {
698 uid_t uid = std::get<0>(l);
699 LOG(DEBUG) << "Deleting symlinks for uid: " << uid;
700 // check installed user private app.
701 ci::PkgQueryInterface pkg_query(pkgid, uid);
702 if (pkg_query.IsPackageInstalled())
704 bf::path apps_rw(std::get<2>(l) / "apps_rw");
705 bf::path dst_dir = apps_rw / pkgid;
706 if (!bf::exists(dst_dir)) {
707 LOG(WARNING) << "dst_dir not exists";
710 result = DeleteSymlinkFiles(src_dir, dst_dir);
715 bool DeleteGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
716 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
717 if (!bf::exists(src_dir)) {
718 LOG(ERROR) << "src_dir not exists";
722 tzplatform_set_user(uid);
723 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
724 tzplatform_reset_user();
725 if (!bf::exists(dst_dir)) {
726 LOG(WARNING) << "dst_dir not exists";
729 bool result = DeleteSymlinkFiles(src_dir, dst_dir);
733 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& path, uid_t uid) {
734 boost::optional<gid_t> gid = ci::GetGidByUid(uid);
738 bf::owner_read | bf::owner_write | bf::group_read | bf::others_read;
740 perms644 | bf::owner_exe | bf::group_exe | bf::others_exe;
741 for (bf::recursive_directory_iterator iter(path);
742 iter != bf::recursive_directory_iterator(); ++iter) {
743 if (bf::is_symlink(symlink_status(iter->path())) ||
744 (bf::is_directory(iter->path()) &&
745 (iter->path().filename() == ".mmc" ||
746 iter->path().filename() == ".pkg" ||
747 iter->path().filename() == "tep"))) {
748 // skip symlink or path which is related to
749 // mount or directory installer creates
751 } else if (bf::is_directory(iter->path())) {
753 if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, *gid))
755 } else if (iter.level() == 1 &&
756 iter->path().parent_path().filename() == "bin") {
758 if (!SetDirOwnershipAndPermissions(iter->path(), perms755, uid, *gid))
762 if (!SetDirOwnershipAndPermissions(iter->path(), perms644, uid, *gid))
769 } // namespace common_installer