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");
54 const char kDisableLegacySharedDataDirSupport[] =
55 "/usr/share/app-installers/disable_legacy_shareddata_support";
57 const std::vector<const char*> kEntries = {
62 const std::vector<std::string> kReadOnlyEntries = {
69 const char kSharedResDir[] = "shared/res";
70 const char kSharedCacheDir[] = "shared/cache";
71 const char kSharedDataDir[] = "shared/data";
72 const char kSharedTrustedDir[] = "shared/trusted";
73 const char kSkelAppDir[] = "skel/apps_rw";
74 const char kExternalStoragePrivilege[] =
75 "http://tizen.org/privilege/externalstorage.appdata";
76 const char kSystemShareGroupName[] = "system_share";
78 bool SetDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
80 // symlink and non directory will be skipped
81 if (bf::is_symlink(symlink_status(subpath)) || !bf::is_directory(subpath))
84 bf::perms perms = bf::all_all ^ bf::group_write ^ bf::others_write;
85 if (subpath.filename() == "data" || subpath.filename() == "cache") {
86 perms |= bf::group_write | bf::set_gid_on_exe;
87 boost::optional<gid_t> system_share =
88 ci::GetGidByGroupName(kSystemShareGroupName);
93 return common_installer::SetDirOwnershipAndPermissions(subpath, perms,
97 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
98 uid_t uid, gid_t gid, const bool set_permissions,
99 const std::vector<const char*>
100 additional_dirs = std::vector<const char*>()) {
101 bf::path base_dir = app_dir / pkgid;
102 if (bf::exists(base_dir)) {
103 LOG(DEBUG) << "Directory for user already exist: " << base_dir;
106 bs::error_code error;
107 bf::create_directories(base_dir, error);
109 LOG(ERROR) << "Failed to create directory: " << base_dir;
114 bs::error_code error;
115 std::vector<const char*> dirs(kEntries);
116 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
118 dirs.push_back(kSharedTrustedDir);
119 for (auto& entry : dirs) {
120 bf::path subpath = base_dir / entry;
121 bf::create_directories(subpath, error);
123 LOG(ERROR) << "Failed to create directory: " << subpath;
127 if (set_permissions) {
128 if (!SetDirectoryOwnerAndPermissions(subpath, uid, gid))
132 for (bf::recursive_directory_iterator iter(subpath);
133 iter != bf::recursive_directory_iterator(); ++iter) {
134 if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, gid))
143 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
144 std::string username = ci::GetUsernameByUid(user);
145 if (username.empty())
149 apps_rw = bf::path(apps_prefix.c_str()) / username / "apps_rw";
153 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
154 const std::string& apps_prefix, const bool set_permissions) {
155 boost::optional<gid_t> gid = ci::GetGidByUid(user);
159 std::string group_name = ci::GetGroupNameByGid(*gid);
160 if (group_name != tzplatform_getenv(TZ_SYS_USER_GROUP))
163 LOG(DEBUG) << "Creating directories for uid: " << user << ", gid: "
166 bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
167 if (apps_rw.empty()) {
168 LOG(DEBUG) << "Directory not exists: " << apps_rw;
172 if (!CreateDirectories(apps_rw, pkgid,
173 user, *gid, set_permissions)) {
179 bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
180 bf::path base_dir = app_dir / pkgid;
181 return ci::RemoveAll(base_dir);
185 bool CreateSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
186 std::vector<std::string> rofiles(kReadOnlyEntries);
187 for (bf::directory_iterator file(src_dir);
188 file != bf::directory_iterator();
190 if (bf::is_regular_file(file->path())) {
191 bf::path current(file->path());
192 bf::path file_name = current.filename();
193 LOG(DEBUG) << "file_name: " << file_name;
194 rofiles.push_back(file_name.string());
198 bs::error_code error;
199 for (auto& entry : rofiles) {
200 bf::path src_path = src_dir / entry;
201 bf::path dst_path = dst_dir / entry;
202 if (!bf::exists(src_path)) {
203 // check if symlink for .mmc/bin,lib,res, then do not skip
204 if (!bf::is_symlink(symlink_status(src_path))) {
205 LOG(INFO) << "src_path not exist : " << src_path;
209 if (bf::exists(dst_path) || bf::is_symlink(symlink_status(dst_path))) {
210 LOG(WARNING) << "dst_path exist, skip : " << dst_path;
213 bf::create_symlink(src_path, dst_path, error);
215 LOG(ERROR) << "Symlink creation failure src_path: " << src_path
216 << " dst_path: " << dst_path;
217 LOG(ERROR) << "error: " << error.message();
224 bool DeleteSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
225 bs::error_code error;
226 for (bf::directory_iterator file(dst_dir);
227 file != bf::directory_iterator();
229 bf::path current(file->path());
230 if (bf::is_symlink(symlink_status(current))) {
231 bf::path resolved_path = bf::read_symlink(current, error);
233 LOG(ERROR) << "Getting resolved path of symlink: " << current;
234 LOG(ERROR) << "resolved_path: " << resolved_path;
235 LOG(ERROR) << "error: " << error.message();
238 LOG(DEBUG) << "resolved_path: " << resolved_path;
239 bf::path parent = resolved_path.parent_path();
240 if (!parent.empty() && (parent == src_dir)) {
241 bf::remove(current, error);
243 LOG(ERROR) << "Symlink deletion failure for: " << current
244 << ", error: " << error.message();
247 LOG(DEBUG) << "removed: " << current;
249 LOG(WARNING) << "Parent is empty or not equal to src, parenet: ("
254 bf::path shared_res = dst_dir / kSharedResDir;
255 if (bf::is_symlink(symlink_status(shared_res))) {
256 bf::remove(shared_res, error);
258 LOG(ERROR) << "Symlink deletion failure for: " << shared_res
259 << ", error: " << error.message();
266 bool CreateStorageDirectories(const boost::filesystem::path& path,
267 bool trusted, bool shareddata,
268 const std::vector<const char*> additional_dirs) {
269 if (!bf::exists(path)) {
270 LOG(DEBUG) << "Creating directories in: " << path;
271 bs::error_code error;
272 bf::create_directories(path, error);
274 LOG(ERROR) << "Failed to create directory: " << path;
279 std::vector<const char*> dirs(kEntries);
280 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
282 dirs.push_back(kSharedTrustedDir);
284 dirs.push_back(kSharedDataDir);
286 bf::path shared_data_path = path / kSharedDataDir;
287 // remove shared/data (deprecated)
288 if (!ci::RemoveAll(shared_data_path))
291 for (auto& entry : dirs) {
292 bs::error_code error;
293 bf::path subpath = path / entry;
294 bf::create_directories(subpath, error);
295 if (error && !bf::exists(subpath)) {
296 LOG(ERROR) << "Failed to create directory: " << subpath;
301 bf::path shared_cache_path = path / kSharedCacheDir;
302 // remove shared/cache (do not support)
303 if (!ci::RemoveAll(shared_cache_path))
311 namespace common_installer {
313 std::string GetDirectoryPathForInternalStorage() {
314 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
315 if (internal_storage_prefix)
316 return std::string(internal_storage_prefix);
317 return tzplatform_getenv(TZ_SYS_HOME);
320 std::string GetDirectoryPathForExternalStorage() {
321 return GetExternalCardPath().string();
324 bool PerformExternalDirectoryCreationForUser(uid_t user,
325 const std::string& pkgid) {
326 bf::path storage_path = GetExternalCardPath();
328 const bool set_permissions = false;
329 if (!bf::exists(storage_path)) {
330 LOG(WARNING) << "External storage (SD Card) is not mounted.";
334 bf::path storage_apps_path = storage_path / "apps";
335 if (!bf::exists(storage_apps_path)) {
336 bs::error_code error;
337 bf::create_directories(storage_apps_path, error);
339 LOG(ERROR) << "Failed to create directory: "
340 << storage_apps_path.c_str();
345 CreateUserDirectories(user, pkgid,
346 storage_apps_path.c_str(), set_permissions);
350 bool PerformExternalDirectoryDeletionForUser(uid_t user,
351 const std::string& pkgid) {
352 bf::path storage_path = GetExternalCardPath();
353 if (!bf::exists(storage_path)) {
354 LOG(WARNING) << "External storage (SD Card) is not mounted. "
355 << "It will be ignored";
359 bf::path storage_apps_path = bf::path(storage_path) / "apps";
360 return DeleteDirectories(
361 GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
364 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
365 UserList list = ci::GetUserList();
366 for (auto l : list) {
367 if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
369 LOG(WARNING) << "Could not create external storage directories for user: "
375 bool PerformExternalDirectoryCreationForAllPkgs() {
376 UserList list = ci::GetUserList();
377 for (auto l : list) {
378 uid_t uid = std::get<0>(l);
379 pkgmgrinfo_pkginfo_filter_h filter_handle = nullptr;
380 int ret = pkgmgrinfo_pkginfo_filter_create(&filter_handle);
381 if (ret != PMINFO_R_OK)
383 ret = pkgmgrinfo_pkginfo_filter_add_string(filter_handle,
384 PMINFO_PKGINFO_PROP_PACKAGE_PRIVILEGE, kExternalStoragePrivilege);
385 if (ret != PMINFO_R_OK) {
386 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
390 ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(filter_handle,
391 [](const pkgmgrinfo_pkginfo_h handle, void* user_data) -> int {
393 static_cast<uid_t>(reinterpret_cast<uintptr_t>(user_data));
394 char* pkgid = nullptr;
396 int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
397 if (ret != PMINFO_R_OK)
399 if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
404 reinterpret_cast<void*>(static_cast<uintptr_t>(uid)));
405 if (ret != PMINFO_R_OK) {
406 LOG(DEBUG) << "Failed to create external directoy";
407 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
410 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
416 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
417 UserList list = ci::GetUserList();
418 for (auto l : list) {
419 uid_t uid = std::get<0>(l);
420 ci::PkgQueryInterface pkg_query(pkgid, uid);
421 LOG(DEBUG) << "Deleting directories for user: " << uid;
422 if (pkg_query.IsPackageInstalled()) {
423 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
424 << " still exists. Skipping";
428 if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
429 LOG(WARNING) << "Could not delete external storage directories for user: "
435 bool CreateStorageDirectories(const boost::filesystem::path& path,
436 const std::string& pkgid, uid_t uid,
437 bool trusted, bool shareddata) {
438 if (!::CreateStorageDirectories(path, trusted, shareddata,
439 std::vector<const char*>())) {
440 LOG(ERROR) << "Failed to create storage directory for path: " << path;
444 std::string error_message;
445 if (!RegisterSecurityContextForPath(pkgid, path, uid, false,
447 LOG(ERROR) << "Failed to register security context for path: " << path
448 << ", error_message: " << error_message;
455 bool DeleteStorageDirectories(const boost::filesystem::path& path) {
456 std::vector<const char*> dirs;
457 dirs.assign(kEntries.begin() + 1, kEntries.end());
458 dirs.push_back(kSharedTrustedDir);
459 dirs.push_back(kSharedDataDir);
460 dirs.push_back(kSharedCacheDir);
461 for (auto& entry : dirs) {
462 bf::path subpath = path / entry;
463 if (!ci::RemoveAll(subpath))
469 bool CreateSkelDirectories(const std::string& pkgid,
470 bool trusted, bool shareddata, bool is_readonly,
471 const std::vector<const char*> additional_dirs) {
472 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
473 bf::path(kSkelAppDir) / pkgid;
474 LOG(DEBUG) << "Creating directories in: " << path;
476 if (!::CreateStorageDirectories(path, trusted, shareddata,
478 LOG(ERROR) << "Failed to create storage directory for path: " << path;
482 std::string error_message;
483 if (!RegisterSecurityContextForPath(pkgid, path, kGlobalUserUid,
484 is_readonly, &error_message)) {
485 LOG(ERROR) << "Failed to register security context for path: " << path
486 << ", error_message: " << error_message;
492 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
493 result = CreateSymlinkFiles(src_dir, path);
499 bool UpdateSkelDirectories(const std::string& pkgid,
500 bool is_remove_shareddata) {
501 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
502 bf::path(kSkelAppDir) / pkgid;
503 bf::path shared_data_path = path / kSharedDataDir;
504 LOG(DEBUG) << ((is_remove_shareddata) ? "Removing" : "Creating")
505 << " directory : " << shared_data_path;
507 if (!is_remove_shareddata) {
508 if (!CreateDir(shared_data_path))
511 std::string error_message;
512 if (!RegisterSecurityContextForPath(pkgid, path, kGlobalUserUid,
513 false, &error_message)) {
514 LOG(ERROR) << "Failed to register security context for path: " << path
515 << ", error_message: " << error_message;
519 return ci::RemoveAll(shared_data_path);
524 bool DeleteSkelDirectories(const std::string& pkgid) {
525 bf::path path = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
526 bf::path(kSkelAppDir);
527 return DeleteDirectories(path, pkgid);
531 bool DeleteUserDirectories(const std::string& pkgid) {
532 UserList list = ci::GetUserList();
533 for (auto l : list) {
534 uid_t uid = std::get<0>(l);
535 ci::PkgQueryInterface pkg_query(pkgid, uid);
536 if (pkg_query.IsPackageInstalled()) {
537 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
541 LOG(DEBUG) << "Deleting directories of " << pkgid
542 << ", for uid: " << std::get<0>(l);
543 bf::path apps_rw(std::get<2>(l) / "apps_rw");
544 if (!DeleteDirectories(apps_rw, pkgid)) {
551 bool DeleteUserExternalDirectories(const std::string& pkgid) {
552 UserList list = ci::GetUserList();
553 for (auto l : list) {
554 uid_t uid = std::get<0>(l);
555 ci::PkgQueryInterface pkg_query(pkgid, uid);
556 if (pkg_query.IsPackageInstalled()) {
557 LOG(INFO) << pkgid << " is installed for user " << uid;
561 LOG(DEBUG) << "Deleting external directories of " << pkgid
562 << ", for uid: " << uid;
563 bf::path apps_rw(std::get<2>(l) / "apps_rw");
564 if (!DeleteDirectories(apps_rw, pkgid)) {
571 bool CopyUserDirectories(const std::string& pkgid) {
572 UserList list = ci::GetUserList();
573 for (auto l : list) {
574 uid_t uid = std::get<0>(l);
575 LOG(DEBUG) << "Copying directories for uid: " << uid;
576 bf::path apps_rw(std::get<2>(l) / "apps_rw");
577 bf::path src = bf::path(tzplatform_getenv(TZ_SYS_ETC)) /
578 bf::path(kSkelAppDir) / pkgid;
579 bf::path dst = apps_rw / pkgid;
580 if (!ci::CopyDir(src, dst, FSFlag::FS_NONE, true))
582 gid_t gid = std::get<1>(l);
583 if (!SetDirectoryOwnerAndPermissions(dst, uid, gid))
585 for (bf::recursive_directory_iterator iter(dst);
586 iter != bf::recursive_directory_iterator(); ++iter) {
587 if (!SetDirectoryOwnerAndPermissions(iter->path(),
591 std::string error_message;
592 if (!RegisterSecurityContextForPath(pkgid, dst, uid,
593 false, &error_message)) {
594 LOG(ERROR) << "Failed to register security context for path: " << dst
595 << ", error_message: " << error_message;
602 bool UpdateUserDirectory(const std::string& pkgid, bool is_remove_shareddata) {
603 UserList list = ci::GetUserList();
604 for (auto l : list) {
605 bf::path apps_rw(std::get<2>(l) / "apps_rw");
606 bf::path root_dst = apps_rw / pkgid;
607 bf::path shareddir_dst = root_dst / kSharedDataDir;
608 uid_t uid = std::get<0>(l);
609 LOG(DEBUG) << ((is_remove_shareddata) ? "Deleting" : "Adding")
610 << " shareddata directory for uid: " << uid;
612 if (!is_remove_shareddata) {
613 bs::error_code error;
614 bf::create_directories(shareddir_dst, error);
615 if (error && !bf::exists(shareddir_dst)) {
616 LOG(ERROR) << "Failed to create directory: " << shareddir_dst;
620 gid_t gid = std::get<1>(l);
621 if (!SetDirectoryOwnerAndPermissions(root_dst, uid, gid))
623 for (bf::recursive_directory_iterator iter(root_dst);
624 iter != bf::recursive_directory_iterator(); ++iter) {
625 if (!SetDirectoryOwnerAndPermissions(iter->path(),
630 std::string error_message;
631 if (!RegisterSecurityContextForPath(pkgid, root_dst, uid,
632 false, &error_message)) {
633 LOG(ERROR) << "Failed to register security context for path: "
634 << root_dst << ", error_message: " << error_message;
638 return ci::RemoveAll(shareddir_dst);
644 bool CreateGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
645 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
646 if (!bf::exists(src_dir)) {
647 LOG(ERROR) << "src_dir not exists";
652 UserList list = ci::GetUserList();
653 for (auto l : list) {
654 uid_t uid = std::get<0>(l);
655 LOG(DEBUG) << "Creating symlinks for uid: " << uid;
656 // check installed user private app.
657 ci::PkgQueryInterface pkg_query(pkgid, uid);
658 if (pkg_query.IsPackageInstalled())
660 bf::path apps_rw(std::get<2>(l) / "apps_rw");
661 bf::path dst_dir = apps_rw / pkgid;
662 if (!bf::exists(dst_dir)) {
663 LOG(WARNING) << "dst_dir not exists";
666 result = CreateSymlinkFiles(src_dir, dst_dir);
671 bool CreateGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
672 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
673 if (!bf::exists(src_dir)) {
674 LOG(WARNING) << "src_dir(" << src_dir << ") not exists";
678 tzplatform_set_user(uid);
679 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
680 tzplatform_reset_user();
681 if (!bf::exists(dst_dir)) {
682 LOG(WARNING) << "dst_dir not exists";
685 bool result = CreateSymlinkFiles(src_dir, dst_dir);
690 bool DeleteGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
691 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
692 if (!bf::exists(src_dir)) {
693 LOG(WARNING) << "src_dir(" << src_dir << ") not exists";
698 UserList list = ci::GetUserList();
699 for (auto l : list) {
700 uid_t uid = std::get<0>(l);
701 LOG(DEBUG) << "Deleting symlinks for uid: " << uid;
702 // check installed user private app.
703 ci::PkgQueryInterface pkg_query(pkgid, uid);
704 if (pkg_query.IsPackageInstalled())
706 bf::path apps_rw(std::get<2>(l) / "apps_rw");
707 bf::path dst_dir = apps_rw / pkgid;
708 if (!bf::exists(dst_dir)) {
709 LOG(WARNING) << "dst_dir not exists";
712 result = DeleteSymlinkFiles(src_dir, dst_dir);
717 bool DeleteGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
718 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
719 if (!bf::exists(src_dir)) {
720 LOG(ERROR) << "src_dir not exists";
724 tzplatform_set_user(uid);
725 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
726 tzplatform_reset_user();
727 if (!bf::exists(dst_dir)) {
728 LOG(WARNING) << "dst_dir not exists";
731 bool result = DeleteSymlinkFiles(src_dir, dst_dir);
735 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& path, uid_t uid) {
736 boost::optional<gid_t> gid = ci::GetGidByUid(uid);
740 bf::owner_read | bf::owner_write | bf::group_read | bf::others_read;
742 perms644 | bf::owner_exe | bf::group_exe | bf::others_exe;
743 for (bf::recursive_directory_iterator iter(path);
744 iter != bf::recursive_directory_iterator(); ++iter) {
745 if (bf::is_symlink(symlink_status(iter->path())) ||
746 (bf::is_directory(iter->path()) &&
747 (iter->path().filename() == ".mmc" ||
748 iter->path().filename() == ".pkg" ||
749 iter->path().filename() == "tep"))) {
750 // skip symlink or path which is related to
751 // mount or directory installer creates
753 } else if (bf::is_directory(iter->path())) {
755 if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, *gid))
757 } else if (iter.level() == 1 &&
758 iter->path().parent_path().filename() == "bin") {
760 if (!SetDirOwnershipAndPermissions(iter->path(), perms755, uid, *gid))
764 if (!SetDirOwnershipAndPermissions(iter->path(), perms644, uid, *gid))
771 bool ShouldSupportLegacySharedDataDir(const std::string& api_version) {
772 if (bf::exists(kDisableLegacySharedDataDirSupport))
774 utils::VersionNumber api_ver(api_version);
781 } // namespace common_installer