8a6a3d3c5e0b180e7513debdb5dc5f6474b028e3
[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 <privilegemgr/privilege_manager.h>
20 #include <app_manager.h>
21 #include <pkgmgr-info.h>
22
23 #ifdef PRIVILEGE_USE_DB
24 #include <sqlite3.h>
25 #include "common/current_application.h"
26 #elif PRIVILEGE_USE_ACE
27 //#include <privilege_checker.h>
28 #elif PRIVILEGE_USE_CYNARA
29 #include <unistd.h>
30
31 #include <cynara/cynara-client.h>
32 #include <sys/smack.h>
33 #endif
34
35 #include "common/logger.h"
36 #include "common/scope_exit.h"
37
38 namespace common {
39 namespace tools {
40
41 void ReportSuccess(picojson::object& out) {
42   LoggerD("Enter");
43   out.insert(std::make_pair("status", picojson::value("success")));
44 }
45
46 void ReportSuccess(const picojson::value& result, picojson::object& out) {
47   LoggerD("Enter");
48   out.insert(std::make_pair("status", picojson::value("success")));
49   out.insert(std::make_pair("result", result));
50 }
51
52 void ReportError(picojson::object& out) {
53   LoggerE("Error without error code");
54   out.insert(std::make_pair("status", picojson::value("error")));
55 }
56
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()));
61 }
62
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()));
67 }
68
69 namespace {
70
71 #ifdef PRIVILEGE_USE_DB
72
73 class AccessControlImpl {
74  public:
75   AccessControlImpl()
76       : initialized_(false) {
77     LoggerD("Privilege access checked using DB.");
78
79     const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
80     sqlite3* db = nullptr;
81
82     int ret = sqlite3_open(kWrtDBPath, &db);
83     if (SQLITE_OK != ret) {
84       LoggerE("Failed to access WRT database");
85       return;
86     }
87
88     const char* kQuery = "select name from WidgetFeature where app_id = "
89                          "(select app_id from WidgetInfo where tizen_appid = ?)"
90                          " and rejected = 0";
91     const std::string app_id = common::CurrentApplication::GetInstance().GetApplicationId();
92     sqlite3_stmt* stmt = nullptr;
93
94     ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
95     ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
96
97     SCOPE_EXIT {
98       sqlite3_finalize(stmt);
99       sqlite3_close(db);
100     };
101
102     if (SQLITE_OK != ret) {
103       LoggerE("Failed to query WRT database");
104       return;
105     }
106
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);
111     }
112
113     initialized_ = true;
114   }
115
116   ~AccessControlImpl() {}
117
118   bool CheckAccess(const std::vector<std::string>& privileges) {
119     LoggerD("Enter");
120     if (!initialized_) {
121       return false;
122     }
123
124     for (const auto& privilege : privileges) {
125       if (std::find(granted_privileges_.begin(), granted_privileges_.end(), privilege) == granted_privileges_.end()) {
126         return false;
127       }
128     }
129
130     return true;
131   }
132
133  private:
134   bool initialized_;
135   std::vector<std::string> granted_privileges_;
136 };
137
138 #elif PRIVILEGE_USE_ACE
139
140 class AccessControlImpl {
141  public:
142   AccessControlImpl() {
143     LoggerD("Privilege access checked using ACE.");
144   }
145
146   ~AccessControlImpl() {
147   }
148
149   bool CheckAccess(const std::vector<std::string>& privileges) {
150     LoggerD("Enter");
151
152     return true;
153   }
154 };
155
156 #elif PRIVILEGE_USE_CYNARA
157
158 class AccessControlImpl {
159  public:
160   AccessControlImpl() : cynara_(nullptr) {
161     LoggerD("Privilege access checked using Cynara.");
162
163     char* smack_label = nullptr;
164     int len= smack_new_label_from_self(&smack_label);
165
166     if (0 < len && nullptr != smack_label) {
167       auto uid = getuid();
168
169       SLoggerD("uid: [%u]", uid);
170       SLoggerD("smack label: [%s]", smack_label);
171
172       uid_ = std::to_string(uid);
173       smack_label_ = smack_label;
174
175       free(smack_label);
176     } else {
177       LoggerE("Failed to get smack label");
178       return;
179     }
180
181     int ret = cynara_initialize(&cynara_, nullptr);
182     if (CYNARA_API_SUCCESS != ret) {
183       LoggerE("Failed to initialize Cynara");
184       cynara_ = nullptr;
185     }
186   }
187
188   ~AccessControlImpl() {
189     if (cynara_) {
190       auto ret = cynara_finish(cynara_);
191       if (CYNARA_API_SUCCESS != ret) {
192         LoggerE("Failed to finalize Cynara");
193       }
194       cynara_ = nullptr;
195     }
196   }
197
198   bool CheckAccess(const std::vector<std::string>& privileges) {
199
200     if (cynara_) {
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
207                                                       )) {
208           return false;
209         }
210       }
211       return true;
212     } else {
213       return false;
214     }
215   }
216
217  private:
218   cynara* cynara_;
219   std::string uid_;
220   std::string smack_label_;
221 };
222
223 #else
224
225 class AccessControlImpl {
226  public:
227   AccessControlImpl() {
228     LoggerD("Privilege access - deny all.");
229   }
230
231   bool CheckAccess(const std::vector<std::string>& privileges) {
232     return false;
233   }
234 };
235
236 #endif
237
238 class AccessControl {
239  public:
240   static AccessControl& GetInstance() {
241     static AccessControl instance;
242     return instance;
243   }
244
245   bool CheckAccess(const std::string& privilege) {
246     return CheckAccess(std::vector<std::string>{privilege});
247   }
248
249   bool CheckAccess(const std::vector<std::string>& privileges) {
250     return impl_.CheckAccess(privileges);
251   }
252
253  private:
254   AccessControl() {}
255   ~AccessControl() {}
256   AccessControlImpl impl_;
257 };
258
259 } // namespace
260
261
262 PlatformResult CheckAccess(const std::string& privilege) {
263   return CheckAccess(std::vector<std::string>{privilege});
264 }
265
266 PlatformResult CheckAccess(const std::vector<std::string>& privileges) {
267   LoggerD("Enter");
268
269   std::string api_version;
270   PlatformResult res = common::tools::GetPkgApiVersion(&api_version);
271   if (res.IsError()) {
272     return res;
273   }
274   LoggerD("Application api version: %s", api_version.c_str());
275
276   for (auto input_priv : privileges) {
277     LoggerD("Input privilege: %s", input_priv.c_str());
278     GList *input_glist = nullptr;
279     GList *mapped_glist = nullptr;
280
281     SCOPE_EXIT {
282       g_list_free(input_glist);
283       g_list_free(mapped_glist);
284     };
285
286     input_glist = g_list_append(input_glist, (void*)input_priv.c_str());
287     int ret = privilege_manager_get_mapped_privilege_list(api_version.c_str(),
288                                                           PRVMGR_PACKAGE_TYPE_WRT,
289                                                           input_glist,
290                                                           &mapped_glist);
291     if (ret != PRVMGR_ERR_NONE) {
292       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get mapped privilege list");
293     }
294
295     LoggerD("Mapped privileges:");
296     std::vector<std::string> mapped_vector;
297     auto push_elem = [](gpointer data, gpointer user_data) -> void {
298       if (data && user_data) {
299         std::vector<std::string>* mapped_vector =
300             static_cast<std::vector<std::string>*>(user_data);
301         char* char_data = static_cast<char*>(data);
302         mapped_vector->push_back(char_data);
303         LoggerD("mapped to: %s", char_data);
304       }
305     };
306     g_list_foreach (mapped_glist, push_elem, &mapped_vector);
307
308     if (!AccessControl::GetInstance().CheckAccess(mapped_vector)){
309       for (const auto& mapped_priv : mapped_vector) {
310         LoggerD("Access to privilege: %s has been denied.", mapped_priv.c_str());
311       }
312       return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied");
313     }
314   }
315   return PlatformResult(ErrorCode::NO_ERROR);
316 }
317
318 PlatformResult GetPkgApiVersion(std::string* api_version) {
319   LoggerD("Entered");
320
321   char* app_id = nullptr;
322   char* pkgid = nullptr;
323   char* api_ver = nullptr;
324   app_info_h app_handle = nullptr;
325   pkgmgrinfo_pkginfo_h pkginfo_handle = nullptr;
326
327   SCOPE_EXIT {
328     if (app_id) {
329       free(app_id);
330     }
331     if (pkgid) {
332       free(pkgid);
333     }
334     if (app_handle) {
335       app_info_destroy(app_handle);
336     }
337     if (pkginfo_handle) {
338       pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle);
339     }
340   };
341
342   pid_t pid = getpid();
343   int ret = app_manager_get_app_id(pid, &app_id);
344   if (ret != APP_MANAGER_ERROR_NONE) {
345     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app id");
346   }
347
348   ret = app_info_create(app_id, &app_handle);
349   if (ret != APP_MANAGER_ERROR_NONE) {
350     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app info");
351   }
352
353   ret = app_info_get_package(app_handle, &pkgid);
354   if ((ret != APP_MANAGER_ERROR_NONE) || (pkgid == nullptr)) {
355     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkg id");
356   }
357
358   ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, getuid(), &pkginfo_handle);
359   if (ret != PMINFO_R_OK) {
360     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkginfo_h");
361   }
362
363   ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo_handle, &api_ver);
364   if (ret != PMINFO_R_OK) {
365     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get api version");
366   }
367
368   *api_version = api_ver;
369   return PlatformResult(ErrorCode::NO_ERROR);
370 }
371
372 std::vector<std::string> SplitString(const std::string& str, const std::string& delim) {
373   std::vector<std::string> tokens;
374   size_t prev = 0, pos = 0;
375   do
376   {
377     pos = str.find(delim, prev);
378     if (pos == std::string::npos) pos = str.length();
379     std::string token = str.substr(prev, pos-prev);
380     if (!token.empty()) tokens.push_back(token);
381     prev = pos + delim.length();
382   }
383   while (pos < str.length() && prev < str.length());
384   return tokens;
385 }
386
387 bool IsAppVersionEarlierThan(const std::string& ver) {
388   LoggerD("Enter");
389   std::string app_ver;
390   auto res = GetPkgApiVersion(&app_ver);
391   if (!res) {
392     LoggerE("Failed to get application version, "
393         "assuming that application version is same as platform");
394     return false;
395   }
396   std::vector<std::string> vec_app = SplitString(app_ver, ".");
397   std::vector<std::string> vec_ref = SplitString(ver, ".");
398
399   size_t length = std::min(vec_app.size(), vec_ref.size());
400   for (size_t i = 0; i < length; ++i) {
401     int num_ver = std::stoi(vec_ref[i]);
402     int num_app = std::stoi(vec_app[i]);
403     if (num_app < num_ver) {
404       return true;
405     } else if (num_app > num_ver) {
406       return false;
407     }
408   }
409   return false;
410 }
411
412 std::string GetErrorString(int error_code) {
413   static const size_t kSize = 1024;
414   char msg[kSize] = {0};
415   strerror_r(error_code, msg, kSize);
416   return msg;
417 }
418
419
420 int HexToInt(char c) {
421   if (c >= '0' && c <= '9') {
422     return c - '0';
423   } else if (c >= 'A' && c <= 'Z') {
424     return c - 'A' + 10;
425   } else {
426     return c - 'a' + 10;
427   }
428 }
429
430 unsigned char* HexToBin(const char* hex, int size, unsigned char* bin, int bin_size) {
431   for (int i = 0; i < size - 1 && i / 2 < bin_size; i += 2) {
432     bin[i / 2] = HexToInt(hex[i]) << 4;
433     bin[i / 2] |= HexToInt(hex[i + 1]);
434   }
435   return bin;
436 }
437
438 char* BinToHex(const unsigned char* bin, int size, char* hex, int hex_size) {
439   static const char * const digits = "0123456789ABCDEF";
440   for (int i = 0; i < size && i < hex_size / 2; i++) {
441     hex[i * 2] = digits[bin[i] >> 4];
442     hex[i * 2 + 1] = digits[bin[i] & 0xF];
443   }
444   return hex;
445 }
446
447 }  // namespace tools
448 }  // namespace common