2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "common/tools.h"
19 #include <privilegemgr/privilege_manager.h>
20 #include <app_manager.h>
21 #include <pkgmgr-info.h>
23 #ifdef PRIVILEGE_USE_DB
25 #include "common/current_application.h"
26 #elif PRIVILEGE_USE_ACE
27 //#include <privilege_checker.h>
28 #elif PRIVILEGE_USE_CYNARA
31 #include <cynara/cynara-client.h>
32 #include <sys/smack.h>
35 #include "common/logger.h"
36 #include "common/scope_exit.h"
41 void ReportSuccess(picojson::object& out) {
43 out.insert(std::make_pair("status", picojson::value("success")));
46 void ReportSuccess(const picojson::value& result, picojson::object& out) {
48 out.insert(std::make_pair("status", picojson::value("success")));
49 out.insert(std::make_pair("result", result));
52 void ReportError(picojson::object& out) {
53 LoggerE("Error without error code");
54 out.insert(std::make_pair("status", picojson::value("error")));
57 void ReportError(const PlatformException& ex, picojson::object& out) {
58 LoggerE("PlatformException: %s, message: %s", ex.name().c_str(), ex.message().c_str());
59 out.insert(std::make_pair("status", picojson::value("error")));
60 out.insert(std::make_pair("error", ex.ToJSON()));
63 void ReportError(const PlatformResult& error, picojson::object* out) {
64 LoggerE("PlatformResult: %d, message: %s", error.error_code(), error.message().c_str());
65 out->insert(std::make_pair("status", picojson::value("error")));
66 out->insert(std::make_pair("error", error.ToJSON()));
71 #ifdef PRIVILEGE_USE_DB
73 class AccessControlImpl {
76 : initialized_(false) {
77 LoggerD("Privilege access checked using DB.");
79 const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
80 sqlite3* db = nullptr;
82 int ret = sqlite3_open(kWrtDBPath, &db);
83 if (SQLITE_OK != ret) {
84 LoggerE("Failed to access WRT database");
88 const char* kQuery = "select name from WidgetFeature where app_id = "
89 "(select app_id from WidgetInfo where tizen_appid = ?)"
91 const std::string app_id = common::CurrentApplication::GetInstance().GetApplicationId();
92 sqlite3_stmt* stmt = nullptr;
94 ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
95 ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
98 sqlite3_finalize(stmt);
102 if (SQLITE_OK != ret) {
103 LoggerE("Failed to query WRT database");
107 while (sqlite3_step(stmt) == SQLITE_ROW) {
108 const char* privilege = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
109 SLoggerD("Granted: %s", privilege);
110 granted_privileges_.push_back(privilege);
116 ~AccessControlImpl() {}
118 bool CheckAccess(const std::vector<std::string>& privileges) {
124 for (const auto& privilege : privileges) {
125 if (std::find(granted_privileges_.begin(), granted_privileges_.end(), privilege) == granted_privileges_.end()) {
135 std::vector<std::string> granted_privileges_;
138 #elif PRIVILEGE_USE_ACE
140 class AccessControlImpl {
142 AccessControlImpl() {
143 LoggerD("Privilege access checked using ACE.");
146 ~AccessControlImpl() {
149 bool CheckAccess(const std::vector<std::string>& privileges) {
156 #elif PRIVILEGE_USE_CYNARA
158 class AccessControlImpl {
160 AccessControlImpl() : cynara_(nullptr) {
161 LoggerD("Privilege access checked using Cynara.");
163 char* smack_label = nullptr;
164 int len= smack_new_label_from_self(&smack_label);
166 if (0 < len && nullptr != smack_label) {
169 SLoggerD("uid: [%u]", uid);
170 SLoggerD("smack label: [%s]", smack_label);
172 uid_ = std::to_string(uid);
173 smack_label_ = smack_label;
177 LoggerE("Failed to get smack label");
181 int ret = cynara_initialize(&cynara_, nullptr);
182 if (CYNARA_API_SUCCESS != ret) {
183 LoggerE("Failed to initialize Cynara");
188 ~AccessControlImpl() {
190 auto ret = cynara_finish(cynara_);
191 if (CYNARA_API_SUCCESS != ret) {
192 LoggerE("Failed to finalize Cynara");
198 bool CheckAccess(const std::vector<std::string>& privileges) {
201 for (const auto& privilege : privileges) {
202 if (CYNARA_API_ACCESS_ALLOWED != cynara_check(cynara_, // p_cynara
203 smack_label_.c_str(), // client
204 "", // client_session
205 uid_.c_str(), // user
206 privilege.c_str() // privilege
220 std::string smack_label_;
225 class AccessControlImpl {
227 AccessControlImpl() {
228 LoggerD("Privilege access - deny all.");
231 bool CheckAccess(const std::vector<std::string>& privileges) {
238 class AccessControl {
240 static AccessControl& GetInstance() {
241 static AccessControl instance;
245 bool CheckAccess(const std::string& privilege) {
246 return CheckAccess(std::vector<std::string>{privilege});
249 bool CheckAccess(const std::vector<std::string>& privileges) {
250 return impl_.CheckAccess(privileges);
256 AccessControlImpl impl_;
262 PlatformResult CheckAccess(const std::string& privilege) {
263 return CheckAccess(std::vector<std::string>{privilege});
266 PlatformResult CheckAccess(const std::vector<std::string>& privileges) {
269 // Local cache of mapped privilege strings. This routine can be called many times, especially
270 // during application launch, generating a high overhead of retrieving mapped privileges from
271 // the underlying databases. This is especially the case since the same mappings can end up
272 // being retrieved several times.
273 using MappedPrivilegeCache = std::map<std::string, std::vector<std::string>>;
274 static MappedPrivilegeCache mapped_privilege_cache;
276 std::string api_version;
277 PlatformResult res = common::tools::GetPkgApiVersion(&api_version);
281 LoggerD("Application api version: %s", api_version.c_str());
283 for (auto input_priv : privileges) {
284 LoggerD("Input privilege: %s", input_priv.c_str());
285 GList *input_glist = nullptr;
286 GList *mapped_glist = nullptr;
289 g_list_free(input_glist);
290 g_list_free(mapped_glist);
293 std::vector<std::string>* mapped_vector_ptr = nullptr;
295 // Check if mapped privilege is in local cache first
296 MappedPrivilegeCache::const_iterator it = mapped_privilege_cache.find(input_priv);
297 if (mapped_privilege_cache.end() == it) {
298 LoggerD("Mapped privileges - need to be fetched from database");
299 // Not in cache - retrieve from underlying databases.
300 input_glist = g_list_append(input_glist, (void*)input_priv.c_str());
301 int ret = privilege_manager_get_mapped_privilege_list(api_version.c_str(),
302 PRVMGR_PACKAGE_TYPE_WRT,
305 if (PRVMGR_ERR_NONE != ret) {
306 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get mapped privilege list");
309 // initialize empty cache vector
310 mapped_privilege_cache[input_priv] = std::vector<std::string>();
311 LoggerD("Mapped privileges:");
312 auto push_elem = [](gpointer data, gpointer user_data) -> void {
313 if (data && user_data) {
314 std::vector<std::string>* mapped_vector =
315 static_cast<std::vector<std::string>*>(user_data);
316 char* char_data = static_cast<char*>(data);
317 mapped_vector->push_back(char_data);
318 LoggerD("mapped to: %s", char_data);
321 // fill the vector with data
322 g_list_foreach (mapped_glist, push_elem, &mapped_privilege_cache[input_priv]);
323 mapped_vector_ptr = &mapped_privilege_cache[input_priv];
325 // Retrieve from local cache
326 LoggerD("Mapped privileges already in cache");
327 mapped_vector_ptr = (std::vector<std::string>*) &(it->second);
330 if (!AccessControl::GetInstance().CheckAccess(*mapped_vector_ptr)){
331 for (const auto& mapped_priv : *mapped_vector_ptr) {
332 LoggerD("Access to privilege: %s has been denied.", mapped_priv.c_str());
334 return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied");
337 return PlatformResult(ErrorCode::NO_ERROR);
340 PlatformResult GetPkgApiVersion(std::string* api_version) {
343 // Local cache of API version string. This can be expensive to retrieve from
344 // underlying databases and this routine can be called many times during
345 // application launch.
346 static std::string cached_api_version;
347 static int cached_pid = -1;
349 char* app_id = nullptr;
350 char* pkgid = nullptr;
351 char* api_ver = nullptr;
352 app_info_h app_handle = nullptr;
353 pkgmgrinfo_pkginfo_h pkginfo_handle = nullptr;
363 app_info_destroy(app_handle);
365 if (pkginfo_handle) {
366 pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle);
370 pid_t pid = getpid();
371 if (cached_pid == pid) {
372 *api_version = cached_api_version; // Retrieve from local cache
374 int ret = app_manager_get_app_id(pid, &app_id);
375 if (ret != APP_MANAGER_ERROR_NONE) {
376 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app id");
379 ret = app_info_create(app_id, &app_handle);
380 if (ret != APP_MANAGER_ERROR_NONE) {
381 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app info");
384 ret = app_info_get_package(app_handle, &pkgid);
385 if ((ret != APP_MANAGER_ERROR_NONE) || (pkgid == nullptr)) {
386 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkg id");
389 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, getuid(), &pkginfo_handle);
390 if (ret != PMINFO_R_OK) {
391 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkginfo_h");
394 ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo_handle, &api_ver);
395 if (ret != PMINFO_R_OK) {
396 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get api version");
399 cached_api_version = api_ver; // Save in local cache
402 *api_version = api_ver;
405 return PlatformResult(ErrorCode::NO_ERROR);
408 std::vector<std::string> SplitString(const std::string& str, const std::string& delim) {
409 std::vector<std::string> tokens;
410 size_t prev = 0, pos = 0;
413 pos = str.find(delim, prev);
414 if (pos == std::string::npos) pos = str.length();
415 std::string token = str.substr(prev, pos-prev);
416 if (!token.empty()) tokens.push_back(token);
417 prev = pos + delim.length();
419 while (pos < str.length() && prev < str.length());
423 bool IsAppVersionEarlierThan(const std::string& ver) {
426 auto res = GetPkgApiVersion(&app_ver);
428 LoggerE("Failed to get application version, "
429 "assuming that application version is same as platform");
432 std::vector<std::string> vec_app = SplitString(app_ver, ".");
433 std::vector<std::string> vec_ref = SplitString(ver, ".");
435 size_t length = std::min(vec_app.size(), vec_ref.size());
436 for (size_t i = 0; i < length; ++i) {
437 int num_ver = std::stoi(vec_ref[i]);
438 int num_app = std::stoi(vec_app[i]);
439 if (num_app < num_ver) {
441 } else if (num_app > num_ver) {
448 std::string GetErrorString(int error_code) {
449 static const size_t kSize = 1024;
450 char msg[kSize] = {0};
451 strerror_r(error_code, msg, kSize);
456 int HexToInt(char c) {
457 if (c >= '0' && c <= '9') {
459 } else if (c >= 'A' && c <= 'Z') {
466 unsigned char* HexToBin(const char* hex, int size, unsigned char* bin, int bin_size) {
467 for (int i = 0; i < size - 1 && i / 2 < bin_size; i += 2) {
468 bin[i / 2] = HexToInt(hex[i]) << 4;
469 bin[i / 2] |= HexToInt(hex[i + 1]);
474 char* BinToHex(const unsigned char* bin, int size, char* hex, int hex_size) {
475 static const char * const digits = "0123456789ABCDEF";
476 for (int i = 0; i < size && i < hex_size / 2; i++) {
477 hex[i * 2] = digits[bin[i] >> 4];
478 hex[i * 2 + 1] = digits[bin[i] & 0xF];
484 } // namespace common