Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / security_registration.cc
1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/security_registration.h"
6
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <manifest_parser/utils/logging.h>
10 #include <security-manager.h>
11 #include <tzplatform_config.h>
12
13 #include <utility>
14 #include <vector>
15 #include <algorithm>
16 #include <functional>
17
18 #include "common/utils/pkgmgr_query.h"
19 #include "common/privileges.h"
20 #include "common/utils/file_util.h"
21 #include "common/utils/glist_range.h"
22
23 namespace fs = std::filesystem;
24 namespace ci = common_installer;
25
26 namespace {
27
28 using AppDefinedPrivInfo = std::vector<std::pair<std::string, std::string>>;
29
30 const std::vector<std::pair<const char*,
31                             app_install_path_type>> kSecurityPolicies = {
32   {".", SECURITY_MANAGER_PATH_PUBLIC_RO},
33   {"bin", SECURITY_MANAGER_PATH_RO},
34   {"data", SECURITY_MANAGER_PATH_RW},
35   {"cache", SECURITY_MANAGER_PATH_RW},
36   {"lib", SECURITY_MANAGER_PATH_RO},
37   {"res", SECURITY_MANAGER_PATH_RO},
38   {"res/global", SECURITY_MANAGER_PATH_PUBLIC_RO},
39   {"res/allowed", SECURITY_MANAGER_PATH_PUBLIC_RO},
40   {"shared", SECURITY_MANAGER_PATH_PUBLIC_RO},
41   {"shared/data", SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO},
42   {"shared/cache", SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO},
43   {"shared/trusted", SECURITY_MANAGER_PATH_TRUSTED_RW},
44   {"tep", SECURITY_MANAGER_PATH_RO},
45   {".image", SECURITY_MANAGER_PATH_RO},
46   {"tmp", SECURITY_MANAGER_PATH_RW},
47   {".mmc", SECURITY_MANAGER_PATH_RO}
48 };
49
50 const std::vector<std::pair<const char*,
51                 app_install_path_type>> kSecurityPoliciesExternalOnly = {
52   {"bin", SECURITY_MANAGER_PATH_RO},
53   {"lib", SECURITY_MANAGER_PATH_RO},
54   {"res", SECURITY_MANAGER_PATH_RO},
55   {".mmc", SECURITY_MANAGER_PATH_RO}
56 };
57
58 const std::vector<std::pair<const char*, app_install_type>> kPathPolicies = {
59   {tzplatform_getenv(TZ_SYS_HOME), SM_APP_INSTALL_LOCAL},
60   {tzplatform_getenv(TZ_SYS_RW_APP), SM_APP_INSTALL_GLOBAL},
61   {tzplatform_getenv(TZ_SYS_RO_APP), SM_APP_INSTALL_PRELOADED},
62   {tzplatform_mkpath(TZ_SYS_ETC, "skel"), SM_APP_INSTALL_PRELOADED},
63 };
64
65 void SetErrorMessage(std::string* error_message, int error) {
66   std::string errnum = std::to_string(error);
67   *error_message = security_manager_strerror(static_cast<lib_retcode>(error));
68   *error_message += ":<" + errnum + ">";
69 }
70
71 class SecurityContextRequest {
72  public:
73   SecurityContextRequest(): req_(nullptr), app_idx_(0) {
74     int error = security_manager_app_inst_req_new(&req_);
75       if (error != SECURITY_MANAGER_SUCCESS) {
76         LOG(ERROR)
77             << "Failed while calling security_manager_app_inst_req_new "
78             << "(error code: " << error << ")";
79         SetErrorMessage(&error_message_, error);
80         req_ = NULL;
81       }
82   }
83   ~SecurityContextRequest() {
84     if (IsValid())
85       security_manager_app_inst_req_free(req_);
86   }
87   bool IsValid() const {
88     return req_ != NULL;
89   }
90   bool PrepareBasic(const std::string& pkg_id, uid_t uid,
91       const std::string& type) {
92     if (pkg_id.empty() || type.empty()) {
93       LOG(ERROR) << "Invalid parameter";
94       return false;
95     }
96     int error = security_manager_app_inst_req_set_pkg_id(req_, pkg_id.c_str());
97     if (error != SECURITY_MANAGER_SUCCESS) {
98       SetErrorMessage(&error_message_, error);
99       return false;
100     }
101     error = security_manager_app_inst_req_set_uid(req_, uid);
102     if (error != SECURITY_MANAGER_SUCCESS) {
103       SetErrorMessage(&error_message_, error);
104       return false;
105     }
106
107     pkg_type pkgtype = SM_PKG_TYPE_NONE;
108     if (type == "tpk")
109       pkgtype = SM_PKG_TYPE_CORE;
110     else if (type == "wgt")
111       pkgtype = SM_PKG_TYPE_WRT;
112
113     error = security_manager_app_inst_req_set_pkg_type(req_, pkgtype);
114     if (error != SECURITY_MANAGER_SUCCESS) {
115       SetErrorMessage(&error_message_, error);
116       return false;
117     }
118     return true;
119   }
120
121   bool PrepareAdditional(const std::string& author_id,
122       const std::string& api_version,
123       const std::filesystem::path& path,
124       bool cross_app_rules) {
125     if (cross_app_rules) {
126       int error = security_manager_app_inst_req_set_hybrid(req_);
127       if (error != SECURITY_MANAGER_SUCCESS) {
128         SetErrorMessage(&error_message_, error);
129         return false;
130       }
131     }
132     if (!api_version.empty()) {
133       int error = security_manager_app_inst_req_set_target_version(req_,
134           api_version.c_str());
135       if (error != SECURITY_MANAGER_SUCCESS) {
136         SetErrorMessage(&error_message_, error);
137         return false;
138       }
139     }
140     if (!author_id.empty()) {
141       int error = security_manager_app_inst_req_set_author_id(req_,
142           author_id.c_str());
143       if (error != SECURITY_MANAGER_SUCCESS) {
144         SetErrorMessage(&error_message_, error);
145         return false;
146       }
147     }
148     if (!path.empty()) {
149       app_install_type type = SM_APP_INSTALL_NONE;
150       for (auto& policy : kPathPolicies) {
151         fs::path root = fs::path(policy.first);
152         if (ci::IsSubDir(path, root)) {
153           type = policy.second;
154           break;
155         }
156       }
157       if (type == SM_APP_INSTALL_NONE) {
158         LOG(ERROR) << "Unexpected path: " << path;
159         return false;
160       }
161
162       LOG(INFO) << "install_type(" << type << ")";
163       int error = security_manager_app_inst_req_set_install_type(req_, type);
164       if (error != SECURITY_MANAGER_SUCCESS) {
165         SetErrorMessage(&error_message_, error);
166         return false;
167       }
168     }
169     return true;
170   }
171
172   bool PreparePrivilegeLevel(ci::PrivilegeLevel priv_level) {
173     pkg_privilege_level level = (pkg_privilege_level)priv_level;
174     int error = security_manager_app_inst_req_set_pkg_privilege_level(
175         req_, level);
176     if (error != SECURITY_MANAGER_SUCCESS) {
177       SetErrorMessage(&error_message_, error);
178       return false;
179     }
180     return true;
181   }
182
183   bool PrepareAppWithPrivileges(const std::string& app_id,
184       const std::vector<std::string>& privileges,
185       const AppDefinedPrivInfo& appdef_privileges,
186       const AppDefinedPrivInfo& provides_appdef_privileges) {
187     if (!PrepareApp(app_id))
188       return false;
189     return PrepareAppPrivileges(privileges, appdef_privileges,
190         provides_appdef_privileges);
191   }
192
193   bool PrepareAppPrivileges(const std::vector<std::string>& privileges,
194       const AppDefinedPrivInfo& appdef_privileges,
195       const AppDefinedPrivInfo& provides_appdef_privileges) {
196     for (auto& priv : privileges) {
197       int error = security_manager_app_inst_req_add_privilege(req_,
198                                                               priv.c_str());
199       if (error != SECURITY_MANAGER_SUCCESS) {
200         SetErrorMessage(&error_message_, error);
201         return false;
202       }
203     }
204     for (auto& priv : appdef_privileges) {
205       int error = security_manager_app_inst_req_add_client_privilege(
206           req_, priv.first.c_str(), priv.second.c_str());
207       if (error != SECURITY_MANAGER_SUCCESS) {
208         SetErrorMessage(&error_message_, error);
209         return false;
210       }
211     }
212     // only one app can provide appdefined privileges
213     if (app_idx_ > 1)
214       return true;
215     for (auto& priv : provides_appdef_privileges) {
216       auto privilege_type = !priv.second.empty() ?
217                             SM_APP_DEFINED_PRIVILEGE_TYPE_LICENSED :
218                             SM_APP_DEFINED_PRIVILEGE_TYPE_UNTRUSTED;
219       int error = security_manager_app_inst_req_add_app_defined_privilege(req_,
220           priv.first.c_str(), privilege_type, priv.second.c_str());
221       if (error != SECURITY_MANAGER_SUCCESS) {
222         SetErrorMessage(&error_message_, error);
223         return false;
224       }
225     }
226     return true;
227   }
228
229   bool PrepareApp(const std::string& app_id) {
230     if (app_id.empty()) {
231       LOG(ERROR) << "Appid is empty.";
232       return false;
233     }
234     // req_->apps.emplace_back();
235     if (app_idx_ > 0) {
236       int error = security_manager_app_inst_req_next(req_);
237       if (error != SECURITY_MANAGER_SUCCESS) {
238         SetErrorMessage(&error_message_, error);
239         return false;
240       }
241     }
242     // req_->apps.back().id = ...
243     int error = security_manager_app_inst_req_set_app_id(req_, app_id.c_str());
244     if (error != SECURITY_MANAGER_SUCCESS) {
245       SetErrorMessage(&error_message_, error);
246       return false;
247     }
248     ++app_idx_;
249     return true;
250   }
251
252   bool Install() {
253     int error = security_manager_app_update(req_);
254     if (error != SECURITY_MANAGER_SUCCESS) {
255       LOG(ERROR) << "Failed while calling  security_manager_app_update failed "
256                  << "(error code: " << error << ")";
257       SetErrorMessage(&error_message_, error);
258       return false;
259     }
260     return true;
261   }
262
263   bool Uninstall() {
264     int error = security_manager_app_uninstall(req_);
265     if (error != SECURITY_MANAGER_SUCCESS) {
266       LOG(ERROR) << "Failed while calling  security_manager_app_uninstall "
267                  << "failed (error code: " << error << ")";
268       SetErrorMessage(&error_message_, error);
269       return false;
270     }
271     return true;
272   }
273
274   const std::string& ErrorMessage() const {
275     return error_message_;
276   }
277
278  private:
279   app_inst_req* req_;
280   uint app_idx_;
281   std::string error_message_;
282 };
283
284 class SecurityContextPathRequest {
285  public:
286   SecurityContextPathRequest() {
287     int error = security_manager_path_req_new(&req_);
288     if (error != SECURITY_MANAGER_SUCCESS) {
289       LOG(ERROR)
290           << "Failed while calling security_manager_path_req_new failed "
291           << "(error code: " << error << ")";
292       SetErrorMessage(&error_message_, error);
293       req_ = NULL;
294     }
295   }
296
297   ~SecurityContextPathRequest() {
298     if (IsValid())
299       security_manager_path_req_free(req_);
300   }
301
302   bool IsValid() {
303     return req_ != NULL;
304   }
305
306   bool Prepare(const std::string& pkg_id, uid_t uid) {
307     if (pkg_id.empty()) {
308       LOG(ERROR) << "Pkgid is empty. This value must be set";
309       return false;
310     }
311     int error = security_manager_path_req_set_pkg_id(req_, pkg_id.c_str());
312     if (error != SECURITY_MANAGER_SUCCESS) {
313       SetErrorMessage(&error_message_, error);
314       return false;
315     }
316     error = security_manager_path_req_set_uid(req_, uid);
317     if (error != SECURITY_MANAGER_SUCCESS) {
318       SetErrorMessage(&error_message_, error);
319       return false;
320     }
321     return true;
322   }
323
324   bool PreparePath(const std::string& pkg_type,
325       const std::filesystem::path& path, bool is_readonly_pkg,
326       bool is_extonly) {
327     if (path.empty()) {
328       LOG(ERROR) << "Path is empty. This value must be set";
329       return false;
330     }
331     app_install_type type = SM_APP_INSTALL_NONE;
332     for (auto& policy : kPathPolicies) {
333       fs::path root = fs::path(policy.first);
334       if (ci::IsSubDir(path, root)) {
335         type = policy.second;
336         break;
337       }
338     }
339     if (type == SM_APP_INSTALL_NONE) {
340       LOG(ERROR) << "Unexpected path: " << path;
341       return false;
342     }
343     // When registering skel dir on global installation mode
344     if (type == SM_APP_INSTALL_PRELOADED && !is_readonly_pkg)
345       type = SM_APP_INSTALL_GLOBAL;
346
347     int error = security_manager_path_req_set_install_type(req_, type);
348     if (error != SECURITY_MANAGER_SUCCESS) {
349       SetErrorMessage(&error_message_, error);
350       return false;
351     }
352     std::vector<std::pair<const char*, app_install_path_type>> policies;
353     if (is_extonly)
354       policies = kSecurityPoliciesExternalOnly;
355     else
356       policies = kSecurityPolicies;
357     for (auto& policy : policies) {
358       fs::path subpath = path / policy.first;
359       if (is_extonly) {
360         // Now, this is for legacy migraton.
361         // do not try to access any file before changing label,
362         // this wil cause a exception from smack denial.
363         std::string subdir(policy.first);
364         if (pkg_type == "wgt" && (subdir == "bin" || subdir == "lib"))
365           continue;
366       } else {
367         if (!fs::exists(subpath))
368           continue;
369         if (fs::is_symlink(symlink_status(subpath)) &&
370             policy.second != SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO) {
371           LOG(DEBUG) << "Path " << subpath << " is a symlink."
372                      << "Path will not be registered";
373           continue;
374         }
375       }
376       error = security_manager_path_req_add_path(req_, subpath.c_str(),
377           policy.second);
378       if (error != SECURITY_MANAGER_SUCCESS) {
379         SetErrorMessage(&error_message_, error);
380         return false;
381       }
382
383       // this is for lib rpk installation. set public RO for contents only.
384       if (pkg_type == "rpk" && std::string(policy.first) == "lib") {
385         for (fs::directory_iterator iter(subpath);
386             iter != fs::directory_iterator(); ++iter) {
387           error = security_manager_path_req_add_path(req_,
388               iter->path().string().c_str(), SECURITY_MANAGER_PATH_PUBLIC_RO);
389           if (error!= SECURITY_MANAGER_SUCCESS) {
390             SetErrorMessage(&error_message_, error);
391             return false;
392           }
393         }
394       }
395     }
396     return true;
397   }
398
399   bool Register() {
400     int error = security_manager_paths_register(req_);
401     if (error != SECURITY_MANAGER_SUCCESS) {
402       LOG(ERROR) << "Failed while calling  security_manager_paths_register "
403                  << "failed (error code: " << error << ")";
404       SetErrorMessage(&error_message_, error);
405       return false;
406     }
407     return true;
408   }
409
410   const std::string& ErrorMessage() const {
411     return error_message_;
412   }
413
414  private:
415   path_req* req_;
416   std::string error_message_;
417 };
418
419 }  // namespace
420
421 namespace common_installer {
422
423 void PrepareAppDefinedPrivilegeData(GList *privileges,
424     AppDefinedPrivInfo* tpk_priv_vec, AppDefinedPrivInfo* wgt_priv_vec) {
425
426   for (auto& priv : GListRange<appdefined_privilege_x*>(privileges)) {
427     if (strcmp(priv->type, kWebPrivilegeType) == 0)
428       wgt_priv_vec->emplace_back(std::make_pair(priv->value, priv->license ?
429           priv->license : std::string()));
430     else
431       tpk_priv_vec->emplace_back(std::make_pair(priv->value, priv->license ?
432           priv->license : std::string()));
433   }
434 }
435
436 bool RegisterSecurityContextForManifest(const ci::InstallerContext* context,
437     std::string* error_message) {
438   std::string pkg_id = context->pkgid.get();
439   std::string pkg_type = context->pkg_type.get();
440   fs::path path = context->GetPkgPath();
441   uid_t uid = context->uid.get();
442   const ci::CertificateInfo* cert_info = &(context->certificate_info.get());
443   manifest_x* manifest = context->manifest_data.get();
444   bool cross_app_rules = context->cross_app_rules.get();
445
446   // Although application framework hold list of privilege per package, there
447   // is situation where we need to filter privileges. This data model doesn't
448   // cover hybrid apps well where native privileges should be granted only to
449   // native app and web privileges should be granted only to web applications.
450   std::vector<std::string> tpk_priv_vec;
451   std::vector<std::string> wgt_priv_vec;
452   for (auto& priv : GListRange<privilege_x*>(manifest->privileges)) {
453     if (strcmp(priv->type, kWebPrivilegeType) == 0)
454       wgt_priv_vec.emplace_back(priv->value);
455     else
456       tpk_priv_vec.emplace_back(priv->value);
457   }
458   AppDefinedPrivInfo tpk_appdef_vec, wgt_appdef_vec;
459   AppDefinedPrivInfo tpk_provides_appdef_vec, wgt_provides_appdef_vec;
460
461   PrepareAppDefinedPrivilegeData(manifest->appdefined_privileges,
462       &tpk_appdef_vec, &wgt_appdef_vec);
463   PrepareAppDefinedPrivilegeData(manifest->provides_appdefined_privileges,
464       &tpk_provides_appdef_vec, &wgt_provides_appdef_vec);
465
466   SecurityContextRequest req;
467   if (!req.IsValid()) {
468     *error_message = req.ErrorMessage();
469     return false;
470   }
471   if (!req.PrepareBasic(pkg_id, uid, pkg_type)) {
472     *error_message = req.ErrorMessage();
473     return false;
474   }
475   if (!req.PrepareAdditional(cert_info->author_id.get(), manifest->api_version,
476       path, cross_app_rules)) {
477     *error_message = req.ErrorMessage();
478     return false;
479   }
480
481   if (!req.PreparePrivilegeLevel(context->privilege_level.get())) {
482     *error_message = req.ErrorMessage();
483     return false;
484   }
485
486   for (application_x* app : GListRange<application_x*>(manifest->application)) {
487     if (!app->appid) {
488       return false;
489     }
490
491     bool is_web_priv = strcmp(app->type, "webapp") == 0;
492     if (!req.PrepareAppWithPrivileges(app->appid,
493         is_web_priv ? wgt_priv_vec : tpk_priv_vec,
494         is_web_priv ? wgt_appdef_vec : tpk_appdef_vec,
495         is_web_priv ? wgt_provides_appdef_vec : tpk_provides_appdef_vec)) {
496       *error_message = req.ErrorMessage();
497       return false;
498     }
499   }
500
501   if (!manifest->application)
502     req.PrepareApp(pkg_id);
503
504   bool result = req.Install();
505   *error_message = req.ErrorMessage();
506   return result;
507 }
508
509 static bool UnregisterSecurityContext(const std::string& pkg_id,
510     const std::string& pkg_type,  uid_t uid,
511     const std::vector<std::string>& appids, std::string* error_message) {
512   SecurityContextRequest req;
513   if (!req.IsValid()) {
514     *error_message = req.ErrorMessage();
515     return false;
516   }
517   if (!req.PrepareBasic(pkg_id, uid, pkg_type)) {
518     *error_message = req.ErrorMessage();
519     return false;
520   }
521
522   for (const auto& appid : appids) {
523     if (!req.PrepareApp(appid)) {
524       return false;
525     }
526   }
527
528   if (appids.empty())
529     req.PrepareApp(pkg_id);
530
531   bool result = req.Uninstall();
532   *error_message = req.ErrorMessage();
533   return result;
534 }
535
536 bool UnregisterSecurityContextForManifest(const std::string& pkg_id,
537     const std::string& pkg_type, uid_t uid, manifest_x* manifest,
538     std::string* error_message) {
539   std::vector<std::string> appids;
540   for (application_x* app : GListRange<application_x*>(manifest->application)) {
541     if (!app->appid) {
542       return false;
543     }
544     appids.emplace_back(app->appid);
545   }
546   return UnregisterSecurityContext(pkg_id, pkg_type, uid,
547       appids, error_message);
548 }
549
550 bool UnregisterSecurityContextForPkgId(const std::string &pkg_id,
551     const std::string& pkg_type, uid_t uid,
552     std::string* error_message, bool ignore_data_absence) {
553   std::vector<std::string> appids;
554   ci::PkgQueryInterface pkg_query(pkg_id, uid);
555   if (!pkg_query.AppidsForPkgId(&appids))
556     return ignore_data_absence;
557   return UnregisterSecurityContext(pkg_id, pkg_type, uid,
558       appids, error_message);
559 }
560
561 bool RegisterSecurityContextForPath(const std::string &pkg_id,
562     const std::string& pkg_type, const std::filesystem::path& path,
563     uid_t uid, bool is_readonly_pkg, std::string* error_message) {
564   SecurityContextPathRequest req;
565   if (!req.IsValid()) {
566     *error_message = req.ErrorMessage();
567     return false;
568   }
569   if (!req.Prepare(pkg_id, uid)) {
570     *error_message = req.ErrorMessage();
571     return false;
572   }
573   if (!req.PreparePath(pkg_type, path, is_readonly_pkg, false)) {
574     *error_message = req.ErrorMessage();
575     return false;
576   }
577   bool result = req.Register();
578   *error_message = req.ErrorMessage();
579   return result;
580 }
581
582 bool RegisterSecurityContextForPathExternalOnly(const std::string &pkg_id,
583     const std::string &pkg_type, const std::filesystem::path& path,
584     uid_t uid, std::string* error_message) {
585   SecurityContextPathRequest req;
586   if (!req.IsValid()) {
587     *error_message = req.ErrorMessage();
588     return false;
589   }
590   if (!req.Prepare(pkg_id, uid)) {
591     *error_message = req.ErrorMessage();
592     return false;
593   }
594   if (!req.PreparePath(pkg_type, path, false, true)) {
595     *error_message = req.ErrorMessage();
596     return false;
597   }
598   bool result = req.Register();
599   *error_message = req.ErrorMessage();
600   return result;
601 }
602
603 bool HasOwnerRwOtherRoPaths(const std::filesystem::path& path) {
604   for (auto& policy : kSecurityPolicies) {
605     if (policy.second != SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO)
606       continue;
607
608     fs::path subpath = path / policy.first;
609     LOG(ERROR) << "subpath : " << subpath;
610     if (fs::exists(subpath))
611       return true;
612   }
613
614   return false;
615 }
616
617 }  // namespace common_installer