2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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.
23 #include <cynara-client.h>
24 #include <cynara-creds-gdbus.h>
25 #include <cynara-session.h>
26 #include <pkgmgr-info.h>
27 #include <pkgmgr_installer_info.h>
28 #include <system_info.h>
34 #include "watchface-common/watchface-util.hh"
35 #include "watchface-common/include/watchface-common.h"
36 #include "watchface-common/watchface-common-internal.hh"
37 #include "watchface-common/include/watchface-common-internal.h"
43 #define MAX_PACKAGE_STR_SIZE 512
44 #define SMACK_LABEL_LEN 255
45 #define COMPLICATION_BUS_NAME_PREFIX "org.tizen.watchface_complication._"
46 #define COMPLICATION_PATH_PREFIX "/org/tizen/watchface_complication_"
47 #define EDITABLE_PATH_PREFIX "/org/tizen/watchface_editable_"
48 #define COMPLICATION_OBJECT_PATH "/org/tizen/watchface_complication"
49 #define MAX_CACHE_COUNT 10
52 #define LOG_TAG "WATCHFACE_COMPLICATION"
55 using namespace tizen_base;
56 namespace watchface_complication {
58 static int __cynara_check(const char* client, const char* user,
59 const char* privilege) {
61 cynara* p_cynara = NULL;
63 ret = cynara_initialize(&p_cynara, NULL);
64 if (ret != CYNARA_API_SUCCESS) {
65 LOGE("cannot init cynara [%d] failed!", ret);
66 return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
69 cynara_ret = cynara_check(p_cynara, client, "", user, privilege);
70 if (cynara_ret == CYNARA_API_ACCESS_ALLOWED) {
71 ret = WATCHFACE_COMPLICATION_ERROR_NONE;
73 if (cynara_ret == CYNARA_API_ACCESS_DENIED)
74 ret = WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
76 ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
78 LOGE("cynara access check [%s][%d] failed!", privilege, ret);
81 cynara_finish(p_cynara);
86 bool CheckWatchFeatureEnabled(void) {
87 static bool feature = false;
88 static bool retrieved = false;
90 if (retrieved == true)
93 ret = system_info_get_platform_bool(
94 "http://tizen.org/feature/watch_app", &feature);
95 if (ret != SYSTEM_INFO_ERROR_NONE) {
96 LOGE("failed to get system info for watch_app feature");
103 int CheckPrivilege(const char* privilege) {
106 char subject_label[SMACK_LABEL_LEN + 1] = {0, };
107 char uid[10] = {0, };
109 fd = open("/proc/self/attr/current", O_RDONLY);
111 LOGE("open [%d] failed!", errno);
112 return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
115 ret = read(fd, subject_label, SMACK_LABEL_LEN);
117 LOGE("read [%d] failed!", errno);
118 ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
120 snprintf(uid, sizeof(uid), "%d", getuid());
121 ret = __cynara_check(subject_label, uid, privilege);
128 int CheckPrivilege(string privilege, cynara_result* pcr) {
129 int ret = WATCHFACE_COMPLICATION_ERROR_NONE;
130 if (*pcr == COMPLICATION_CYNARA_DENIED) {
131 LOGE("Permission denied");
132 return WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
133 } else if (*pcr == COMPLICATION_CYNARA_UNKNOWN) {
134 ret = CheckPrivilege(privilege.c_str());
135 if (ret == WATCHFACE_COMPLICATION_ERROR_NONE) {
136 *pcr = COMPLICATION_CYNARA_ALLOWED;
137 } else if (ret == WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED) {
138 *pcr = COMPLICATION_CYNARA_DENIED;
147 int CheckPrivilege(std::string& privilege, GDBusConnection* connection,
148 std::string& sender_name, std::string& sender_appid) {
153 ret = cynara_creds_gdbus_get_client(connection, sender_name.c_str(),
154 CLIENT_METHOD_DEFAULT, &client);
155 if (ret != CYNARA_API_SUCCESS) {
156 LOGE("failed to get client");
157 ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
161 ret = cynara_creds_gdbus_get_user(connection, sender_name.c_str(),
162 USER_METHOD_DEFAULT, &user);
163 if (ret != CYNARA_API_SUCCESS) {
164 LOGE("failed to get user");
165 ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
169 LOGD("appid(%s), client(%s), user(%s)", sender_appid.c_str(), client, user);
171 ret = __cynara_check(client, user, privilege.c_str());
182 std::string GetSenderAppid(GDBusConnection* conn,
183 const std::string& sender_name) {
185 char buffer[MAX_PACKAGE_STR_SIZE + 1] = {0, };
186 int pid = GetSenderPid(conn, sender_name);
188 ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
189 if (ret != AUL_R_OK) {
190 LOGE("Failed to get the sender ID: (%s) (%d)", sender_name.c_str(), pid);
191 return std::string();
193 return std::string(buffer);
196 int GetSenderPid(GDBusConnection* conn, const std::string& sender_name) {
197 GDBusMessage* msg = NULL;
198 GDBusMessage* reply = NULL;
203 msg = g_dbus_message_new_method_call("org.freedesktop.DBus",
204 "/org/freedesktop/DBus",
205 "org.freedesktop.DBus",
206 "GetConnectionUnixProcessID");
208 LOGE("Can't allocate new method call");
212 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name.c_str()));
213 reply = g_dbus_connection_send_message_with_reply_sync(conn, msg,
214 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
218 LOGE("Failed to get pid [%s]", err->message);
224 body = g_dbus_message_get_body(reply);
225 g_variant_get(body, "(u)", &pid);
231 g_object_unref(reply);
236 bool CheckSender(const char* sender_app_id,
237 const std::string& sender_name,
238 GDBusConnection* conn) {
240 char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
241 int pid = GetSenderPid(conn, sender_name);
243 ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
244 if (ret != AUL_R_OK) {
245 LOGE("Failed to get the sender ID: (%s) (%d)", sender_name.c_str(), pid);
249 if (strcmp(buffer, sender_app_id) != 0) {
250 LOGE("invalid appid : (%s) (%s)", buffer, sender_app_id);
257 bool CheckComplicationType(int type) {
259 case WATCHFACE_COMPLICATION_TYPE_NO_DATA:
261 case WATCHFACE_COMPLICATION_TYPE_SHORT_TEXT:
263 case WATCHFACE_COMPLICATION_TYPE_LONG_TEXT:
265 case WATCHFACE_COMPLICATION_TYPE_RANGED_VALUE:
267 case WATCHFACE_COMPLICATION_TYPE_TIME:
269 case WATCHFACE_COMPLICATION_TYPE_ICON:
271 case WATCHFACE_COMPLICATION_TYPE_IMAGE:
273 case WATCHFACE_COMPLICATION_TYPE_SMALL_IMAGE:
280 bool CheckCertificate(const std::string& provider_app_id) {
281 static std::map<std::string, bool> cache;
284 auto cp = cache.find(provider_app_id);
285 if (cp != cache.end())
288 pkgmgrinfo_cert_compare_result_type_e res;
289 std::string app_id = GetAppId();
290 int cert_ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(app_id.c_str(),
291 provider_app_id.c_str(), getuid(), &res);
293 LOGE("CheckCertificate() Failed %d", cert_ret);
296 if (res == PMINFO_CERT_COMPARE_MATCH) {
300 LOGI("CheckCertificate() Failed : CERTIFICATE_NOT_MATCH");
303 if (cache.size() >= MAX_CACHE_COUNT)
306 cache[provider_app_id] = ret;
311 std::string EncodeStr(EncodeType type, std::string appid) {
313 std::string encoded_path_str;
314 std::string encoded_str;
319 encoded_path = g_compute_checksum_for_string(G_CHECKSUM_MD5,
321 if (encoded_path == NULL)
324 encoded_path_str = std::string(encoded_path);
325 if (type == EncodeType::CompPath)
326 encoded_str = COMPLICATION_PATH_PREFIX + encoded_path_str;
327 else if (type == EncodeType::EditablePath)
328 encoded_str = EDITABLE_PATH_PREFIX + encoded_path_str;
330 encoded_str = COMPLICATION_BUS_NAME_PREFIX + encoded_path_str;
337 std::string EncodeStr(EncodeType type, std::string appid, int compid) {
340 std::string str = appid + "_" + std::to_string(compid);
342 return EncodeStr(type, str);
345 std::string GetCmdStr(CmdType type) {
348 case CompUpdateRequest :
349 ret = "__COMP_UPDATE_REQUEST__";
352 ret = "__COMP_UPDATED__";
354 case CompNotifyDataUpdate :
355 ret = "__COMP_NOTIFY_DATA_UPDATE__";
357 case CompNotifyListeningStatus :
358 ret = "__COMP_NOTIFY_LISTENING_STATUS__";
360 case EditableEditRequest :
361 ret = "__EDITABLE_EDIT_REQUEST__";
363 case EditableEditPreview :
364 ret = "__EDITABLE_EDIT_PREVIEW__";
366 case EditableEditComplete :
367 ret = "__EDITABLE_EDIT_COMPLETE__";
369 case EditableEditCancel :
370 ret = "__EDITABLE_EDIT_CANCEL__";
372 case EditableEditReady :
373 ret = "__EDITABLE_EDIT_READY__";
376 ret = "__SETUP_REPLY__";
379 ret = "__PROVIDER_READY__";
382 ret = "__EDIT_RESULT__";
391 std::string GetAppId() {
392 static std::string appid = "";
393 char appid_buf[MAX_PACKAGE_STR_SIZE] = {0, };
395 if (!appid.empty()) {
396 LOGI("appid(%s)", appid.c_str());
401 int ret = aul_app_get_appid_bypid(pid, appid_buf, sizeof(appid_buf));
402 if (ret != AUL_R_OK) {
403 LOGE("Fail to get appid");
406 appid = std::string(appid_buf);
410 int GetDataType(Bundle shared_data) {
411 string shared_type = shared_data.GetString(DATA_TYPE_KEY);
412 if (shared_type.empty()) {
413 LOGE("failed to get data type");
414 return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
417 int comp_type = stoi(shared_type);
418 if (!CheckComplicationType(comp_type)) {
419 LOGE("Invalid param for type(%d)", comp_type);
420 return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
425 bool IsValidData(Bundle shared_data) {
426 int type = GetDataType(shared_data);
427 bool is_valid = true;
430 case WATCHFACE_COMPLICATION_TYPE_SHORT_TEXT : {
431 if (shared_data.GetString(SHORT_TEXT_KEY).empty())
435 case WATCHFACE_COMPLICATION_TYPE_LONG_TEXT : {
436 if (shared_data.GetString(LONG_TEXT_KEY).empty())
440 case WATCHFACE_COMPLICATION_TYPE_RANGED_VALUE : {
441 if (shared_data.GetString(RANGE_CUR_KEY).empty() ||
442 shared_data.GetString(RANGE_MAX_KEY).empty() ||
443 shared_data.GetString(RANGE_MIN_KEY).empty())
447 case WATCHFACE_COMPLICATION_TYPE_TIME : {
448 if (shared_data.GetString(TIME_KEY).empty() &&
449 shared_data.GetString(TIME_ZONE_ID_KEY).empty())
453 case WATCHFACE_COMPLICATION_TYPE_ICON : {
454 if (shared_data.GetString(ICON_KEY).empty())
458 case WATCHFACE_COMPLICATION_TYPE_IMAGE : {
459 if (shared_data.GetString(IMAGE_KEY).empty())
463 case WATCHFACE_COMPLICATION_TYPE_SMALL_IMAGE : {
464 if (shared_data.GetString(SMALL_IMAGE_KEY).empty())
468 case WATCHFACE_COMPLICATION_TYPE_NO_DATA :
477 LOGE("Invalid data (%d)", type);
481 std::string GetAppPath(const char* appid, char* path) {
483 aul_get_app_shared_resource_path_by_appid(appid, &root_path);
484 std::string app_path =
485 "" + std::string(root_path) + "../../" + std::string(path);
487 LOGI("%s", app_path.c_str());
491 int ConvertPathToAppPath(const char* appid, bundle* data) {
492 list<string> key_list {ICON_KEY, IMAGE_KEY, AOD_ICON_KEY,
493 AOD_IMAGE_KEY, SMALL_IMAGE_KEY, AOD_SMALL_IMAGE_KEY};
494 for (auto& i : key_list) {
496 int ret = bundle_get_str(data, i.c_str(), &path);
497 if (ret != BUNDLE_ERROR_NONE)
499 char* dup_path = strdup(path);
500 bundle_del(data, i.c_str());
501 ret = bundle_add_str(data, i.c_str(),
502 util::GetAppPath(appid, dup_path).c_str());
504 if (ret != BUNDLE_ERROR_NONE) {
505 LOGE("fail to add app path");
506 return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
509 return WATCHFACE_COMPLICATION_ERROR_NONE;
512 int ConvertAulError(int ret) {
514 return WATCHFACE_COMPLICATION_ERROR_NONE;
515 if (ret == AUL_R_EILLACC)
516 return WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
517 else if (ret == AUL_R_EINVAL)
518 return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
520 return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
523 void DestroyTimeInfo(struct complication_time_info_s* info_s) {
524 if (info_s->timezone)
525 free(info_s->timezone);
527 if (info_s->timezone_id)
528 free(info_s->timezone_id);
531 free(info_s->country);
538 const char* DBHelper::GetParserDataPath() const {
543 pkgmgr_installer_info_get_target_uid(&target_uid);
545 if (target_uid == ROOT_USER
546 || target_uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
552 tzplatform_set_user(target_uid);
554 path = tzplatform_mkpath(is_global ? TZ_SYS_DB : TZ_USER_DB,
555 ".complication_provider.db");
556 tzplatform_reset_user();
561 bool DBHelper::Open() {
562 const char* path = GetParserDataPath();
566 sqlite3* db = nullptr;
567 int ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, nullptr);
568 if (ret != SQLITE_OK) {
569 LOGE("open db(%s) error: %d", path, ret);
573 return Exec("PRAGMA foreign_keys = ON");
576 bool DBHelper::Open(int mode) {
577 const char* path = GetParserDataPath();
581 sqlite3* db = nullptr;
582 int ret = sqlite3_open_v2(path, &db, mode, nullptr);
583 if (ret != SQLITE_OK) {
584 LOGE("open db(%s) error: %d", path, ret);
588 return Exec("PRAGMA foreign_keys = ON");
591 void DBHelper::Close() {
595 bool DBHelper::Exec(const std::string& query) {
596 if (sqlite3_exec(db_.get(), query.c_str(), NULL, NULL, NULL) != SQLITE_OK) {
597 LOGE("exec error %s", sqlite3_errmsg(db_.get()));
603 bool DBHelper::Prepare(const std::string& query) {
604 sqlite3_stmt* stmt = nullptr;
605 if (sqlite3_prepare_v2(db_.get(), query.c_str(), query.size(), &stmt,
606 nullptr) != SQLITE_OK) {
607 LOGE("prepare error: %s", sqlite3_errmsg(db_.get()));
616 const DBHelper::Cursor& DBHelper::GetCursor() const {
620 int DBHelper::Step() const {
621 int ret = sqlite3_step(stmt_.get());
622 if (ret != SQLITE_DONE && ret != SQLITE_ROW)
623 LOGE("step error: %s", sqlite3_errmsg(db_.get()));
627 int DBHelper::Reset() const {
628 return sqlite3_reset(stmt_.get());
631 bool DBHelper::Bind(int pos, std::string text) {
632 int ret = sqlite3_bind_text(stmt_.get(), pos, text.c_str(),
633 -1, SQLITE_TRANSIENT);
634 if (ret != SQLITE_OK) {
635 LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
642 bool DBHelper::Bind(int pos, int val) {
643 if (sqlite3_bind_int(stmt_.get(), pos, val) != SQLITE_OK) {
644 LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
651 const char* DBHelper::GetText(int pos) const {
652 return reinterpret_cast<const char*>(sqlite3_column_text(stmt_.get(), pos));
655 int DBHelper::GetInt(int pos) const {
656 return sqlite3_column_int(stmt_.get(), pos);
660 } // namespace watchface_complication