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