Fix some log level
[platform/core/appfw/app-installers.git] / src / common / shared_dirs.cc
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.
4
5 #include "common/shared_dirs.h"
6
7 #include <manifest_parser/utils/logging.h>
8 #include <manifest_parser/utils/version_number.h>
9
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>
14
15 #include <glib.h>
16 #include <gio/gio.h>
17 #include <vcore/Certificate.h>
18 #include <pkgmgr-info.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <tzplatform_config.h>
23 #include <sys/xattr.h>
24
25
26 #include <algorithm>
27 #include <cassert>
28 #include <cstring>
29 #include <cstdio>
30 #include <exception>
31 #include <iterator>
32 #include <regex>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 #include <tuple>
37
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"
45
46 namespace bf = boost::filesystem;
47 namespace bpo = boost::program_options;
48 namespace bs = boost::system;
49 namespace ci = common_installer;
50
51 namespace {
52
53 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
54 const utils::VersionNumber ver30("3.0");
55
56 const std::vector<const char*> kEntries = {
57   {"/"},
58   {"cache"},
59   {"data"},
60   {"shared"},
61 };
62 const std::vector<const char*> kReadOnlyEntries = {
63   {"bin"},
64   {"lib"},
65   {"res"},
66   {"shared/res"},
67 };
68
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";
76
77 bool SetFileOwner(const bf::path& subpath, uid_t uid, gid_t gid) {
78   bs::error_code error;
79   int fd = open(subpath.c_str(), O_RDONLY);
80   if (fd < 0) {
81     LOG(ERROR) << "Can't open directory : " << subpath;
82     return false;
83   }
84   int ret = fchown(fd, uid, gid);
85   close(fd);
86   if (ret != 0) {
87     LOG(ERROR) << "Failed to change owner of: " << subpath;
88     return false;
89   }
90   return true;
91 }
92
93 bool SetOwnerAndPermissions(const bf::path& subpath, uid_t uid,
94                             gid_t gid, bf::perms perms) {
95   bs::error_code error;
96   bf::permissions(subpath, perms, error);
97   if (error) {
98     LOG(ERROR) << "Failed to set permissions for: " << subpath;
99     return false;
100   }
101
102   if (!SetFileOwner(subpath, uid, gid)) {
103     return false;
104   }
105   return true;
106 }
107
108 bool SetDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
109                                             gid_t gid) {
110   bs::error_code error;
111   bf::perms perms = bf::owner_read |
112                     bf::owner_write |
113                     bf::group_read;
114   // symlink will be skipped
115   if (bf::is_symlink(symlink_status(subpath)))
116     return true;
117
118   // non directory will be skipped
119   bool result = true;
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);
126       if (!system_share)
127         return false;
128       gid = *system_share;
129     }
130     result = SetOwnerAndPermissions(subpath, uid, gid, perms);
131   }
132
133   return result;
134 }
135
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;
142     return true;
143   }
144
145   bs::error_code error;
146   std::vector<const char*> dirs(kEntries);
147   dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
148   // always trusted
149   dirs.push_back(kSharedTrustedDir);
150   for (auto& entry : dirs) {
151     bf::path subpath = base_dir / entry;
152     bf::create_directories(subpath, error);
153     if (error) {
154       LOG(ERROR) << "Failed to create directory: " << subpath;
155       return false;
156     }
157
158     if (set_permissions) {
159       if (!SetDirectoryOwnerAndPermissions(subpath, uid, gid))
160         return false;
161
162       // for content
163       for (bf::recursive_directory_iterator iter(subpath);
164            iter != bf::recursive_directory_iterator(); ++iter) {
165         if (!SetDirectoryOwnerAndPermissions(iter->path(), uid, gid))
166           return false;
167       }
168     }
169   }
170
171   return true;
172 }
173
174 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
175   std::string username = ci::GetUsernameByUid(user);
176   if (username.empty())
177     return {};
178
179   bf::path apps_rw;
180   apps_rw = bf::path(apps_prefix.c_str()) / username / "apps_rw";
181   return apps_rw;
182 }
183
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);
187   if (!gid)
188     return false;
189
190   std::string group_name = ci::GetGroupNameByGid(*gid);
191   if (group_name != tzplatform_getenv(TZ_SYS_USER_GROUP))
192     return false;
193
194   LOG(DEBUG) << "Creating directories for uid: " << user << ", gid: "
195              << *gid;
196
197   bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
198   if (apps_rw.empty()) {
199     LOG(DEBUG) << "Directory not exists: " << apps_rw;
200     return false;
201   }
202
203   if (!CreateDirectories(apps_rw, pkgid,
204      user, *gid, set_permissions)) {
205     return false;
206   }
207   return true;
208 }
209
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);
214   if (error) {
215     LOG(ERROR) << "Failed to delete directory: " << base_dir;
216     return false;
217   }
218   return true;
219 }
220
221
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));
226
227   for (bf::directory_iterator file(src_dir);
228       file != bf::directory_iterator();
229       ++file) {
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()));
235     }
236   }
237
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;
247         continue;
248       }
249     }
250     if (bf::exists(dst_path)) {
251       LOG(WARNING) << "dst_path exist, skip : " << dst_path;
252       continue;
253     }
254     bf::create_symlink(src_path, dst_path, error);
255     if (error) {
256       LOG(ERROR) << "Symlink creation failure src_path: " << src_path
257                  << " dst_path: " << dst_path;
258       LOG(ERROR) << "error: " << error.message();
259       return false;
260     }
261   }
262   return true;
263 }
264
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();
269       ++file) {
270     bf::path current(file->path());
271     if (bf::is_symlink(symlink_status(current))) {
272       bf::path resolved_path = bf::read_symlink(current, error);
273       if (error) {
274         LOG(ERROR) << "Getting resolved path of symlink: " << current;
275         LOG(ERROR) << "resolved_path: " << resolved_path;
276         LOG(ERROR) << "error: " << error.message();
277         return false;
278       }
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;
284         if (error) {
285           LOG(ERROR) << "Symlink deletion failure for: " << current;
286           LOG(ERROR) << "error: " << error.message();
287           return false;
288         }
289       } else {
290         LOG(WARNING) << "Parent is empty or not equal to src, parenet: ("
291                    << parent << ")";
292       }
293     }
294   }
295   bf::path shared_res = dst_dir / kSharedResDir;
296   if (bf::is_symlink(symlink_status(shared_res))) {
297       bf::remove(shared_res, error);
298       if (error) {
299           LOG(ERROR) << "Symlink deletion failure for: " << shared_res;
300           LOG(ERROR) << "error: " << error.message();
301           return false;
302       }
303   }
304   return true;
305 }
306
307 }  // namespace
308
309 namespace common_installer {
310
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);
316 }
317
318 std::string GetDirectoryPathForExternalStorage() {
319   return GetExternalCardPath().string();
320 }
321
322 bool PerformExternalDirectoryCreationForUser(uid_t user,
323                                              const std::string& pkgid) {
324   bf::path storage_path = GetExternalCardPath();
325
326   const bool set_permissions = false;
327   if (!bf::exists(storage_path)) {
328     LOG(WARNING) << "External storage (SD Card) is not mounted.";
329     return false;
330   }
331
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);
336     if (error) {
337       LOG(ERROR) << "Failed to create directory: "
338           << storage_apps_path.c_str();
339       return false;
340     }
341   }
342
343   CreateUserDirectories(user, pkgid,
344                             storage_apps_path.c_str(), set_permissions);
345   return true;
346 }
347
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";
354     return true;
355   }
356
357   bf::path storage_apps_path = bf::path(storage_path) / "apps";
358   return DeleteDirectories(
359       GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
360 }
361
362 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
363   UserList list = ci::GetUserList();
364   for (auto l : list) {
365     if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
366                                                  pkgid))
367       LOG(WARNING) << "Could not create external storage directories for user: "
368                    << std::get<0>(l);
369   }
370   return true;
371 }
372
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;
376
377   int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
378   if (ret != PMINFO_R_OK)
379     return -1;
380   if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
381     return -1;
382
383   return 0;
384 }
385
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)
393       return false;
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);
398       return false;
399     }
400
401     ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(filter_handle,
402         PrivilegeCallback,
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);
407       return false;
408     }
409     pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
410   }
411
412   return true;
413 }
414
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";
423       continue;
424     }
425
426     if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
427       LOG(WARNING) << "Could not delete external storage directories for user: "
428                    << uid;
429   }
430   return true;
431 }
432
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;
439
440   utils::VersionNumber api_ver(api_version);
441
442   bs::error_code error;
443   bf::create_directories(path, error);
444   if (error) {
445     LOG(ERROR) << "Failed to create directory: " << path;
446     return false;
447   }
448
449   std::vector<const char*> dirs(kEntries);
450   dirs.insert(dirs.end(), additional_dirs.begin(), additional_dirs.end());
451   if (trusted)
452     dirs.push_back(kSharedTrustedDir);
453   if (api_ver < ver30 || shareddata) {
454     dirs.push_back(kSharedDataDir);
455   }
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;
461       return false;
462     }
463   }
464
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;
470     return false;
471   }
472
473   bool result = true;
474   if (!is_readonly) {
475     bf::path src_dir = bf::path(tzplatform_getenv(TZ_SYS_RW_APP)) / pkgid;
476     result = CreateSymlinkFiles(src_dir, path);
477   }
478
479   return result;
480 }
481
482
483 bool DeleteSkelDirectories(const std::string& pkgid) {
484   return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
485 }
486
487
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);
493       continue;
494     }
495
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)) {
500       return false;
501     }
502   }
503   return true;
504 }
505
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);
511       continue;
512     }
513
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)) {
518       return false;
519     }
520   }
521   return true;
522 }
523
524
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))
534       continue;
535     gid_t gid = std::get<1>(l);
536     if (!SetDirectoryOwnerAndPermissions(dst, uid, gid))
537       return false;
538     for (bf::recursive_directory_iterator iter(dst);
539         iter != bf::recursive_directory_iterator(); ++iter) {
540       if (!SetDirectoryOwnerAndPermissions(iter->path(),
541           uid, gid))
542         return false;
543     }
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;
549       return false;
550     }
551   }
552   return true;
553 }
554
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";
559     return false;
560   }
561
562   bool result = true;
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))
569       continue;
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";
574       continue;
575     }
576     result = CreateSymlinkFiles(src_dir, dst_dir);
577   }
578   return result;
579 }
580
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";
585     return false;
586   }
587
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";
593     return true;
594   }
595   bool result = CreateSymlinkFiles(src_dir, dst_dir);
596
597   return result;
598 }
599
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";
604     return false;
605   }
606
607   bool result = true;
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))
614       continue;
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";
619       continue;
620     }
621     result = DeleteSymlinkFiles(src_dir, dst_dir);
622   }
623   return result;
624 }
625
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";
630     return false;
631   }
632
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";
638     return true;
639   }
640   bool result = DeleteSymlinkFiles(src_dir, dst_dir);
641   return result;
642 }
643
644 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& path, uid_t uid) {
645   boost::optional<gid_t> gid = ci::GetGidByUid(uid);
646   if (!gid)
647     return false;
648   return SetDirectoryOwnerAndPermissions(path, uid, *gid);
649 }
650
651 }  // namespace common_installer