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>
38 #include "common/paths.h"
39 #include "common/security_registration.h"
40 #include "common/pkgmgr_query.h"
41 #include "common/utils/base64.h"
42 #include "common/utils/file_util.h"
43 #include "common/utils/user_util.h"
44 #include "common/utils/glist_range.h"
46 namespace bf = boost::filesystem;
47 namespace bpo = boost::program_options;
48 namespace bs = boost::system;
49 namespace ci = common_installer;
53 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
54 const utils::VersionNumber ver30("3.0");
56 const std::vector<const char*> kEntries = {
62 const std::vector<const char*> kReadOnlyEntries = {
69 const char kSharedResDir[] = "shared/res";
70 const char kSharedDataDir[] = "shared/data";
71 const char kSharedTrustedDir[] = "shared/trusted";
72 const char kSkelAppDir[] = "/etc/skel/apps_rw";
73 const char kExternalStoragePrivilege[] =
74 "http://tizen.org/privilege/externalstorage.appdata";
75 const char kSystemShareGroupName[] = "system_share";
77 bool SetFileOwner(const bf::path& subpath, uid_t uid, gid_t gid) {
79 int fd = open(subpath.c_str(), O_RDONLY);
81 LOG(ERROR) << "Can't open directory : " << subpath;
84 int ret = fchown(fd, uid, gid);
87 LOG(ERROR) << "Failed to change owner of: " << subpath;
93 bool SetOwnerAndPermissions(const bf::path& subpath, uid_t uid,
94 gid_t gid, bf::perms perms) {
96 bf::permissions(subpath, perms, error);
98 LOG(ERROR) << "Failed to set permissions for: " << subpath;
102 if (!SetFileOwner(subpath, uid, gid)) {
108 bool SetDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
110 bs::error_code error;
111 bf::perms perms = bf::owner_read |
114 // symlink will be skipped
115 if (bf::is_symlink(symlink_status(subpath)))
118 // non directory will be skipped
120 if (bf::is_directory(subpath)) {
121 perms |= bf::owner_exe | bf::group_exe | bf::others_read | bf::others_exe;
122 if (subpath.filename() == "data") {
123 perms |= bf::group_write | bf::set_gid_on_exe;
124 boost::optional<gid_t> system_share =
125 ci::GetGidByGroupName(kSystemShareGroupName);
130 result = SetOwnerAndPermissions(subpath, uid, gid, perms);
136 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
137 uid_t uid, gid_t gid, const bool set_permissions,
138 const std::vector<const char*> additional_dirs = std::vector<const char*>()) {
139 bf::path base_dir = app_dir / pkgid;
140 if (bf::exists(base_dir)) {
141 LOG(DEBUG) << "Directory for user already exist: " << base_dir;
145 bs::error_code error;
146 std::vector<const char*> dirs(kEntries);
147 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
149 dirs.push_back(kSharedTrustedDir);
150 for (auto& entry : dirs) {
151 bf::path subpath = base_dir / entry;
152 bf::create_directories(subpath, error);
154 LOG(ERROR) << "Failed to create directory: " << subpath;
158 if (set_permissions) {
159 if (!SetDirectoryOwnerAndPermissions(subpath, uid, gid))
163 for (bf::recursive_directory_iterator iter(subpath);
164 iter != bf::recursive_directory_iterator(); ++iter) {
165 if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, gid))
174 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
175 std::string username = ci::GetUsernameByUid(user);
176 if (username.empty())
180 apps_rw = bf::path(apps_prefix.c_str()) / username / "apps_rw";
184 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
185 const std::string& apps_prefix, const bool set_permissions) {
186 boost::optional<gid_t> gid = ci::GetGidByUid(user);
190 std::string group_name = ci::GetGroupNameByGid(*gid);
191 if (group_name != tzplatform_getenv(TZ_SYS_USER_GROUP))
194 LOG(DEBUG) << "Creating directories for uid: " << user << ", gid: "
197 bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
198 if (apps_rw.empty()) {
199 LOG(DEBUG) << "Directory not exists: " << apps_rw;
203 if (!CreateDirectories(apps_rw, pkgid,
204 user, *gid, set_permissions)) {
210 bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
211 bf::path base_dir = app_dir / pkgid;
212 bs::error_code error;
213 bf::remove_all(base_dir, error);
215 LOG(ERROR) << "Failed to delete directory: " << base_dir;
222 bool CreateSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
223 std::vector<char*> rofiles;
224 for (auto& entry : kReadOnlyEntries)
225 rofiles.push_back(strdup(entry));
227 for (bf::directory_iterator file(src_dir);
228 file != bf::directory_iterator();
230 if (bf::is_regular_file(file->path())) {
231 bf::path current(file->path());
232 bf::path file_name = current.filename();
233 LOG(DEBUG) << "file_name: " << file_name;
234 rofiles.push_back(strdup(file_name.c_str()));
238 bs::error_code error;
239 for (auto& entry : rofiles) {
240 bf::path src_path = src_dir / entry;
241 bf::path dst_path = dst_dir / entry;
242 free(const_cast<char*>(entry));
243 if (!bf::exists(src_path)) {
244 // check if symlink for .mmc/bin,lib,res, then do not skip
245 if (!bf::is_symlink(symlink_status(src_path))) {
246 LOG(INFO) << "src_path not exist : " << src_path;
250 if (bf::exists(dst_path)) {
251 LOG(WARNING) << "dst_path exist, skip : " << dst_path;
254 bf::create_symlink(src_path, dst_path, error);
256 LOG(ERROR) << "Symlink creation failure src_path: " << src_path
257 << " dst_path: " << dst_path;
258 LOG(ERROR) << "error: " << error.message();
265 bool DeleteSymlinkFiles(const bf::path& src_dir, const bf::path& dst_dir) {
266 bs::error_code error;
267 for (bf::directory_iterator file(dst_dir);
268 file != bf::directory_iterator();
270 bf::path current(file->path());
271 if (bf::is_symlink(symlink_status(current))) {
272 bf::path resolved_path = bf::read_symlink(current, error);
274 LOG(ERROR) << "Getting resolved path of symlink: " << current;
275 LOG(ERROR) << "resolved_path: " << resolved_path;
276 LOG(ERROR) << "error: " << error.message();
279 LOG(DEBUG) << "resolved_path: " << resolved_path;
280 bf::path parent = resolved_path.parent_path();
281 if (!parent.empty() && (parent == src_dir)) {
282 bf::remove(current, error);
283 LOG(DEBUG) << "removed: " << current;
285 LOG(ERROR) << "Symlink deletion failure for: " << current;
286 LOG(ERROR) << "error: " << error.message();
290 LOG(WARNING) << "Parent is empty or not equal to src, parenet: ("
295 bf::path shared_res = dst_dir / kSharedResDir;
296 if (bf::is_symlink(symlink_status(shared_res))) {
297 bf::remove(shared_res, error);
299 LOG(ERROR) << "Symlink deletion failure for: " << shared_res;
300 LOG(ERROR) << "error: " << error.message();
309 namespace common_installer {
311 std::string GetDirectoryPathForInternalStorage() {
312 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
313 if (internal_storage_prefix)
314 return std::string(internal_storage_prefix);
315 return tzplatform_getenv(TZ_SYS_HOME);
318 std::string GetDirectoryPathForExternalStorage() {
319 return GetExternalCardPath().string();
322 bool PerformExternalDirectoryCreationForUser(uid_t user,
323 const std::string& pkgid) {
324 bf::path storage_path = GetExternalCardPath();
326 const bool set_permissions = false;
327 if (!bf::exists(storage_path)) {
328 LOG(WARNING) << "External storage (SD Card) is not mounted.";
332 bf::path storage_apps_path = storage_path / "apps";
333 if (!bf::exists(storage_apps_path)) {
334 bs::error_code error;
335 bf::create_directories(storage_apps_path, error);
337 LOG(ERROR) << "Failed to create directory: "
338 << storage_apps_path.c_str();
343 CreateUserDirectories(user, pkgid,
344 storage_apps_path.c_str(), set_permissions);
348 bool PerformExternalDirectoryDeletionForUser(uid_t user,
349 const std::string& pkgid) {
350 bf::path storage_path = GetExternalCardPath();
351 if (!bf::exists(storage_path)) {
352 LOG(WARNING) << "External storage (SD Card) is not mounted. "
353 << "It will be ignored";
357 bf::path storage_apps_path = bf::path(storage_path) / "apps";
358 return DeleteDirectories(
359 GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
362 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
363 UserList list = ci::GetUserList();
364 for (auto l : list) {
365 if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
367 LOG(WARNING) << "Could not create external storage directories for user: "
373 int PrivilegeCallback(const pkgmgrinfo_pkginfo_h handle, void* user_data) {
374 uid_t uid = static_cast<uid_t>(reinterpret_cast<uintptr_t>(user_data));
375 char* pkgid = nullptr;
377 int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
378 if (ret != PMINFO_R_OK)
380 if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
386 bool PerformExternalDirectoryCreationForAllPkgs() {
387 UserList list = ci::GetUserList();
388 for (auto l : list) {
389 uid_t uid = std::get<0>(l);
390 pkgmgrinfo_pkginfo_filter_h filter_handle = nullptr;
391 int ret = pkgmgrinfo_pkginfo_filter_create(&filter_handle);
392 if (ret != PMINFO_R_OK)
394 ret = pkgmgrinfo_pkginfo_filter_add_string(filter_handle,
395 PMINFO_PKGINFO_PROP_PACKAGE_PRIVILEGE, kExternalStoragePrivilege);
396 if (ret != PMINFO_R_OK) {
397 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
401 ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(filter_handle,
403 reinterpret_cast<void*>(static_cast<uintptr_t>(uid)));
404 if (ret != PMINFO_R_OK) {
405 LOG(DEBUG) << "Failed to create external directoy";
406 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
409 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
415 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
416 UserList list = ci::GetUserList();
417 for (auto l : list) {
418 uid_t uid = std::get<0>(l);
419 LOG(DEBUG) << "Deleting directories for user: " << uid;
420 if (QueryIsPackageInstalled(pkgid, uid)) {
421 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
422 << " still exists. Skipping";
426 if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
427 LOG(WARNING) << "Could not delete external storage directories for user: "
433 bool CreateSkelDirectories(const std::string& pkgid,
434 const std::string& api_version,
435 bool trusted, bool shareddata, bool is_readonly,
436 const std::vector<const char*> additional_dirs) {
437 bf::path path = bf::path(kSkelAppDir) / pkgid;
438 LOG(DEBUG) << "Creating directories in: " << path;
440 utils::VersionNumber api_ver(api_version);
442 bs::error_code error;
443 bf::create_directories(path, error);
445 LOG(ERROR) << "Failed to create directory: " << path;
449 std::vector<const char*> dirs(kEntries);
450 dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
452 dirs.push_back(kSharedTrustedDir);
453 if (api_ver < ver30 || shareddata) {
454 dirs.push_back(kSharedDataDir);
456 for (auto& entry : dirs) {
457 bf::path subpath = path / entry;
458 bf::create_directories(subpath, error);
459 if (error && !bf::exists(subpath)) {
460 LOG(ERROR) << "Failed to create directory: " << subpath;
465 std::string error_message;
466 if (!RegisterSecurityContextForPath(pkgid, path, kGlobalUserUid,
467 is_readonly, &error_message)) {
468 LOG(ERROR) << "Failed to register security context for path: " << path
469 << ", error_message: " << error_message;
475 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
476 result = CreateSymlinkFiles(src_dir, path);
483 bool DeleteSkelDirectories(const std::string& pkgid) {
484 return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
488 bool DeleteUserDirectories(const std::string& pkgid) {
489 UserList list = ci::GetUserList();
490 for (auto l : list) {
491 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
492 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
496 LOG(DEBUG) << "Deleting directories of " << pkgid
497 << ", for uid: " << std::get<0>(l);
498 bf::path apps_rw(std::get<2>(l) / "apps_rw");
499 if (!DeleteDirectories(apps_rw, pkgid)) {
506 bool DeleteUserExternalDirectories(const std::string& pkgid) {
507 UserList list = ci::GetUserList();
508 for (auto l : list) {
509 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
510 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
514 LOG(DEBUG) << "Deleting external directories of " << pkgid
515 << ", for uid: " << std::get<0>(l);
516 bf::path apps_rw(std::get<2>(l) / "apps_rw");
517 if (!DeleteDirectories(apps_rw, pkgid)) {
525 bool CopyUserDirectories(const std::string& pkgid) {
526 UserList list = ci::GetUserList();
527 for (auto l : list) {
528 uid_t uid = std::get<0>(l);
529 LOG(DEBUG) << "Copying directories for uid: " << uid;
530 bf::path apps_rw(std::get<2>(l) / "apps_rw");
531 bf::path src = bf::path(kSkelAppDir) / pkgid;
532 bf::path dst = apps_rw / pkgid;
533 if (!ci::CopyDir(src, dst, FSFlag::FS_NONE, true))
535 gid_t gid = std::get<1>(l);
536 if (!SetDirectoryOwnerAndPermissions(dst, uid, gid))
538 for (bf::recursive_directory_iterator iter(dst);
539 iter != bf::recursive_directory_iterator(); ++iter) {
540 if (!SetDirectoryOwnerAndPermissions(iter->path(),
544 std::string error_message;
545 if (!RegisterSecurityContextForPath(pkgid, dst, std::get<0>(l),
546 false, &error_message)) {
547 LOG(ERROR) << "Failed to register security context for path: " << dst
548 << ", error_message: " << error_message;
555 bool CreateGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
556 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
557 if (!bf::exists(src_dir)) {
558 LOG(ERROR) << "src_dir not exists";
563 UserList list = ci::GetUserList();
564 for (auto l : list) {
565 uid_t uid = std::get<0>(l);
566 LOG(DEBUG) << "Creating symlinks for uid: " << uid;
567 // check installed user private app.
568 if (QueryIsPackageInstalled(pkgid, uid))
570 bf::path apps_rw(std::get<2>(l) / "apps_rw");
571 bf::path dst_dir = apps_rw / pkgid;
572 if (!bf::exists(dst_dir)) {
573 LOG(WARNING) << "dst_dir not exists";
576 result = CreateSymlinkFiles(src_dir, dst_dir);
581 bool CreateGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
582 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
583 if (!bf::exists(src_dir)) {
584 LOG(ERROR) << "src_dir not exists";
588 tzplatform_set_user(uid);
589 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
590 tzplatform_reset_user();
591 if (!bf::exists(dst_dir)) {
592 LOG(WARNING) << "dst_dir not exists";
595 bool result = CreateSymlinkFiles(src_dir, dst_dir);
600 bool DeleteGlobalAppSymlinksForAllUsers(const std::string& pkgid) {
601 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
602 if (!bf::exists(src_dir)) {
603 LOG(ERROR) << "src_dir not exists";
608 UserList list = ci::GetUserList();
609 for (auto l : list) {
610 uid_t uid = std::get<0>(l);
611 LOG(DEBUG) << "Deleting symlinks for uid: " << uid;
612 // check installed user private app.
613 if (QueryIsPackageInstalled(pkgid, uid))
615 bf::path apps_rw(std::get<2>(l) / "apps_rw");
616 bf::path dst_dir = apps_rw / pkgid;
617 if (!bf::exists(dst_dir)) {
618 LOG(WARNING) << "dst_dir not exists";
621 result = DeleteSymlinkFiles(src_dir, dst_dir);
626 bool DeleteGlobalAppSymlinksForUser(const std::string& pkgid, uid_t uid) {
627 bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
628 if (!bf::exists(src_dir)) {
629 LOG(ERROR) << "src_dir not exists";
633 tzplatform_set_user(uid);
634 bf::path dst_dir = bf::path(tzplatform_getenv(TZ_USER_APP)) / pkgid;
635 tzplatform_reset_user();
636 if (!bf::exists(dst_dir)) {
637 LOG(WARNING) << "dst_dir not exists";
640 bool result = DeleteSymlinkFiles(src_dir, dst_dir);
644 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& path, uid_t uid) {
645 boost::optional<gid_t> gid = ci::GetGidByUid(uid);
648 return SetDirectoryOwnerAndPermissions(path, uid, *gid);
651 } // namespace common_installer