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 <app_manager.h>
20 #include <pkgmgr-info.h>
21 #include <privilegemgr/privilege_manager.h>
24 #ifdef PRIVILEGE_USE_DB
26 #include "common/current_application.h"
27 #elif PRIVILEGE_USE_ACE
28 //#include <privilege_checker.h>
29 #elif PRIVILEGE_USE_CYNARA
32 #include <cynara/cynara-client.h>
33 #include <sys/smack.h>
36 #include "common/logger.h"
37 #include "common/scope_exit.h"
42 void ReportSuccess(picojson::object& out) {
44 out.insert(std::make_pair("status", picojson::value("success")));
47 void ReportSuccess(const picojson::value& result, picojson::object& out) {
49 out.insert(std::make_pair("status", picojson::value("success")));
50 out.insert(std::make_pair("result", result));
53 void ReportError(picojson::object& out) {
54 LoggerE("Error without error code");
55 out.insert(std::make_pair("status", picojson::value("error")));
58 void ReportError(const PlatformException& ex, picojson::object& out) {
59 LoggerE("PlatformException: %s, message: %s", ex.name().c_str(), ex.message().c_str());
60 out.insert(std::make_pair("status", picojson::value("error")));
61 out.insert(std::make_pair("error", ex.ToJSON()));
64 void ReportError(const PlatformResult& error, picojson::object* out) {
65 LoggerE("PlatformResult: %d, message: %s", static_cast<int>(error.error_code()),
66 error.message().c_str());
67 out->insert(std::make_pair("status", picojson::value("error")));
68 out->insert(std::make_pair("error", error.ToJSON()));
73 #ifdef PRIVILEGE_USE_DB
75 class AccessControlImpl {
77 AccessControlImpl() : initialized_(false) {
78 ScopeLogger("Privilege access checked using DB.");
80 const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
81 sqlite3* db = nullptr;
83 int ret = sqlite3_open(kWrtDBPath, &db);
84 if (SQLITE_OK != ret) {
85 LoggerE("Failed to access WRT database");
90 "select name from WidgetFeature where app_id = "
91 "(select app_id from WidgetInfo where tizen_appid = ?)"
93 const std::string app_id = common::CurrentApplication::GetInstance().GetApplicationId();
94 sqlite3_stmt* stmt = nullptr;
96 ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
97 ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
100 sqlite3_finalize(stmt);
104 if (SQLITE_OK != ret) {
105 LoggerE("Failed to query WRT database");
109 while (sqlite3_step(stmt) == SQLITE_ROW) {
110 const char* privilege = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
111 SLoggerD("Granted: %s", privilege);
112 granted_privileges_.push_back(privilege);
118 ~AccessControlImpl() {
121 bool CheckAccess(const std::vector<std::string>& privileges) {
127 for (const auto& privilege : privileges) {
128 if (std::find(granted_privileges_.begin(), granted_privileges_.end(), privilege) ==
129 granted_privileges_.end()) {
139 std::vector<std::string> granted_privileges_;
142 #elif PRIVILEGE_USE_ACE
144 class AccessControlImpl {
146 AccessControlImpl() {
147 LoggerD("Privilege access checked using ACE.");
150 ~AccessControlImpl() {
153 bool CheckAccess(const std::vector<std::string>& privileges) {
160 #elif PRIVILEGE_USE_CYNARA
162 class AccessControlImpl {
164 AccessControlImpl() : cynara_(nullptr) {
165 ScopeLogger("Privilege access checked using Cynara.");
167 char* smack_label = nullptr;
168 int len = smack_new_label_from_self(&smack_label);
170 if (0 < len && nullptr != smack_label) {
173 SLoggerD("uid: [%u]", uid);
174 SLoggerD("smack label: [%s]", smack_label);
176 uid_ = std::to_string(uid);
177 smack_label_ = smack_label;
181 LoggerE("Failed to get smack label");
185 int ret = cynara_initialize(&cynara_, nullptr);
186 if (CYNARA_API_SUCCESS != ret) {
187 LoggerE("Failed to initialize Cynara");
192 ~AccessControlImpl() {
194 auto ret = cynara_finish(cynara_);
195 if (CYNARA_API_SUCCESS != ret) {
196 LoggerE("Failed to finalize Cynara");
202 bool CheckAccess(const std::vector<std::string>& privileges) {
204 for (const auto& privilege : privileges) {
205 if (CYNARA_API_ACCESS_ALLOWED != cynara_check(cynara_, // p_cynara
206 smack_label_.c_str(), // client
207 "", // client_session
208 uid_.c_str(), // user
209 privilege.c_str()) // privilege
223 std::string smack_label_;
228 class AccessControlImpl {
230 AccessControlImpl() {
231 LoggerD("Privilege access - deny all.");
234 bool CheckAccess(const std::vector<std::string>& privileges) {
241 class AccessControl {
243 static AccessControl& GetInstance() {
244 static AccessControl instance;
248 bool CheckAccess(const std::string& privilege) {
249 return CheckAccess(std::vector<std::string>{privilege});
252 bool CheckAccess(const std::vector<std::string>& privileges) {
253 return impl_.CheckAccess(privileges);
261 AccessControlImpl impl_;
266 PlatformResult CheckAccess(const std::string& privilege) {
267 return CheckAccess(std::vector<std::string>{privilege});
270 PlatformResult CheckAccess(const std::vector<std::string>& privileges) {
273 // Local cache of mapped privilege strings. This routine can be called many times, especially
274 // during application launch, generating a high overhead of retrieving mapped privileges from
275 // the underlying databases. This is especially the case since the same mappings can end up
276 // being retrieved several times.
277 using MappedPrivilegeCache = std::map<std::string, std::vector<std::string>>;
278 static MappedPrivilegeCache mapped_privilege_cache;
280 std::string api_version;
281 PlatformResult res = common::tools::GetPkgApiVersion(&api_version);
285 LoggerD("Application api version: %s", api_version.c_str());
287 for (auto input_priv : privileges) {
288 LoggerD("Input privilege: %s", input_priv.c_str());
289 GList* input_glist = nullptr;
290 GList* mapped_glist = nullptr;
293 g_list_free(input_glist);
294 g_list_free(mapped_glist);
297 std::vector<std::string>* mapped_vector_ptr = nullptr;
299 // Check if mapped privilege is in local cache first
300 MappedPrivilegeCache::const_iterator it = mapped_privilege_cache.find(input_priv);
301 if (mapped_privilege_cache.end() == it) {
302 LoggerD("Mapped privileges - need to be fetched from database");
303 // Not in cache - retrieve from underlying databases.
304 input_glist = g_list_append(input_glist, (void*)input_priv.c_str());
305 int ret = privilege_manager_get_mapped_privilege_list(
306 api_version.c_str(), PRVMGR_PACKAGE_TYPE_WRT, input_glist, &mapped_glist);
307 if (PRVMGR_ERR_NONE != ret) {
308 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get mapped privilege list");
311 // initialize empty cache vector
312 mapped_privilege_cache[input_priv] = std::vector<std::string>();
313 LoggerD("Mapped privileges:");
314 auto push_elem = [](gpointer data, gpointer user_data) -> void {
315 if (data && user_data) {
316 std::vector<std::string>* mapped_vector =
317 static_cast<std::vector<std::string>*>(user_data);
318 char* char_data = static_cast<char*>(data);
319 mapped_vector->push_back(char_data);
320 LoggerD("mapped to: %s", char_data);
323 // fill the vector with data
324 g_list_foreach(mapped_glist, push_elem, &mapped_privilege_cache[input_priv]);
325 mapped_vector_ptr = &mapped_privilege_cache[input_priv];
327 // Retrieve from local cache
328 LoggerD("Mapped privileges already in cache");
329 mapped_vector_ptr = (std::vector<std::string>*)&(it->second);
332 if (!AccessControl::GetInstance().CheckAccess(*mapped_vector_ptr)) {
333 for (const auto& mapped_priv : *mapped_vector_ptr) {
334 LoggerD("Access to privilege: %s has been denied.", mapped_priv.c_str());
336 return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied");
339 return PlatformResult(ErrorCode::NO_ERROR);
342 PlatformResult GetPkgApiVersion(std::string* api_version) {
345 // Local cache of API version string. This can be expensive to retrieve from
346 // underlying databases and this routine can be called many times during
347 // application launch.
348 static std::string cached_api_version;
349 static int cached_pid = -1;
351 char* app_id = nullptr;
352 char* pkgid = nullptr;
353 char* api_ver = nullptr;
354 app_info_h app_handle = nullptr;
355 pkgmgrinfo_pkginfo_h pkginfo_handle = nullptr;
365 app_info_destroy(app_handle);
367 if (pkginfo_handle) {
368 pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle);
372 pid_t pid = getpid();
373 if (cached_pid == pid) {
374 *api_version = cached_api_version; // Retrieve from local cache
376 int ret = app_manager_get_app_id(pid, &app_id);
377 if (ret != APP_MANAGER_ERROR_NONE) {
378 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app id");
381 ret = app_info_create(app_id, &app_handle);
382 if (ret != APP_MANAGER_ERROR_NONE) {
383 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app info");
386 ret = app_info_get_package(app_handle, &pkgid);
387 if ((ret != APP_MANAGER_ERROR_NONE) || (pkgid == nullptr)) {
388 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkg id");
391 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, getuid(), &pkginfo_handle);
392 if (ret != PMINFO_R_OK) {
393 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkginfo_h");
396 ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo_handle, &api_ver);
397 if (ret != PMINFO_R_OK) {
398 return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get api version");
401 cached_api_version = api_ver; // Save in local cache
404 *api_version = api_ver;
407 return PlatformResult(ErrorCode::NO_ERROR);
410 std::vector<std::string> SplitString(const std::string& str, const std::string& delim) {
411 std::vector<std::string> tokens;
412 size_t prev = 0, pos = 0;
414 pos = str.find(delim, prev);
415 if (pos == std::string::npos) pos = str.length();
416 std::string token = str.substr(prev, pos - prev);
417 if (!token.empty()) tokens.push_back(token);
418 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);
429 "Failed to get application version, "
430 "assuming that application version is same as platform");
433 std::vector<std::string> vec_app = SplitString(app_ver, ".");
434 std::vector<std::string> vec_ref = SplitString(ver, ".");
436 size_t length = std::min(vec_app.size(), vec_ref.size());
437 for (size_t i = 0; i < length; ++i) {
438 int num_ver = std::stoi(vec_ref[i]);
439 int num_app = std::stoi(vec_app[i]);
440 if (num_app < num_ver) {
442 } else if (num_app > num_ver) {
449 std::string GetErrorString(int error_code) {
450 static const size_t kSize = 1024;
451 char msg[kSize] = {0};
452 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];
483 bool IsPathValid(const std::string& path) {
487 * Directory dot-referencing is not allowed
489 return std::string::npos == path.find("/../") && std::string::npos == path.find("/./") &&
490 0 != path.find("./") && 0 != path.find("../") && path.length() - 2 != path.rfind("/.") &&
491 path.length() - 3 != path.rfind("/..");
494 PlatformResult CheckFileStatus(const std::string& path) {
499 if (stat(path.c_str(), &buf)) {
500 LoggerD("Failed to stat path: %s", path.c_str());
502 if (ENOENT == errno) {
503 return PlatformResult(ErrorCode::NOT_FOUND_ERR, "File does not exist: " + path);
504 } else if (EACCES == errno) {
505 return PlatformResult(ErrorCode::IO_ERR, "The user cannot access the file: " + path);
508 LoggerD("stat() error: %s", common::tools::GetErrorString(errno).c_str());
509 return PlatformResult(ErrorCode::UNKNOWN_ERR, "Cannot get status of the file: " + path);
512 if (!S_ISREG(buf.st_mode)) {
513 return PlatformResult(ErrorCode::NOT_FOUND_ERR,
514 "Path does not point to a regular file: " + path);
517 if (!(S_IRUSR & buf.st_mode)) {
518 return PlatformResult(ErrorCode::IO_ERR, "The user cannot read the file: " + path);
521 return PlatformResult(ErrorCode::NO_ERROR);
524 PlatformResult CheckFileAvailability(const std::string& path) {
527 if (!IsPathValid(path)) {
528 return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid path: " + path);
531 return CheckFileStatus(path);
534 std::string ConvertToLowerCase(const std::string& input_string) {
535 std::string output_string = input_string;
536 std::transform(output_string.begin(), output_string.end(), output_string.begin(), ::tolower);
537 return output_string;
541 } // namespace common