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>
21 #include <sys/types.h>
24 #include <tzplatform_config.h>
25 #include <sys/xattr.h>
26 #include <gum/gum-user.h>
27 #include <gum/gum-user-service.h>
28 #include <gum/common/gum-user-types.h>
42 #include "common/paths.h"
43 #include "common/security_registration.h"
44 #include "common/pkgmgr_query.h"
45 #include "common/utils/base64.h"
46 #include "common/utils/file_util.h"
47 #include "common/utils/glist_range.h"
49 namespace bf = boost::filesystem;
50 namespace bpo = boost::program_options;
51 namespace bs = boost::system;
52 namespace ci = common_installer;
56 const utils::VersionNumber ver30("3.0");
58 typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
59 const std::vector<const char*> kEntries = {
66 const char kSharedDataDir[] = "shared/data";
67 const char kSharedTrustedDir[] = "shared/trusted";
68 const char kSkelAppDir[] = "/etc/skel/apps_rw";
69 const char kLegacyAppDir[] = "/opt/usr/apps";
70 const char kExternalStoragePrivilege[] =
71 "http://tizen.org/privilege/externalstorage.appdata";
72 const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
73 const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
75 bool SetOwnerAndPermissions(const bf::path& subpath, uid_t uid,
76 gid_t gid, bf::perms perms) {
78 bf::permissions(subpath, perms, error);
80 LOG(ERROR) << "Failed to set permissions for: " << subpath;
83 int fd = open(subpath.c_str(), O_RDONLY);
85 LOG(ERROR) << "Can't open directory : " << subpath;
88 int ret = fchown(fd, uid, gid);
91 LOG(ERROR) << "Failed to change owner of: " << subpath;
97 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
100 bf::perms perms = bf::owner_read |
103 if (bf::is_directory(subpath))
104 perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
106 return SetOwnerAndPermissions(subpath, uid, gid, perms);
109 bool SetLegacyDirectoryOwnerAndPermissions(const bf::path& subpath) {
110 bs::error_code error;
111 bf::perms perms = bf::owner_read |
115 if (bf::is_directory(subpath))
116 perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
118 return SetOwnerAndPermissions(subpath, GLOBAL_USER,
119 tzplatform_getgid(TZ_SYS_GLOBALAPP_USER),
123 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
125 uid_t uid, gid_t gid, const bool set_permissions) {
126 bf::path base_dir = app_dir / pkgid;
127 if (bf::exists(base_dir)) {
128 LOG(DEBUG) << "Directory for user already exist: " << base_dir;
132 bs::error_code error;
133 std::vector<const char*> dirs(kEntries);
135 dirs.push_back(kSharedTrustedDir);
136 for (auto& entry : dirs) {
137 bf::path subpath = base_dir / entry;
138 bf::create_directories(subpath, error);
140 LOG(ERROR) << "Failed to create directory: " << subpath;
144 if (set_permissions) {
145 if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
149 for (bf::recursive_directory_iterator iter(subpath);
150 iter != bf::recursive_directory_iterator(); ++iter) {
151 if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
160 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
162 struct passwd *pwd_result;
163 char buf[kPWBufSize];
164 int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
165 if (ret != 0 || pwd_result == nullptr)
169 apps_rw = bf::path(apps_prefix.c_str()) / pwd.pw_name / "apps_rw";
174 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
176 const std::string& apps_prefix, const bool set_permissions) {
178 struct passwd *pwd_result;
179 char buf_pw[kPWBufSize];
180 int ret = getpwuid_r(user, &pwd, buf_pw, sizeof(buf_pw), &pwd_result);
181 if (ret != 0 || pwd_result == nullptr) {
182 LOG(WARNING) << "Failed to get user for home directory: " << user;
187 struct group *gr_result;
188 char buf_gr[kGRBufSize];
189 ret = getgrgid_r(pwd.pw_gid, &gr, buf_gr, sizeof(buf_gr), &gr_result);
191 || strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
194 LOG(DEBUG) << "Creating directories for uid: " << pwd.pw_uid << ", 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, trusted,
204 pwd.pw_uid, pwd.pw_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;
221 user_list GetUserList() {
222 GumUserService* service =
223 gum_user_service_create_sync((getuid() == 0) ? TRUE : FALSE);
224 gchar** user_type_strv = gum_user_type_to_strv(
225 GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL |
226 GUM_USERTYPE_SECURITY);
227 GumUserList* gum_user_list =
228 gum_user_service_get_user_list_sync(service, user_type_strv);
230 for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
232 g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
234 g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
235 gchar* homedir = nullptr;
236 g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
237 if (homedir == nullptr) {
238 LOG(WARNING) << "No homedir for uid: " << uid;
241 list.emplace_back(uid, gid, bf::path(homedir));
243 g_strfreev(user_type_strv);
244 gum_user_service_list_free(gum_user_list);
250 namespace common_installer {
252 std::string GetDirectoryPathForInternalStorage() {
253 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
254 if (internal_storage_prefix)
255 return std::string(internal_storage_prefix);
256 return tzplatform_getenv(TZ_SYS_HOME);
259 std::string GetDirectoryPathForExternalStorage() {
260 return GetExternalCardPath().string();
263 bool PerformExternalDirectoryCreationForUser(uid_t user,
264 const std::string& pkgid) {
265 bf::path storage_path = GetExternalCardPath();
267 // TODO(t.iwanek): trusted in this context means that we have signature
268 // this argument is not longer needed as all package must be signed
269 // so that trusted directory may be labeled correctly by security-manager in
270 // all cases. This parameter and its propagation should be removed.
273 const bool set_permissions = false;
274 if (!bf::exists(storage_path)) {
275 LOG(WARNING) << "External storage (SD Card) is not mounted.";
279 bf::path storage_apps_path = storage_path / "apps";
280 if (!bf::exists(storage_apps_path)) {
281 bs::error_code error;
282 bf::create_directories(storage_apps_path, error);
284 LOG(ERROR) << "Failed to create directory: "
285 << storage_apps_path.c_str();
290 if (CreateUserDirectories(user, pkgid, trusted,
291 storage_apps_path.c_str(), set_permissions)) {
296 bool PerformExternalDirectoryDeletionForUser(uid_t user,
297 const std::string& pkgid) {
298 bf::path storage_path = GetExternalCardPath();
299 if (!bf::exists(storage_path)) {
300 LOG(WARNING) << "External storage (SD Card) is not mounted.";
304 bf::path storage_apps_path = bf::path(storage_path) / "apps";
305 return DeleteDirectories(
306 GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
309 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
310 user_list list = GetUserList();
311 for (auto l : list) {
312 if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
314 LOG(WARNING) << "Could not create external storage directories for user: "
320 int PrivilegeCallback(const pkgmgrinfo_pkginfo_h handle, void* user_data) {
321 uid_t uid = (uid_t)user_data;
322 char* pkgid = nullptr;
324 int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
325 if (ret != PMINFO_R_OK)
327 if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
333 bool PerformExternalDirectoryCreationForAllPkgs(void) {
334 user_list list = GetUserList();
335 for (auto l : list) {
336 uid_t uid = std::get<0>(l);
337 pkgmgrinfo_pkginfo_filter_h filter_handle = nullptr;
338 int ret = pkgmgrinfo_pkginfo_filter_create(&filter_handle);
339 if (ret != PMINFO_R_OK)
341 ret = pkgmgrinfo_pkginfo_filter_add_string(filter_handle,
342 PMINFO_PKGINFO_PROP_PACKAGE_PRIVILEGE, kExternalStoragePrivilege);
343 if (ret != PMINFO_R_OK) {
344 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
348 ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(filter_handle,
349 PrivilegeCallback, reinterpret_cast<void*>(uid));
350 if (ret != PMINFO_R_OK) {
351 LOG(DEBUG) << "Failed to create external directoy";
352 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
355 pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
361 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
362 user_list list = GetUserList();
363 for (auto l : list) {
364 uid_t uid = std::get<0>(l);
365 LOG(DEBUG) << "Deleting directories for user: " << uid;
366 if (QueryIsPackageInstalled(pkgid, uid)) {
367 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
368 << " still exists. Skipping";
372 if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
373 LOG(WARNING) << "Could not delete external storage directories for user: "
379 bool CreateSkelDirectories(const std::string& pkgid,
380 const std::string& api_version,
382 bf::path path = bf::path(kSkelAppDir) / pkgid;
383 LOG(DEBUG) << "Creating directories in: " << path;
385 utils::VersionNumber api_ver(api_version);
387 bs::error_code error;
388 bf::create_directories(path, error);
391 LOG(ERROR) << "Failed to create directory: " << path;
395 std::vector<const char*> dirs(kEntries);
397 dirs.push_back(kSharedTrustedDir);
398 if (api_ver < ver30) {
399 dirs.push_back(kSharedDataDir);
401 for (auto& entry : dirs) {
402 bf::path subpath = path / entry;
403 bf::create_directories(subpath, error);
404 if (error && !bf::exists(subpath)) {
405 LOG(ERROR) << "Failed to create directory: " << subpath;
410 std::string error_message;
411 if (!RegisterSecurityContextForPath(pkgid, path, GLOBAL_USER,
412 false, &error_message)) {
413 LOG(ERROR) << "Failed to register security context for path: " << path
414 << ", error_message: " << error_message;
422 bool DeleteSkelDirectories(const std::string& pkgid) {
423 return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
427 bool DeleteUserDirectories(const std::string& pkgid) {
428 user_list list = GetUserList();
429 for (auto l : list) {
430 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
431 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
435 LOG(DEBUG) << "Deleting directories of " << pkgid
436 << ", for uid: " << std::get<0>(l);
437 bf::path apps_rw(std::get<2>(l) / "apps_rw");
438 if (!DeleteDirectories(apps_rw, pkgid)) {
445 bool DeleteUserExternalDirectories(const std::string& pkgid) {
446 user_list list = GetUserList();
447 for (auto l : list) {
448 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
449 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
453 LOG(DEBUG) << "Deleting external directories of " << pkgid
454 << ", for uid: " << std::get<0>(l);
455 bf::path apps_rw(std::get<2>(l) / "apps_rw");
456 if (!DeleteDirectories(apps_rw, pkgid)) {
464 bool CopyUserDirectories(const std::string& pkgid) {
465 user_list list = GetUserList();
466 for (auto l : list) {
467 LOG(DEBUG) << "Copying directories for uid: " << std::get<0>(l);
468 bf::path apps_rw(std::get<2>(l) / "apps_rw");
469 bf::path src = bf::path(kSkelAppDir) / pkgid;
470 bf::path dst = apps_rw / pkgid;
471 if (!ci::CopyDir(src, dst))
473 if (!SetPackageDirectoryOwnerAndPermissions(dst, std::get<0>(l),
476 for (bf::recursive_directory_iterator iter(dst);
477 iter != bf::recursive_directory_iterator(); ++iter) {
478 if (!SetPackageDirectoryOwnerAndPermissions(iter->path(),
479 std::get<0>(l), std::get<1>(l)))
482 std::string error_message;
483 if (!RegisterSecurityContextForPath(pkgid, dst, std::get<0>(l), true,
485 LOG(ERROR) << "Failed to register security context for path: " << dst
486 << ", error_message: " << error_message;
493 bool CreateLegacyDirectories(const std::string& pkgid) {
494 // create lagcay directories for backward compatibility
495 bs::error_code error;
496 bf::path path = bf::path(kLegacyAppDir) / pkgid;
497 bf::create_directories(path, error);
498 if (error && !bf::exists(path)) {
499 LOG(ERROR) << "Failed to create directory: " << path;
503 std::vector<const char*> dirs(kEntries);
504 dirs.push_back(kSharedTrustedDir);
505 dirs.push_back(kSharedDataDir);
506 for (auto& entry : dirs) {
507 bf::path subpath = path / entry;
508 bf::create_directories(subpath, error);
509 if (error && !bf::exists(subpath)) {
510 LOG(ERROR) << "Failed to create directory: " << subpath;
513 if (!SetLegacyDirectoryOwnerAndPermissions(subpath)) {
514 LOG(ERROR) << "Failed to set permission: " << subpath;
519 std::string error_message;
520 if (!RegisterSecurityContextForPath(pkgid, path, GLOBAL_USER,
521 false, &error_message)) {
522 LOG(ERROR) << "Failed to register security context for path: " << path
523 << ", error_message: " << error_message;
530 bool DeleteLegacyDirectories(uid_t uid, const std::string& pkgid) {
531 bool del_flag = true;
534 user_list list = GetUserList();
537 for (auto l : list) {
538 chk_uid = std::get<0>(l);
541 LOG(DEBUG) << "Check package existence for uid: " << chk_uid;
542 if (QueryIsPackageInstalled(pkgid, chk_uid)) {
543 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << chk_uid
550 if (del_flag && uid != GLOBAL_USER) {
551 if (QueryIsPackageInstalled(pkgid, GLOBAL_USER)) {
552 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << GLOBAL_USER
559 LOG(DEBUG) << "Delete legacy directories for package: " << pkgid;
560 DeleteDirectories(bf::path(kLegacyAppDir), pkgid);
566 } // namespace common_installer