Implement new dbus method for create all external directories
[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 <pwd.h>
20 #include <grp.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <fcntl.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>
29
30 #include <algorithm>
31 #include <cassert>
32 #include <cstring>
33 #include <cstdio>
34 #include <exception>
35 #include <iterator>
36 #include <regex>
37 #include <string>
38 #include <utility>
39 #include <vector>
40 #include <tuple>
41
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"
48
49 namespace bf = boost::filesystem;
50 namespace bpo = boost::program_options;
51 namespace bs = boost::system;
52 namespace ci = common_installer;
53
54 namespace {
55
56 const utils::VersionNumber ver30("3.0");
57
58 typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
59 const std::vector<const char*> kEntries = {
60   {"/"},
61   {"cache/"},
62   {"data/"},
63   {"shared/"},
64 };
65
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);
74
75 bool SetOwnerAndPermissions(const bf::path& subpath, uid_t uid,
76                             gid_t gid, bf::perms perms) {
77   bs::error_code error;
78   bf::permissions(subpath, perms, error);
79   if (error) {
80     LOG(ERROR) << "Failed to set permissions for: " << subpath;
81     return false;
82   }
83   int fd = open(subpath.c_str(), O_RDONLY);
84   if (fd < 0) {
85     LOG(ERROR) << "Can't open directory : " << subpath;
86     return false;
87   }
88   int ret = fchown(fd, uid, gid);
89   close(fd);
90   if (ret != 0) {
91     LOG(ERROR) << "Failed to change owner of: " << subpath;
92     return false;
93   }
94   return true;
95 }
96
97 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
98                                             gid_t gid) {
99   bs::error_code error;
100   bf::perms perms = bf::owner_read |
101                     bf::owner_write |
102                     bf::group_read;
103   if (bf::is_directory(subpath))
104     perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
105
106   return SetOwnerAndPermissions(subpath, uid, gid, perms);
107 }
108
109 bool SetLegacyDirectoryOwnerAndPermissions(const bf::path& subpath) {
110   bs::error_code error;
111   bf::perms perms = bf::owner_read |
112                     bf::owner_write |
113                     bf::group_read |
114                     bf::others_read;
115   if (bf::is_directory(subpath))
116     perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
117
118   return SetOwnerAndPermissions(subpath, GLOBAL_USER,
119                                 tzplatform_getgid(TZ_SYS_GLOBALAPP_USER),
120                                 perms);
121 }
122
123 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
124                        bool trusted,
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;
129     return true;
130   }
131
132   bs::error_code error;
133   std::vector<const char*> dirs(kEntries);
134   if (trusted)
135     dirs.push_back(kSharedTrustedDir);
136   for (auto& entry : dirs) {
137     bf::path subpath = base_dir / entry;
138     bf::create_directories(subpath, error);
139     if (error) {
140       LOG(ERROR) << "Failed to create directory: " << subpath;
141       return false;
142     }
143
144     if (set_permissions) {
145       if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
146         return false;
147
148       // for content
149       for (bf::recursive_directory_iterator iter(subpath);
150            iter != bf::recursive_directory_iterator(); ++iter) {
151         if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
152           return false;
153       }
154     }
155   }
156
157   return true;
158 }
159
160 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
161   struct passwd pwd;
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)
166     return {};
167
168   bf::path apps_rw;
169   apps_rw = bf::path(apps_prefix.c_str()) / pwd.pw_name / "apps_rw";
170
171   return apps_rw;
172 }
173
174 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
175     bool trusted,
176     const std::string& apps_prefix, const bool set_permissions) {
177   struct passwd pwd;
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;
183     return false;
184   }
185
186   struct group gr;
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);
190   if (ret != 0
191       || strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
192     return false;
193
194   LOG(DEBUG) << "Creating directories for uid: " << pwd.pw_uid << ", gid: "
195              << pwd.pw_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, trusted,
204       pwd.pw_uid, pwd.pw_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 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);
229   user_list list;
230   for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
231     uid_t uid;
232     g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
233     gid_t gid;
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;
239       continue;
240     }
241     list.emplace_back(uid, gid, bf::path(homedir));
242   }
243   g_strfreev(user_type_strv);
244   gum_user_service_list_free(gum_user_list);
245   return list;
246 }
247
248 }  // namespace
249
250 namespace common_installer {
251
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);
257 }
258
259 std::string GetDirectoryPathForExternalStorage() {
260   return GetExternalCardPath().string();
261 }
262
263 bool PerformExternalDirectoryCreationForUser(uid_t user,
264                                              const std::string& pkgid) {
265   bf::path storage_path = GetExternalCardPath();
266
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.
271   bool trusted = true;
272
273   const bool set_permissions = false;
274   if (!bf::exists(storage_path)) {
275     LOG(WARNING) << "External storage (SD Card) is not mounted.";
276     return false;
277   }
278
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);
283     if (error) {
284       LOG(ERROR) << "Failed to create directory: "
285           << storage_apps_path.c_str();
286       return false;
287     }
288   }
289
290   if (CreateUserDirectories(user, pkgid, trusted,
291                             storage_apps_path.c_str(), set_permissions)) {
292   }
293   return true;
294 }
295
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.";
301     return false;
302   }
303
304   bf::path storage_apps_path = bf::path(storage_path) / "apps";
305   return DeleteDirectories(
306       GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
307 }
308
309 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
310   user_list list = GetUserList();
311   for (auto l : list) {
312     if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
313                                                  pkgid))
314       LOG(WARNING) << "Could not create external storage directories for user: "
315                    << std::get<0>(l);
316   }
317   return true;
318 }
319
320 int PrivilegeCallback(const pkgmgrinfo_pkginfo_h handle, void* user_data) {
321   uid_t uid = (uid_t)user_data;
322   char* pkgid = nullptr;
323
324   int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid);
325   if (ret != PMINFO_R_OK)
326     return -1;
327   if (!PerformExternalDirectoryCreationForUser(uid, pkgid))
328     return -1;
329
330   return 0;
331 }
332
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)
340       return false;
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);
345       return false;
346     }
347
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);
353       return false;
354     }
355     pkgmgrinfo_pkginfo_filter_destroy(filter_handle);
356   }
357
358   return true;
359 }
360
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";
369       continue;
370     }
371
372     if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
373       LOG(WARNING) << "Could not delete external storage directories for user: "
374                    << uid;
375   }
376   return true;
377 }
378
379 bool CreateSkelDirectories(const std::string& pkgid,
380                            const std::string& api_version,
381                            bool trusted) {
382   bf::path path = bf::path(kSkelAppDir) / pkgid;
383   LOG(DEBUG) << "Creating directories in: " << path;
384
385   utils::VersionNumber api_ver(api_version);
386
387   bs::error_code error;
388   bf::create_directories(path, error);
389
390   if (error) {
391     LOG(ERROR) << "Failed to create directory: " << path;
392     return false;
393   }
394
395   std::vector<const char*> dirs(kEntries);
396   if (trusted)
397     dirs.push_back(kSharedTrustedDir);
398   if (api_ver < ver30) {
399     dirs.push_back(kSharedDataDir);
400   }
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;
406       return false;
407     }
408   }
409
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;
415     return false;
416   }
417
418   return true;
419 }
420
421
422 bool DeleteSkelDirectories(const std::string& pkgid) {
423   return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
424 }
425
426
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);
432       continue;
433     }
434
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)) {
439       return false;
440     }
441   }
442   return true;
443 }
444
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);
450       continue;
451     }
452
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)) {
457       return false;
458     }
459   }
460   return true;
461 }
462
463
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))
472       continue;
473     if (!SetPackageDirectoryOwnerAndPermissions(dst, std::get<0>(l),
474         std::get<1>(l)))
475       return false;
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)))
480         return false;
481     }
482     std::string error_message;
483     if (!RegisterSecurityContextForPath(pkgid, dst, std::get<0>(l), true,
484         &error_message)) {
485       LOG(ERROR) << "Failed to register security context for path: " << dst
486                  << ", error_message: " << error_message;
487       return false;
488     }
489   }
490   return true;
491 }
492
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;
500     return false;
501   }
502
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;
511       return false;
512     }
513     if (!SetLegacyDirectoryOwnerAndPermissions(subpath)) {
514       LOG(ERROR) << "Failed to set permission: " << subpath;
515       return false;
516     }
517   }
518
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;
524     return false;
525   }
526
527   return true;
528 }
529
530 bool DeleteLegacyDirectories(uid_t uid, const std::string& pkgid) {
531   bool del_flag = true;
532   uid_t chk_uid;
533
534   user_list list = GetUserList();
535   if (list.empty())
536     return true;
537   for (auto l : list) {
538     chk_uid = std::get<0>(l);
539     if (chk_uid == uid)
540       continue;
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
544                  << " still exists.";
545       del_flag = false;
546       break;;
547     }
548   }
549
550   if (del_flag && uid != GLOBAL_USER) {
551     if (QueryIsPackageInstalled(pkgid, GLOBAL_USER)) {
552       LOG(DEBUG) << "Package: " << pkgid << " for uid: " << GLOBAL_USER
553                  << " still exists.";
554       del_flag = false;
555     }
556   }
557
558   if (del_flag) {
559     LOG(DEBUG) << "Delete legacy directories for package: " << pkgid;
560     DeleteDirectories(bf::path(kLegacyAppDir), pkgid);
561   }
562
563   return true;
564 }
565
566 }  // namespace common_installer