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