Merge branch 'tizen_3.0' into tizen_4.0
[platform/core/api/webapi-plugins.git] / src / common / tools.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "common/tools.h"
18
19 #include <app_manager.h>
20 #include <pkgmgr-info.h>
21 #include <privilegemgr/privilege_manager.h>
22 #include <sys/stat.h>
23
24 #ifdef PRIVILEGE_USE_DB
25 #include <sqlite3.h>
26 #include "common/current_application.h"
27 #elif PRIVILEGE_USE_ACE
28 //#include <privilege_checker.h>
29 #elif PRIVILEGE_USE_CYNARA
30 #include <unistd.h>
31
32 #include <cynara/cynara-client.h>
33 #include <sys/smack.h>
34 #endif
35
36 #include "common/logger.h"
37 #include "common/scope_exit.h"
38
39 namespace common {
40 namespace tools {
41
42 void ReportSuccess(picojson::object& out) {
43   ScopeLogger();
44   out.insert(std::make_pair("status", picojson::value("success")));
45 }
46
47 void ReportSuccess(const picojson::value& result, picojson::object& out) {
48   ScopeLogger();
49   out.insert(std::make_pair("status", picojson::value("success")));
50   out.insert(std::make_pair("result", result));
51 }
52
53 void ReportError(picojson::object& out) {
54   LoggerE("Error without error code");
55   out.insert(std::make_pair("status", picojson::value("error")));
56 }
57
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()));
62 }
63
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()));
69 }
70
71 namespace {
72
73 #ifdef PRIVILEGE_USE_DB
74
75 class AccessControlImpl {
76  public:
77   AccessControlImpl() : initialized_(false) {
78     ScopeLogger("Privilege access checked using DB.");
79
80     const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
81     sqlite3* db = nullptr;
82
83     int ret = sqlite3_open(kWrtDBPath, &db);
84     if (SQLITE_OK != ret) {
85       LoggerE("Failed to access WRT database");
86       return;
87     }
88
89     const char* kQuery =
90         "select name from WidgetFeature where app_id = "
91         "(select app_id from WidgetInfo where tizen_appid = ?)"
92         " and rejected = 0";
93     const std::string app_id = common::CurrentApplication::GetInstance().GetApplicationId();
94     sqlite3_stmt* stmt = nullptr;
95
96     ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
97     ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
98
99     SCOPE_EXIT {
100       sqlite3_finalize(stmt);
101       sqlite3_close(db);
102     };
103
104     if (SQLITE_OK != ret) {
105       LoggerE("Failed to query WRT database");
106       return;
107     }
108
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);
113     }
114
115     initialized_ = true;
116   }
117
118   ~AccessControlImpl() {
119   }
120
121   bool CheckAccess(const std::vector<std::string>& privileges) {
122     ScopeLogger();
123     if (!initialized_) {
124       return false;
125     }
126
127     for (const auto& privilege : privileges) {
128       if (std::find(granted_privileges_.begin(), granted_privileges_.end(), privilege) ==
129           granted_privileges_.end()) {
130         return false;
131       }
132     }
133
134     return true;
135   }
136
137  private:
138   bool initialized_;
139   std::vector<std::string> granted_privileges_;
140 };
141
142 #elif PRIVILEGE_USE_ACE
143
144 class AccessControlImpl {
145  public:
146   AccessControlImpl() {
147     LoggerD("Privilege access checked using ACE.");
148   }
149
150   ~AccessControlImpl() {
151   }
152
153   bool CheckAccess(const std::vector<std::string>& privileges) {
154     ScopeLogger();
155
156     return true;
157   }
158 };
159
160 #elif PRIVILEGE_USE_CYNARA
161
162 class AccessControlImpl {
163  public:
164   AccessControlImpl() : cynara_(nullptr) {
165     ScopeLogger("Privilege access checked using Cynara.");
166
167     char* smack_label = nullptr;
168     int len = smack_new_label_from_self(&smack_label);
169
170     if (0 < len && nullptr != smack_label) {
171       auto uid = getuid();
172
173       SLoggerD("uid: [%u]", uid);
174       SLoggerD("smack label: [%s]", smack_label);
175
176       uid_ = std::to_string(uid);
177       smack_label_ = smack_label;
178
179       free(smack_label);
180     } else {
181       LoggerE("Failed to get smack label");
182       return;
183     }
184
185     int ret = cynara_initialize(&cynara_, nullptr);
186     if (CYNARA_API_SUCCESS != ret) {
187       LoggerE("Failed to initialize Cynara");
188       cynara_ = nullptr;
189     }
190   }
191
192   ~AccessControlImpl() {
193     if (cynara_) {
194       auto ret = cynara_finish(cynara_);
195       if (CYNARA_API_SUCCESS != ret) {
196         LoggerE("Failed to finalize Cynara");
197       }
198       cynara_ = nullptr;
199     }
200   }
201
202   bool CheckAccess(const std::vector<std::string>& privileges) {
203     if (cynara_) {
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
210             ) {
211           return false;
212         }
213       }
214       return true;
215     } else {
216       return false;
217     }
218   }
219
220  private:
221   cynara* cynara_;
222   std::string uid_;
223   std::string smack_label_;
224 };
225
226 #else
227
228 class AccessControlImpl {
229  public:
230   AccessControlImpl() {
231     LoggerD("Privilege access - deny all.");
232   }
233
234   bool CheckAccess(const std::vector<std::string>& privileges) {
235     return false;
236   }
237 };
238
239 #endif
240
241 class AccessControl {
242  public:
243   static AccessControl& GetInstance() {
244     static AccessControl instance;
245     return instance;
246   }
247
248   bool CheckAccess(const std::string& privilege) {
249     return CheckAccess(std::vector<std::string>{privilege});
250   }
251
252   bool CheckAccess(const std::vector<std::string>& privileges) {
253     return impl_.CheckAccess(privileges);
254   }
255
256  private:
257   AccessControl() {
258   }
259   ~AccessControl() {
260   }
261   AccessControlImpl impl_;
262 };
263
264 }  // namespace
265
266 PlatformResult CheckAccess(const std::string& privilege) {
267   return CheckAccess(std::vector<std::string>{privilege});
268 }
269
270 PlatformResult CheckAccess(const std::vector<std::string>& privileges) {
271   ScopeLogger();
272
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;
279
280   std::string api_version;
281   PlatformResult res = common::tools::GetPkgApiVersion(&api_version);
282   if (res.IsError()) {
283     return res;
284   }
285   LoggerD("Application api version: %s", api_version.c_str());
286
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;
291
292     SCOPE_EXIT {
293       g_list_free(input_glist);
294       g_list_free(mapped_glist);
295     };
296
297     std::vector<std::string>* mapped_vector_ptr = nullptr;
298
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");
309       }
310
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);
321         }
322       };
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];
326     } else {
327       // Retrieve from local cache
328       LoggerD("Mapped privileges already in cache");
329       mapped_vector_ptr = (std::vector<std::string>*)&(it->second);
330     }
331
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());
335       }
336       return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied");
337     }
338   }
339   return PlatformResult(ErrorCode::NO_ERROR);
340 }
341
342 PlatformResult GetPkgApiVersion(std::string* api_version) {
343   ScopeLogger();
344
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;
350
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;
356
357   SCOPE_EXIT {
358     if (app_id) {
359       free(app_id);
360     }
361     if (pkgid) {
362       free(pkgid);
363     }
364     if (app_handle) {
365       app_info_destroy(app_handle);
366     }
367     if (pkginfo_handle) {
368       pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle);
369     }
370   };
371
372   pid_t pid = getpid();
373   if (cached_pid == pid) {
374     *api_version = cached_api_version;  // Retrieve from local cache
375   } else {
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");
379     }
380
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");
384     }
385
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");
389     }
390
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");
394     }
395
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");
399     }
400
401     cached_api_version = api_ver;  // Save in local cache
402     cached_pid = pid;
403
404     *api_version = api_ver;
405   }
406
407   return PlatformResult(ErrorCode::NO_ERROR);
408 }
409
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;
413   do {
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());
420   return tokens;
421 }
422
423 bool IsAppVersionEarlierThan(const std::string& ver) {
424   ScopeLogger();
425   std::string app_ver;
426   auto res = GetPkgApiVersion(&app_ver);
427   if (!res) {
428     LoggerE(
429         "Failed to get application version, "
430         "assuming that application version is same as platform");
431     return false;
432   }
433   std::vector<std::string> vec_app = SplitString(app_ver, ".");
434   std::vector<std::string> vec_ref = SplitString(ver, ".");
435
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) {
441       return true;
442     } else if (num_app > num_ver) {
443       return false;
444     }
445   }
446   return false;
447 }
448
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);
453   return msg;
454 }
455
456 int HexToInt(char c) {
457   if (c >= '0' && c <= '9') {
458     return c - '0';
459   } else if (c >= 'A' && c <= 'Z') {
460     return c - 'A' + 10;
461   } else {
462     return c - 'a' + 10;
463   }
464 }
465
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]);
470   }
471   return bin;
472 }
473
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];
479   }
480   return hex;
481 }
482
483 bool IsPathValid(const std::string& path) {
484   ScopeLogger();
485
486   /*
487    * Directory dot-referencing is not allowed
488    */
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("/..");
492 }
493
494 PlatformResult CheckFileStatus(const std::string& path) {
495   ScopeLogger();
496
497   struct stat buf;
498
499   if (stat(path.c_str(), &buf)) {
500     LoggerD("Failed to stat path: %s", path.c_str());
501
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);
506     }
507
508     LoggerD("stat() error: %s", common::tools::GetErrorString(errno).c_str());
509     return PlatformResult(ErrorCode::UNKNOWN_ERR, "Cannot get status of the file: " + path);
510   }
511
512   if (!S_ISREG(buf.st_mode)) {
513     return PlatformResult(ErrorCode::NOT_FOUND_ERR,
514                           "Path does not point to a regular file: " + path);
515   }
516
517   if (!(S_IRUSR & buf.st_mode)) {
518     return PlatformResult(ErrorCode::IO_ERR, "The user cannot read the file: " + path);
519   }
520
521   return PlatformResult(ErrorCode::NO_ERROR);
522 }
523
524 PlatformResult CheckFileAvailability(const std::string& path) {
525   ScopeLogger();
526
527   if (!IsPathValid(path)) {
528     return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid path: " + path);
529   }
530
531   return CheckFileStatus(path);
532 }
533
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;
538 }
539
540 }  // namespace tools
541 }  // namespace common