2 * Copyright (c) 2019 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.
19 #include <linux/xattr.h>
20 #include <sys/smack.h>
22 #include <glib/gstdio.h>
24 #include <tzplatform_config.h>
25 #include <security-manager.h>
33 #include "notification-ex/common.h"
34 #include "notification-ex/shared_file.h"
35 #include "notification-ex/group_item.h"
41 #define LOG_TAG "NOTIFICATION_EX"
42 #define CHECK_LABEL "::RO"
43 #define NOTI_PRIV_DATA_DIR "data/.notification_ex"
44 #define ERR_BUFFER_SIZE 1024
48 namespace notification {
50 SharedFile::SharedFile() = default;
51 SharedFile::~SharedFile() = default;
52 SharedFile::SharingData::SharingData() = default;
53 SharedFile::SharingData::~SharingData() = default;
54 SharedFile::SharingTarget::SharingTarget() = default;
55 SharedFile::SharingTarget::~SharingTarget() = default;
57 const char* SharedFile::GetLastIndex(const char* path, const char* search) {
62 if (path == nullptr || search == nullptr)
65 search_len = strlen(search);
66 index = path + strlen(path) - search_len;
68 while (index >= path) {
69 for (i = 0; i < search_len; i++) {
70 if (index[i] != search[i])
83 bool SharedFile::MakeDir(const char* path) {
84 if (access(path, R_OK) == 0)
87 auto noti_dir = unique_ptr<GFile, decltype(&g_object_unref)>(
88 g_file_new_for_path(path), g_object_unref);
89 if (noti_dir == nullptr)
92 GError* g_err = nullptr;
93 if (!g_file_make_directory(noti_dir.get(), nullptr, &g_err)) {
95 LOGE("Failed to make sharing dir[%s]", g_err->message);
104 string SharedFile::GetDir(string path) {
112 index = GetLastIndex(path.c_str(), "/");
113 if (index == nullptr) {
114 LOGE("Failed to find directory separator");
118 dir_len = index - path.c_str() + 1;
119 if (dir_len <= 0 || dir_len > PATH_MAX)
122 dir.reserve(PATH_MAX);
123 snprintf(&dir[0], dir_len, "%s", path.c_str());
128 int SharedFile::CopyFile(const char* source, const char* dest) {
129 GError* g_err = nullptr;
130 struct utimbuf ut = {0, };
132 if (source == nullptr || dest == nullptr) {
133 LOGE("Invalid parameter");
134 return ERROR_INVALID_PARAMETER;
137 auto dst = unique_ptr<GFile, decltype(&g_object_unref)>(
138 g_file_new_for_path(dest), g_object_unref);
139 if (dst == nullptr) {
140 LOGE("dest path is wrong [%s]", dest);
141 return ERROR_IO_ERROR;
144 if (g_file_query_exists(dst.get(), nullptr)) {
145 LOGD("dst path already existed [%s]", dest);
146 return ERROR_ALREADY_EXIST_ID;
149 auto src = unique_ptr<GFile, decltype(&g_object_unref)>(
150 g_file_new_for_path(source), g_object_unref);
151 if (src == nullptr) {
152 LOGE("src path is wrong [%s]", source);
153 return ERROR_IO_ERROR;
156 if (!g_file_copy(src.get(), dst.get(), G_FILE_COPY_NOFOLLOW_SYMLINKS, nullptr,
157 nullptr, nullptr, &g_err)) {
159 LOGE("Copying file from [%s] to [%s] is failed [%s]", source, dest,
163 return ERROR_IO_ERROR;
166 ut.modtime = time(nullptr);
167 if (g_utime(dest, &ut) != 0)
168 LOGD("Failed to set g_utime %d ", errno);
173 vector<char*> SharedFile::ConvertListToArray(const list<string>& data) {
179 for (const auto& i : data)
180 v.push_back(const_cast<char*>(i.c_str()));
185 bool SharedFile::IsPrivatePath(string path) const {
186 char* smack_label = nullptr;
188 char err_buf[ERR_BUFFER_SIZE];
191 LOGE("Invalid parameter");
196 if (smack_new_label_from_path(path.c_str(), XATTR_NAME_SMACK, 1, &smack_label)
198 LOGE("smack_new_label_from_path failed : %d [%s][%s]",
199 errno, strerror_r(errno, err_buf, sizeof(err_buf)), path.c_str());
203 if (GetLastIndex(smack_label, CHECK_LABEL) != nullptr)
210 string SharedFile::GetDataPath(string app_id, string path) const {
214 if (app_id.empty() || path.empty()) {
215 LOGE("Invalid parameter");
219 tzplatform_set_user(getuid());
220 user_app = tzplatform_getenv(TZ_USER_APP);
221 tzplatform_reset_user();
223 dir = user_app + "/" + app_id + "/" + NOTI_PRIV_DATA_DIR + "/";
224 dir += string(GetLastIndex(path.c_str(), "/") + 1);
229 int SharedFile::SetSharingData(SharingData sharing_data,
230 list<string> new_shared_file_list, list<string> new_receiver_group_list,
231 multimap<string, string> receiver_group_map) {
232 private_sharing_req* handle = nullptr;
233 vector<char*> path_array;
234 vector<char*> target_array;
235 const char* appid = nullptr;
238 if (new_shared_file_list.empty() || new_receiver_group_list.empty()) {
239 LOGE("Invalid parameter");
240 return ERROR_INVALID_PARAMETER;
243 ret = security_manager_private_sharing_req_new(&handle);
244 if (ret != SECURITY_MANAGER_SUCCESS) {
245 LOGE("Failed to create private sharing request handle[%d]", ret);
246 return ERROR_IO_ERROR;
249 auto req = unique_ptr<private_sharing_req,
250 decltype(&security_manager_private_sharing_req_free)>(
251 handle, security_manager_private_sharing_req_free);
253 return ERROR_IO_ERROR;
255 appid = sharing_data.app_id.c_str();
257 ret = security_manager_private_sharing_req_set_owner_appid(req.get(), appid);
258 if (ret != SECURITY_MANAGER_SUCCESS) {
259 LOGE("Failed to set owner appid[%s][%d]", appid, ret);
260 return ERROR_IO_ERROR;
263 path_array = ConvertListToArray(new_shared_file_list);
264 if (path_array.empty()) {
265 LOGE("path_array is null");
266 return ERROR_IO_ERROR;
269 ret = security_manager_private_sharing_req_add_paths(req.get(),
270 const_cast<const char**>(path_array.data()), path_array.size());
271 if (ret != SECURITY_MANAGER_SUCCESS) {
272 LOGE("Failed to add paths [%d]", ret);
273 return ERROR_IO_ERROR;
276 target_array = ConvertListToArray(new_receiver_group_list);
277 if (target_array.empty()) {
278 LOGE("target_array is null");
279 return ERROR_IO_ERROR;
282 for (int i = 0; i < static_cast<int>(target_array.size()); i++) {
283 multimap<string, string>::iterator it;
284 for (it = receiver_group_map.begin(); it != receiver_group_map.end(); it++) {
285 if (it->first.compare(target_array[i]) == 0) {
286 ret = security_manager_private_sharing_req_set_target_appid(req.get(),
288 if (ret != SECURITY_MANAGER_SUCCESS) {
289 LOGE("Failed to set target appid [%s]", appid);
290 return ERROR_IO_ERROR;
293 ret = security_manager_private_sharing_apply(req.get());
294 if (ret != SECURITY_MANAGER_SUCCESS) {
295 LOGE("Failed to apply private sharing [%d]", ret);
296 return ERROR_IO_ERROR;
305 int SharedFile::UnsetSharingData(SharingData sharing_data,
306 multimap<string, string> receiver_group_map) {
307 private_sharing_req* handle = nullptr;
308 vector<char*> path_array;
309 vector<char*> target_array;
310 const char* appid = nullptr;
313 if (receiver_group_map.empty()) {
314 LOGE("Invalid parameter");
315 return ERROR_INVALID_PARAMETER;
318 ret = security_manager_private_sharing_req_new(&handle);
319 if (ret != SECURITY_MANAGER_SUCCESS) {
320 LOGE("Failed to create private sharing request handle[%d]", ret);
321 return ERROR_IO_ERROR;
324 auto req = unique_ptr<private_sharing_req,
325 decltype(&security_manager_private_sharing_req_free)>(
326 handle, security_manager_private_sharing_req_free);
328 return ERROR_IO_ERROR;
330 appid = sharing_data.app_id.c_str();
332 ret = security_manager_private_sharing_req_set_owner_appid(req.get(), appid);
333 if (ret != SECURITY_MANAGER_SUCCESS) {
334 LOGE("Failed to set owner appid[%s][%d]", appid, ret);
335 return ERROR_IO_ERROR;
338 path_array = ConvertListToArray(sharing_data.shared_file_list);
339 if (path_array.empty()) {
340 LOGE("path_array is null");
341 return ERROR_IO_ERROR;
344 ret = security_manager_private_sharing_req_add_paths(req.get(),
345 const_cast<const char**>(path_array.data()), path_array.size());
346 if (ret != SECURITY_MANAGER_SUCCESS) {
347 LOGE("Failed to add paths [%d]", ret);
348 return ERROR_IO_ERROR;
351 target_array = ConvertListToArray(sharing_data.receiver_group_list);
352 if (target_array.empty()) {
353 LOGE("target_array is null");
354 return ERROR_IO_ERROR;
357 for (int i = 0; i < static_cast<int>(target_array.size()); i++) {
358 multimap<string, string>::iterator it;
359 for (it = receiver_group_map.begin(); it != receiver_group_map.end(); it++) {
360 if (it->first.compare(target_array[i]) == 0) {
361 ret = security_manager_private_sharing_req_set_target_appid(req.get(),
363 if (ret != SECURITY_MANAGER_SUCCESS) {
364 LOGE("Failed to set target appid [%s]", appid);
365 return ERROR_IO_ERROR;
368 ret = security_manager_private_sharing_drop(req.get());
369 if (ret != SECURITY_MANAGER_SUCCESS) {
370 LOGE("Failed to drop private sharing [%d]", ret);
371 return ERROR_IO_ERROR;
380 SharedFile::SharingData SharedFile::FindSharingData(string appid) {
381 if (sharing_data_list_.size() == 0 || appid.empty())
384 for (auto sharing_data : sharing_data_list_) {
385 if (sharing_data.app_id.compare(appid) == 0)
392 int SharedFile::SetPrivateSharing(list<shared_ptr<AbstractItem>> notiList,
393 multimap<string, string> receiver_group_map) {
394 if (notiList.empty() || receiver_group_map.empty()) {
395 LOGE("Invalid parameter");
396 return ERROR_INVALID_PARAMETER;
399 for (auto& i : notiList) {
400 SharingData sharing_data;
401 list<string> new_shared_file_list;
402 list<string> new_receiver_group_list;
404 list<string> shared_path_list = i->GetSharedPath();
405 if (shared_path_list.empty())
408 string appid = i->GetSenderAppId();
412 sharing_data = FindSharingData(appid);
413 if (!sharing_data.app_id.empty()) {
414 string noti_id = i->GetId();
415 list<string>::iterator it;
416 it = find_if(sharing_data.noti_id_list.begin(),
417 sharing_data.noti_id_list.end(),
418 [¬i_id](std::string id){
419 return id.compare(noti_id) == 0;
421 if (it == sharing_data.noti_id_list.end())
422 sharing_data.noti_id_list.push_back(noti_id);
424 for (auto& shared_path : shared_path_list) {
425 list<string>::iterator it;
426 it = find_if(sharing_data.shared_file_list.begin(),
427 sharing_data.shared_file_list.end(),
428 [&shared_path](std::string shared_file){
429 return shared_file.compare(shared_path) == 0;
431 if (it == sharing_data.shared_file_list.end()) {
432 sharing_data.shared_file_list.push_back(shared_path);
433 new_shared_file_list.push_back(shared_path);
437 list<string> receiver_list = i->GetReceiverList();
438 for (auto& receiver : receiver_list) {
439 list<string>::iterator it;
440 it = find_if(sharing_data.receiver_group_list.begin(),
441 sharing_data.receiver_group_list.end(),
442 [&receiver](std::string receiver_group){
443 return receiver_group.compare(receiver) == 0;
445 if (it == sharing_data.receiver_group_list.end()) {
446 sharing_data.receiver_group_list.push_back(receiver);
447 new_receiver_group_list.push_back(receiver);
451 sharing_data.app_id = appid;
452 sharing_data.dir = GetDir(*(shared_path_list.begin()));
453 sharing_data.noti_id_list.emplace_back(i->GetId());
454 sharing_data.shared_file_list = shared_path_list;
455 sharing_data.receiver_group_list = i->GetReceiverList();
456 sharing_data_list_.emplace_back(sharing_data);
458 new_shared_file_list = shared_path_list;
459 new_receiver_group_list = i->GetReceiverList();
462 if (SetSharingData(sharing_data, new_shared_file_list,
463 new_receiver_group_list, receiver_group_map) == ERROR_NONE)
467 LOGD("SetPrivateSharing");
471 int SharedFile::UpdatePrivateSharing(list<shared_ptr<AbstractItem>> notiList,
472 multimap<string, string> receiver_group_map) {
473 if (notiList.empty() || receiver_group_map.empty()) {
474 LOGE("Invalid parameter");
475 return ERROR_INVALID_PARAMETER;
478 for (auto& i : notiList) {
479 list<string> new_shared_file_list;
480 list<string> new_receiver_group_list;
481 list<string> shared_path_list = i->GetSharedPath();
482 if (shared_path_list.empty())
485 string appid = i->GetSenderAppId();
486 SharingData sharing_data = FindSharingData(appid);
487 if (appid.empty() || sharing_data.app_id.empty())
490 for (auto& shared_path : shared_path_list) {
491 std::list<std::string>::iterator it;
492 it = std::find_if(sharing_data.shared_file_list.begin(),
493 sharing_data.shared_file_list.end(),
494 [&shared_path](std::string shared_file){
495 return shared_file.compare(shared_path) == 0;
497 if (it == sharing_data.shared_file_list.end()) {
498 sharing_data.shared_file_list.push_back(shared_path);
499 new_shared_file_list.push_back(shared_path);
503 new_receiver_group_list = i->GetReceiverList();
504 if (SetSharingData(sharing_data, new_shared_file_list,
505 new_receiver_group_list, receiver_group_map) == ERROR_NONE)
509 LOGD("UpdatePrivateSharing");
513 int SharedFile::RemovePrivateSharing(list<shared_ptr<AbstractItem>> notiList,
514 multimap<string, string> receiver_group_map) {
515 if (notiList.empty() || receiver_group_map.empty()) {
516 LOGE("Invalid parameter");
517 return ERROR_INVALID_PARAMETER;
520 for (auto& i : notiList) {
521 string appid = i->GetSenderAppId();
525 SharingData sharing_data = FindSharingData(appid);
526 if (sharing_data.app_id.empty())
529 sharing_data.noti_id_list.remove(i->GetId());
530 if (sharing_data.noti_id_list.size() == 0) {
531 UnsetSharingData(sharing_data, receiver_group_map);
533 vector<char*> path_array = ConvertListToArray(sharing_data.shared_file_list);
534 if (!path_array.empty()) {
535 for (int i = 0; i < static_cast<int>(path_array.size()); i++) {
536 if (g_remove(path_array[i]) == -1)
537 LOGE("Failed to remove shared_file(%s)", path_array[i]);
541 if (g_rmdir(sharing_data.dir.c_str()) != 0)
542 LOGE("Failed to remove sharing directory(%s)(%d)",
543 sharing_data.dir.c_str(), errno);
547 LOGD("RemovePrivateSharing");
551 int SharedFile::CopyPrivateFile(shared_ptr<item::AbstractItem> item) {
552 if (item == nullptr) {
553 LOGE("Invalid paramenter");
554 return ERROR_INVALID_PARAMETER;
557 list<map<string, string>> path_map_list = item->GetPathMapList();
558 if (path_map_list.empty())
561 if (!MakeDir(GetDir((*(path_map_list.begin())).begin()->second).c_str()))
562 return ERROR_IO_ERROR;
564 list<map<string, string>>::iterator list_it;
565 for (list_it = path_map_list.begin(); list_it != path_map_list.end(); ++list_it) {
566 map<string, string>::iterator map_it;
567 for (map_it = (*list_it).begin(); map_it != (*list_it).end(); map_it++) {
568 CopyFile((map_it->first).c_str(), (map_it->second).c_str());
576 } // namespace notification