Remove attr_copy_file
[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 <boost/filesystem/operations.hpp>
8 #include <boost/filesystem/path.hpp>
9 #include <boost/program_options.hpp>
10 #include <boost/system/error_code.hpp>
11
12 #include <glib.h>
13 #include <gio/gio.h>
14 #include <manifest_parser/utils/logging.h>
15 #include <vcore/Certificate.h>
16 #include <pkgmgr-info.h>
17 #include <pwd.h>
18 #include <grp.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 #include <gum/gum-user.h>
25 #include <gum/gum-user-service.h>
26 #include <gum/common/gum-user-types.h>
27
28 #include <algorithm>
29 #include <cassert>
30 #include <cstring>
31 #include <cstdio>
32 #include <exception>
33 #include <iterator>
34 #include <regex>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 #include <tuple>
39
40 #include "common/paths.h"
41 #include "common/security_registration.h"
42 #include "common/pkgmgr_query.h"
43 #include "common/utils/base64.h"
44 #include "common/utils/file_util.h"
45 #include "common/utils/glist_range.h"
46
47 namespace bf = boost::filesystem;
48 namespace bpo = boost::program_options;
49 namespace bs = boost::system;
50 namespace ci = common_installer;
51
52 namespace {
53
54 typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
55 const std::vector<const char*> kEntries = {
56   {"/"},
57   {"cache/"},
58   {"data/"},
59   {"shared/"},
60   {"shared/cache/"},
61 };
62
63 const char kTrustedDir[] = "shared/trusted";
64 const char kSkelAppDir[] = "/etc/skel/apps_rw";
65 const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
66 const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
67 const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
68
69 bool ValidateTizenPackageId(const std::string& id) {
70   std::regex package_regex(kPackagePattern);
71   return std::regex_match(id, package_regex);
72 }
73
74 int PkgmgrListCallback(const pkgmgrinfo_pkginfo_h handle, void *user_data) {
75   auto pkgs = reinterpret_cast<ci::PkgList*>(user_data);
76   char* pkgid = nullptr;
77   if (pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid) != PMINFO_R_OK) {
78     return -1;
79   }
80   char* api_version;
81   if (pkgmgrinfo_pkginfo_get_api_version(handle, &api_version) != PMINFO_R_OK) {
82     return -1;
83   }
84   pkgmgrinfo_certinfo_h cert_handle;
85   if (pkgmgrinfo_pkginfo_create_certinfo(&cert_handle) != PMINFO_R_OK) {
86     return -1;
87   }
88   if (pkgmgrinfo_pkginfo_load_certinfo(pkgid, cert_handle, 0) != PMINFO_R_OK) {
89     pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
90     return -1;
91   }
92   const char* author_cert;
93   if (pkgmgrinfo_pkginfo_get_cert_value(cert_handle, PMINFO_AUTHOR_SIGNER_CERT,
94       &author_cert) != PMINFO_R_OK) {
95     pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
96     return -1;
97   }
98   if (author_cert) {
99     ValidationCore::Certificate cert(author_cert,
100         ValidationCore::Certificate::FORM_BASE64);
101     unsigned char* public_key;
102     size_t len;
103     cert.getPublicKeyDER(&public_key, &len);
104     std::string author_id =
105         ci::EncodeBase64(reinterpret_cast<const char*>(public_key));
106     pkgs->emplace_back(pkgid, api_version, author_id);
107   } else {
108     pkgs->emplace_back(pkgid, std::string(), std::string());
109   }
110
111   pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
112
113   return 0;
114 }
115
116 ci::PkgList GetAllGlobalAppsInformation() {
117   ci::PkgList pkgs;
118   if (pkgmgrinfo_pkginfo_get_usr_list(&PkgmgrListCallback,
119       &pkgs, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) != PMINFO_R_OK) {
120     LOG(ERROR) << "Failed to query global application list";
121     return {};
122   }
123   return pkgs;
124 }
125
126 ci::PkgList GetPkgInformation(uid_t uid, const std::string& pkgid) {
127   if (!ValidateTizenPackageId(pkgid)) {
128     LOG(DEBUG) << "Package id validation failed. pkgid = " << pkgid;
129     return ci::PkgList();
130   }
131
132   ci::PkgList pkgs;
133   pkgmgrinfo_pkginfo_h handle;
134   if (pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid.c_str(), uid, &handle) !=
135       PMINFO_R_OK) {
136     LOG(DEBUG) << "pkgmgrinfo_pkginfo_get_pkginfo failed, for pkgid=" << pkgid;
137     return {};
138   }
139   if (PkgmgrListCallback(handle, &pkgs) != 0) {
140     pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
141     LOG(DEBUG) << "PkgmgrListCallback failed";
142     return {};
143   }
144   pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
145   return pkgs;
146 }
147
148 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
149                                             gid_t gid) {
150   bs::error_code error;
151   bf::perms perms = bf::owner_read |
152                     bf::owner_write |
153                     bf::group_read;
154   if (bf::is_directory(subpath)) {
155     perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
156   }
157   bf::permissions(subpath, perms, error);
158   if (error) {
159     LOG(ERROR) << "Failed to set permissions for: " << subpath;
160     return false;
161   }
162   int fd = open(subpath.c_str(), O_RDONLY);
163   if (fd < 0) {
164     LOG(ERROR) << "Can't open directory : " << subpath;
165     return false;
166   }
167   int ret = fchown(fd, uid, gid);
168   close(fd);
169   if (ret != 0) {
170     LOG(ERROR) << "Failed to change owner of: " << subpath;
171     return false;
172   }
173   return true;
174 }
175
176 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
177                        bool trusted,
178                        uid_t uid, gid_t gid, const bool set_permissions) {
179   bf::path base_dir = app_dir / pkgid;
180   if (bf::exists(base_dir)) {
181     LOG(DEBUG) << "Directory for user already exist: " << base_dir;
182     return true;
183   }
184
185   bs::error_code error;
186   std::vector<const char*> dirs(kEntries);
187   if (trusted)
188     dirs.push_back(kTrustedDir);
189   for (auto& entry : dirs) {
190     bf::path subpath = base_dir / entry;
191     bf::create_directories(subpath, error);
192     if (error) {
193       LOG(ERROR) << "Failed to create directory: " << subpath;
194       return false;
195     }
196
197     if (set_permissions) {
198       if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
199         return false;
200
201       // for content
202       for (bf::recursive_directory_iterator iter(subpath);
203            iter != bf::recursive_directory_iterator(); ++iter) {
204         if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
205           return false;
206       }
207     }
208   }
209
210   return true;
211 }
212
213 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
214   struct passwd pwd;
215   struct passwd *pwd_result;
216   char buf[kPWBufSize];
217   int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
218   if (ret != 0 || pwd_result == nullptr)
219     return {};
220
221   bf::path apps_rw;
222   apps_rw = bf::path(apps_prefix.c_str()) / pwd.pw_name / "apps_rw";
223
224   return apps_rw;
225 }
226
227 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
228     bool trusted,
229     const std::string& apps_prefix, const bool set_permissions) {
230   struct passwd pwd;
231   struct passwd *pwd_result;
232   char buf_pw[kPWBufSize];
233   int ret = getpwuid_r(user, &pwd, buf_pw, sizeof(buf_pw), &pwd_result);
234   if (ret != 0 || pwd_result == nullptr) {
235     LOG(WARNING) << "Failed to get user for home directory: " << user;
236     return false;
237   }
238
239   struct group gr;
240   struct group *gr_result;
241   char buf_gr[kGRBufSize];
242   ret = getgrgid_r(pwd.pw_gid, &gr, buf_gr, sizeof(buf_gr), &gr_result);
243   if (ret != 0
244       || strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
245     return false;
246
247   LOG(DEBUG) << "Creating directories for uid: " << pwd.pw_uid << ", gid: "
248              << pwd.pw_gid;
249
250   bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
251   if (apps_rw.empty()) {
252     LOG(DEBUG) << "Directory not exists: " << apps_rw;
253     return false;
254   }
255
256   if (!CreateDirectories(apps_rw, pkgid, trusted,
257       pwd.pw_uid, pwd.pw_gid, set_permissions)) {
258     return false;
259   }
260   return true;
261 }
262
263 bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
264   bf::path base_dir = app_dir / pkgid;
265   bs::error_code error;
266   bf::remove_all(base_dir, error);
267   if (error) {
268     LOG(ERROR) << "Failed to delete directory: " << base_dir;
269     return false;
270   }
271   return true;
272 }
273
274 user_list GetUserList() {
275   GumUserService* service =
276       gum_user_service_create_sync((getuid() == 0) ? TRUE : FALSE);
277   gchar** user_type_strv = gum_user_type_to_strv(
278       GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL);
279   GumUserList* gum_user_list =
280       gum_user_service_get_user_list_sync(service, user_type_strv);
281   user_list list;
282   for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
283     uid_t uid;
284     g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
285     gid_t gid;
286     g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
287     gchar* homedir = nullptr;
288     g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
289     if (homedir == nullptr) {
290       LOG(WARNING) << "No homedir for uid: " << uid;
291       continue;
292     }
293     list.emplace_back(uid, gid, bf::path(homedir));
294   }
295   g_strfreev(user_type_strv);
296   gum_user_service_list_free(gum_user_list);
297   return list;
298 }
299
300 }  // namespace
301
302 namespace common_installer {
303
304 std::string GetDirectoryPathForInternalStorage() {
305   const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
306   if (internal_storage_prefix)
307     return std::string(internal_storage_prefix);
308   return tzplatform_getenv(TZ_SYS_HOME);
309 }
310
311 std::string GetDirectoryPathForExternalStorage() {
312   return GetExternalCardPath().string();
313 }
314
315 bool PerformInternalDirectoryCreationForUser(uid_t user,
316                                              const std::string& pkgid,
317                                              bool trusted) {
318   const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
319   const bool set_permissions = true;
320   if (!CreateUserDirectories(user, pkgid, trusted,
321                              internal_storage_prefix, set_permissions))
322     return false;
323   return true;
324 }
325
326 bool PerformExternalDirectoryCreationForUser(uid_t user,
327                                              const std::string& pkgid) {
328   bf::path storage_path = GetExternalCardPath();
329
330   // TODO(t.iwanek): trusted in this context means that we have signature
331   // this argument is not longer needed as all package must be signed
332   // so that trusted directory may be labeled correctly by security-manager in
333   // all cases. This parameter and its propagation should be removed.
334   bool trusted = true;
335
336   const bool set_permissions = false;
337   if (!bf::exists(storage_path)) {
338     LOG(WARNING) << "External storage (SD Card) is not mounted.";
339     return false;
340   }
341
342   bf::path storage_apps_path = storage_path / "apps";
343   if (!bf::exists(storage_apps_path)) {
344     bs::error_code error;
345     bf::create_directories(storage_apps_path, error);
346     if (error) {
347       LOG(ERROR) << "Failed to create directory: "
348           << storage_apps_path.c_str();
349       return false;
350     }
351   }
352
353   if (CreateUserDirectories(user, pkgid, trusted,
354                             storage_apps_path.c_str(), set_permissions)) {
355   }
356   return true;
357 }
358
359 bool PerformExternalDirectoryDeletionForUser(uid_t user,
360                                              const std::string& pkgid) {
361   bf::path storage_path = GetExternalCardPath();
362   if (!bf::exists(storage_path)) {
363     LOG(WARNING) << "External storage (SD Card) is not mounted.";
364     return false;
365   }
366
367   bf::path storage_apps_path = bf::path(storage_path) / "apps";
368   return DeleteDirectories(
369       GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
370 }
371
372 bool PerformInternalDirectoryCreationForAllUsers(const std::string& pkgid,
373                                                  bool trusted) {
374   user_list list = GetUserList();
375   for (auto l : list) {
376     if (!PerformInternalDirectoryCreationForUser(std::get<0>(l),
377                                                  pkgid,
378                                                  trusted))
379       LOG(ERROR) << "Could not create internal storage directories for user: "
380                  << std::get<0>(l);
381   }
382   return true;
383 }
384
385 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
386   user_list list = GetUserList();
387   for (auto l : list) {
388     if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
389                                                  pkgid))
390       LOG(WARNING) << "Could not create external storage directories for user: "
391                    << std::get<0>(l);
392   }
393   return true;
394 }
395
396 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
397   user_list list = GetUserList();
398   for (auto l : list) {
399     uid_t uid = std::get<0>(l);
400     LOG(DEBUG) << "Deleting directories for user: " << uid;
401     if (QueryIsPackageInstalled(pkgid, uid)) {
402       LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
403                  << " still exists. Skipping";
404       continue;
405     }
406
407     if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
408       LOG(WARNING) << "Could not delete external storage directories for user: "
409                    << uid;
410   }
411   return true;
412 }
413
414 bool CreateSkelDirectories(const std::string& pkgid) {
415   bf::path path = bf::path(kSkelAppDir) / pkgid;
416   LOG(DEBUG) << "Creating directories in: " << path;
417   bs::error_code error;
418   bf::create_directories(path, error);
419
420   if (error) {
421     LOG(ERROR) << "Failed to create directory: " << path;
422     return false;
423   }
424
425   for (auto& entry : kEntries) {
426     bf::path subpath = path / entry;
427     bf::create_directories(subpath, error);
428     if (error && !bf::exists(subpath)) {
429       LOG(ERROR) << "Failed to create directory: " << subpath;
430       return false;
431     }
432   }
433
434   std::string error_message;
435   if (!RegisterSecurityContextForPath(pkgid, path,
436       tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &error_message)) {
437     LOG(ERROR) << "Failed to register security context for path: " << path
438                << ", error_message: " << error_message;
439     return false;
440   }
441
442   return true;
443 }
444
445
446 bool DeleteSkelDirectories(const std::string& pkgid) {
447   return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
448 }
449
450
451 bool DeleteUserDirectories(const std::string& pkgid) {
452   user_list list = GetUserList();
453   for (auto l : list) {
454     if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
455       LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
456       continue;
457     }
458
459     LOG(DEBUG) << "Deleting directories of " << pkgid
460                << ", for uid: " << std::get<0>(l);
461     bf::path apps_rw(std::get<2>(l) / "apps_rw");
462     if (!DeleteDirectories(apps_rw, pkgid)) {
463       return false;
464     }
465   }
466   return true;
467 }
468
469 bool DeleteUserExternalDirectories(const std::string& pkgid) {
470   user_list list = GetUserList();
471   for (auto l : list) {
472     if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
473       LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
474       continue;
475     }
476
477     LOG(DEBUG) << "Deleting external directories of " << pkgid
478                << ", for uid: " << std::get<0>(l);
479     bf::path apps_rw(std::get<2>(l) / "apps_rw");
480     if (!DeleteDirectories(apps_rw, pkgid)) {
481       return false;
482     }
483   }
484   return true;
485 }
486
487
488 bool CopyUserDirectories(const std::string& pkgid) {
489   user_list list = GetUserList();
490   for (auto l : list) {
491     LOG(DEBUG) << "Copying directories for uid: " << std::get<0>(l);
492     bf::path apps_rw(std::get<2>(l) / "apps_rw");
493     bf::path src = bf::path(kSkelAppDir) / pkgid;
494     bf::path dst = apps_rw / pkgid;
495     if (!ci::CopyDir(src, dst))
496       continue;
497     if (!SetPackageDirectoryOwnerAndPermissions(dst, std::get<0>(l),
498         std::get<1>(l)))
499       return false;
500     for (bf::recursive_directory_iterator iter(dst);
501         iter != bf::recursive_directory_iterator(); ++iter) {
502       if (!SetPackageDirectoryOwnerAndPermissions(iter->path(),
503           std::get<0>(l), std::get<1>(l)))
504         return false;
505     }
506   }
507   return true;
508 }
509
510 ci::PkgList CreatePkgInformationList(uid_t uid,
511                                      const std::vector<std::string>& pkgs) {
512   return pkgs.empty() ?
513       GetAllGlobalAppsInformation() : GetPkgInformation(uid, *pkgs.begin());
514 }
515
516 }  // namespace common_installer