Fix smack labeling for lib rpk
[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       // this is for lib rpk installation. set public RO for contents only.
387       if (pkg_type == "rpk" && std::string(policy.first) == "lib") {
388         for (bf::directory_iterator iter(subpath);
389             iter != bf::directory_iterator(); ++iter) {
390           error = security_manager_path_req_add_path(req_,
391               iter->path().string().c_str(), SECURITY_MANAGER_PATH_PUBLIC_RO);
392           if (error!= SECURITY_MANAGER_SUCCESS) {
393             SetErrorMessage(&error_message_, error);
394             return false;
395           }
396         }
397       }
398     }
399     return true;
400   }
401
402   bool Register() {
403     int error = security_manager_paths_register(req_);
404     if (error != SECURITY_MANAGER_SUCCESS) {
405       LOG(ERROR) << "Failed while calling  security_manager_paths_register "
406                  << "failed (error code: " << error << ")";
407       SetErrorMessage(&error_message_, error);
408       return false;
409     }
410     return true;
411   }
412
413   const std::string& ErrorMessage() const {
414     return error_message_;
415   }
416
417  private:
418   path_req* req_;
419   std::string error_message_;
420 };
421
422 }  // namespace
423
424 namespace common_installer {
425
426 void PrepareAppDefinedPrivilegeData(GList *privileges,
427     AppDefinedPrivInfo* tpk_priv_vec, AppDefinedPrivInfo* wgt_priv_vec) {
428
429   for (auto& priv : GListRange<appdefined_privilege_x*>(privileges)) {
430     if (strcmp(priv->type, kWebPrivilegeType) == 0)
431       wgt_priv_vec->emplace_back(std::make_pair(priv->value, priv->license ?
432           priv->license : std::string()));
433     else
434       tpk_priv_vec->emplace_back(std::make_pair(priv->value, priv->license ?
435           priv->license : std::string()));
436   }
437 }
438
439 bool RegisterSecurityContextForManifest(const ci::InstallerContext* context,
440     std::string* error_message) {
441   std::string pkg_id = context->pkgid.get();
442   std::string pkg_type = context->pkg_type.get();
443   bf::path path = context->GetPkgPath();
444   uid_t uid = context->uid.get();
445   const ci::CertificateInfo* cert_info = &(context->certificate_info.get());
446   manifest_x* manifest = context->manifest_data.get();
447   bool cross_app_rules = context->cross_app_rules.get();
448
449   // Although application framework hold list of privilege per package, there
450   // is situation where we need to filter privileges. This data model doesn't
451   // cover hybrid apps well where native privileges should be granted only to
452   // native app and web privileges should be granted only to web applications.
453   std::vector<std::string> tpk_priv_vec;
454   std::vector<std::string> wgt_priv_vec;
455   for (auto& priv : GListRange<privilege_x*>(manifest->privileges)) {
456     if (strcmp(priv->type, kWebPrivilegeType) == 0)
457       wgt_priv_vec.emplace_back(priv->value);
458     else
459       tpk_priv_vec.emplace_back(priv->value);
460   }
461   AppDefinedPrivInfo tpk_appdef_vec, wgt_appdef_vec;
462   AppDefinedPrivInfo tpk_provides_appdef_vec, wgt_provides_appdef_vec;
463
464   PrepareAppDefinedPrivilegeData(manifest->appdefined_privileges,
465       &tpk_appdef_vec, &wgt_appdef_vec);
466   PrepareAppDefinedPrivilegeData(manifest->provides_appdefined_privileges,
467       &tpk_provides_appdef_vec, &wgt_provides_appdef_vec);
468
469   SecurityContextRequest req;
470   if (!req.IsValid()) {
471     *error_message = req.ErrorMessage();
472     return false;
473   }
474   if (!req.PrepareBasic(pkg_id, uid, pkg_type)) {
475     *error_message = req.ErrorMessage();
476     return false;
477   }
478   if (!req.PrepareAdditional(cert_info->author_id.get(), manifest->api_version,
479       path, cross_app_rules)) {
480     *error_message = req.ErrorMessage();
481     return false;
482   }
483
484   if (!req.PreparePrivilegeLevel(context->privilege_level.get())) {
485     *error_message = req.ErrorMessage();
486     return false;
487   }
488
489   for (application_x* app : GListRange<application_x*>(manifest->application)) {
490     if (!app->appid) {
491       return false;
492     }
493
494     bool is_web_priv = strcmp(app->type, "webapp") == 0;
495     if (!req.PrepareAppWithPrivileges(app->appid,
496         is_web_priv ? wgt_priv_vec : tpk_priv_vec,
497         is_web_priv ? wgt_appdef_vec : tpk_appdef_vec,
498         is_web_priv ? wgt_provides_appdef_vec : tpk_provides_appdef_vec)) {
499       *error_message = req.ErrorMessage();
500       return false;
501     }
502   }
503
504   if (!manifest->application)
505     req.PrepareApp(pkg_id);
506
507   bool result = req.Install();
508   *error_message = req.ErrorMessage();
509   return result;
510 }
511
512 static bool UnregisterSecurityContext(const std::string& pkg_id,
513     const std::string& pkg_type,  uid_t uid,
514     const std::vector<std::string>& appids, std::string* error_message) {
515   SecurityContextRequest req;
516   if (!req.IsValid()) {
517     *error_message = req.ErrorMessage();
518     return false;
519   }
520   if (!req.PrepareBasic(pkg_id, uid, pkg_type)) {
521     *error_message = req.ErrorMessage();
522     return false;
523   }
524
525   for (const auto& appid : appids) {
526     if (!req.PrepareApp(appid)) {
527       return false;
528     }
529   }
530
531   if (appids.empty())
532     req.PrepareApp(pkg_id);
533
534   bool result = req.Uninstall();
535   *error_message = req.ErrorMessage();
536   return result;
537 }
538
539 bool UnregisterSecurityContextForManifest(const std::string& pkg_id,
540     const std::string& pkg_type, uid_t uid, manifest_x* manifest,
541     std::string* error_message) {
542   std::vector<std::string> appids;
543   for (application_x* app : GListRange<application_x*>(manifest->application)) {
544     if (!app->appid) {
545       return false;
546     }
547     appids.emplace_back(app->appid);
548   }
549   return UnregisterSecurityContext(pkg_id, pkg_type, uid,
550       appids, error_message);
551 }
552
553 bool UnregisterSecurityContextForPkgId(const std::string &pkg_id,
554     const std::string& pkg_type, uid_t uid,
555     std::string* error_message, bool ignore_data_absence) {
556   std::vector<std::string> appids;
557   ci::PkgQueryInterface pkg_query(pkg_id, uid);
558   if (!pkg_query.AppidsForPkgId(&appids))
559     return ignore_data_absence;
560   return UnregisterSecurityContext(pkg_id, pkg_type, uid,
561       appids, error_message);
562 }
563
564 bool RegisterSecurityContextForPath(const std::string &pkg_id,
565     const std::string& pkg_type, const boost::filesystem::path& path,
566     uid_t uid, bool is_readonly_pkg, std::string* error_message) {
567   SecurityContextPathRequest req;
568   if (!req.IsValid()) {
569     *error_message = req.ErrorMessage();
570     return false;
571   }
572   if (!req.Prepare(pkg_id, uid)) {
573     *error_message = req.ErrorMessage();
574     return false;
575   }
576   if (!req.PreparePath(pkg_type, path, is_readonly_pkg, false)) {
577     *error_message = req.ErrorMessage();
578     return false;
579   }
580   bool result = req.Register();
581   *error_message = req.ErrorMessage();
582   return result;
583 }
584
585 bool RegisterSecurityContextForPathExternalOnly(const std::string &pkg_id,
586     const std::string &pkg_type, const boost::filesystem::path& path,
587     uid_t uid, std::string* error_message) {
588   SecurityContextPathRequest req;
589   if (!req.IsValid()) {
590     *error_message = req.ErrorMessage();
591     return false;
592   }
593   if (!req.Prepare(pkg_id, uid)) {
594     *error_message = req.ErrorMessage();
595     return false;
596   }
597   if (!req.PreparePath(pkg_type, path, false, true)) {
598     *error_message = req.ErrorMessage();
599     return false;
600   }
601   bool result = req.Register();
602   *error_message = req.ErrorMessage();
603   return result;
604 }
605
606 bool HasOwnerRwOtherRoPaths(const boost::filesystem::path& path) {
607   for (auto& policy : kSecurityPolicies) {
608     if (policy.second != SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO)
609       continue;
610
611     bf::path subpath = path / policy.first;
612     LOG(ERROR) << "subpath : " << subpath;
613     if (bf::exists(subpath))
614       return true;
615   }
616
617   return false;
618 }
619
620 }  // namespace common_installer