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