Release version 0.5.85
[platform/core/api/notification.git] / notification-ex / shared_file.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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 <unistd.h>
18 #include <dlog.h>
19 #include <linux/xattr.h>
20 #include <sys/smack.h>
21 #include <gio/gio.h>
22 #include <glib/gstdio.h>
23 #include <utime.h>
24 #include <tzplatform_config.h>
25 #include <security-manager.h>
26
27 #include <string>
28 #include <list>
29 #include <map>
30 #include <algorithm>
31 #include <vector>
32
33 #include "notification-ex/common.h"
34 #include "notification-ex/shared_file.h"
35 #include "notification-ex/group_item.h"
36
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #endif
40
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
45
46 using namespace std;
47
48 namespace notification {
49 namespace item {
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;
56
57 const char* SharedFile::GetLastIndex(const char* path, const char* search) {
58   int i;
59   int search_len;
60   const char* index;
61
62   if (path == nullptr || search == nullptr)
63     return nullptr;
64
65   search_len = strlen(search);
66   index = path + strlen(path) - search_len;
67
68   while (index >= path) {
69     for (i = 0; i < search_len; i++) {
70       if (index[i] != search[i])
71         break;
72     }
73
74     if (i == search_len)
75       return index;
76
77     index--;
78   }
79
80   return nullptr;
81 }
82
83 bool SharedFile::MakeDir(const char* path) {
84   if (access(path, R_OK) == 0)
85     return true;
86
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)
90     return false;
91
92   GError* g_err = nullptr;
93   if (!g_file_make_directory(noti_dir.get(), nullptr, &g_err)) {
94     if (g_err) {
95       LOGE("Failed to make sharing dir[%s]", g_err->message);
96       g_error_free(g_err);
97     }
98     return false;
99   }
100
101   return true;
102 }
103
104 string SharedFile::GetDir(string path) {
105   int dir_len;
106   const char* index;
107   string dir;
108
109   if (path.empty())
110     return "";
111
112   index = GetLastIndex(path.c_str(), "/");
113   if (index == nullptr) {
114     LOGE("Failed to find directory separator");
115     return "";
116   }
117
118   dir_len = index - path.c_str() + 1;
119   if (dir_len <= 0 || dir_len > PATH_MAX)
120     return "";
121
122   dir.reserve(PATH_MAX);
123   snprintf(&dir[0], dir_len, "%s", path.c_str());
124
125   return dir;
126 }
127
128 int SharedFile::CopyFile(const char* source, const char* dest) {
129   GError* g_err = nullptr;
130   struct utimbuf ut = {0, };
131
132   if (source == nullptr || dest == nullptr) {
133     LOGE("Invalid parameter");
134     return ERROR_INVALID_PARAMETER;
135   }
136
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;
142   }
143
144   if (g_file_query_exists(dst.get(), nullptr)) {
145     LOGD("dst path already existed [%s]", dest);
146     return  ERROR_ALREADY_EXIST_ID;
147   }
148
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;
154   }
155
156   if (!g_file_copy(src.get(), dst.get(), G_FILE_COPY_NOFOLLOW_SYMLINKS, nullptr,
157                 nullptr, nullptr, &g_err)) {
158     if (g_err) {
159       LOGE("Copying file from [%s] to [%s] is failed [%s]", source, dest,
160           g_err->message);
161       g_error_free(g_err);
162     }
163     return ERROR_IO_ERROR;
164   }
165
166   ut.modtime = time(nullptr);
167   if (g_utime(dest, &ut) != 0)
168     LOGD("Failed to set g_utime %d ", errno);
169
170   return ERROR_NONE;
171 }
172
173 vector<char*> SharedFile::ConvertListToArray(const list<string>& data) {
174   vector<char*> v;
175
176   if (data.empty())
177     return {};
178
179   for (const auto& i : data)
180     v.push_back(const_cast<char*>(i.c_str()));
181
182   return v;
183 }
184
185 bool SharedFile::IsPrivatePath(string path) const {
186   char* smack_label = nullptr;
187   bool ret = false;
188   char err_buf[ERR_BUFFER_SIZE];
189
190   if (path.empty()) {
191     LOGE("Invalid parameter");
192     return false;
193   }
194
195   errno = 0;
196   if (smack_new_label_from_path(path.c_str(), XATTR_NAME_SMACK, 1, &smack_label)
197         <= 0) {
198     LOGE("smack_new_label_from_path failed  : %d [%s][%s]",
199         errno, strerror_r(errno, err_buf, sizeof(err_buf)), path.c_str());
200     return false;
201   }
202
203   if (GetLastIndex(smack_label, CHECK_LABEL) != nullptr)
204     ret = true;
205
206   free(smack_label);
207   return ret;
208 }
209
210 string SharedFile::GetDataPath(string app_id, string path) const {
211   string user_app;
212   string dir;
213
214   if (app_id.empty() || path.empty()) {
215     LOGE("Invalid parameter");
216     return nullptr;
217   }
218
219   tzplatform_set_user(getuid());
220   user_app = tzplatform_getenv(TZ_USER_APP);
221   tzplatform_reset_user();
222
223   dir = user_app + "/" + app_id + "/" + NOTI_PRIV_DATA_DIR + "/";
224   dir += string(GetLastIndex(path.c_str(), "/") + 1);
225
226   return dir;
227 }
228
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;
236   int ret;
237
238   if (new_shared_file_list.empty() || new_receiver_group_list.empty()) {
239     LOGE("Invalid parameter");
240     return ERROR_INVALID_PARAMETER;
241   }
242
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;
247   }
248
249   auto req = unique_ptr<private_sharing_req,
250                 decltype(&security_manager_private_sharing_req_free)>(
251                 handle, security_manager_private_sharing_req_free);
252   if (req == nullptr)
253     return ERROR_IO_ERROR;
254
255   appid = sharing_data.app_id.c_str();
256
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;
261   }
262
263   path_array = ConvertListToArray(new_shared_file_list);
264   if (path_array.empty()) {
265     LOGE("path_array is null");
266     return ERROR_IO_ERROR;
267   }
268
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;
274   }
275
276   target_array = ConvertListToArray(new_receiver_group_list);
277   if (target_array.empty()) {
278     LOGE("target_array is null");
279     return ERROR_IO_ERROR;
280   }
281
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(),
287                 it->second.c_str());
288         if (ret != SECURITY_MANAGER_SUCCESS) {
289           LOGE("Failed to set target appid [%s]", appid);
290           return ERROR_IO_ERROR;
291         }
292
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;
297         }
298       }
299     }
300   }
301
302   return ERROR_NONE;
303 }
304
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;
311   int ret;
312
313   if (receiver_group_map.empty()) {
314     LOGE("Invalid parameter");
315     return ERROR_INVALID_PARAMETER;
316   }
317
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;
322   }
323
324   auto req = unique_ptr<private_sharing_req,
325                 decltype(&security_manager_private_sharing_req_free)>(
326                 handle, security_manager_private_sharing_req_free);
327   if (req == nullptr)
328     return ERROR_IO_ERROR;
329
330   appid = sharing_data.app_id.c_str();
331
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;
336   }
337
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;
342   }
343
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;
349   }
350
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;
355   }
356
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(),
362                 it->second.c_str());
363         if (ret != SECURITY_MANAGER_SUCCESS) {
364           LOGE("Failed to set target appid [%s]", appid);
365           return ERROR_IO_ERROR;
366         }
367
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;
372         }
373       }
374     }
375   }
376
377   return ERROR_NONE;
378 }
379
380 SharedFile::SharingData SharedFile::FindSharingData(string appid) {
381   if (sharing_data_list_.size() == 0 || appid.empty())
382     return {};
383
384   for (auto sharing_data : sharing_data_list_) {
385     if (sharing_data.app_id.compare(appid) == 0)
386       return sharing_data;
387   }
388
389   return {};
390 }
391
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;
397   }
398
399   for (auto& i : notiList) {
400     SharingData sharing_data;
401     list<string> new_shared_file_list;
402     list<string> new_receiver_group_list;
403
404     list<string> shared_path_list = i->GetSharedPath();
405     if (shared_path_list.empty())
406       continue;
407
408     string appid = i->GetSenderAppId();
409     if (appid.empty())
410       continue;
411
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                     [&noti_id](std::string id){
419                       return id.compare(noti_id) == 0;
420                     });
421       if (it == sharing_data.noti_id_list.end())
422         sharing_data.noti_id_list.push_back(noti_id);
423
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;
430                     });
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);
434         }
435       }
436
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;
444                     });
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);
448         }
449       }
450     } else {
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);
457
458       new_shared_file_list = shared_path_list;
459       new_receiver_group_list = i->GetReceiverList();
460     }
461
462     if (SetSharingData(sharing_data, new_shared_file_list,
463                 new_receiver_group_list, receiver_group_map) == ERROR_NONE)
464       i->SetSharedPath();
465   }
466
467   LOGD("SetPrivateSharing");
468   return ERROR_NONE;
469 }
470
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;
476   }
477
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())
483       continue;
484
485     string appid = i->GetSenderAppId();
486     SharingData sharing_data = FindSharingData(appid);
487     if (appid.empty() || sharing_data.app_id.empty())
488       continue;
489
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;
496                     });
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);
500       }
501     }
502
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)
506       i->SetSharedPath();
507   }
508
509   LOGD("UpdatePrivateSharing");
510   return ERROR_NONE;
511 }
512
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;
518   }
519
520   for (auto& i : notiList) {
521     string appid = i->GetSenderAppId();
522     if (appid.empty())
523       continue;
524
525     SharingData sharing_data = FindSharingData(appid);
526     if (sharing_data.app_id.empty())
527       continue;
528
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);
532
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]);
538         }
539       }
540
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);
544     }
545   }
546
547   LOGD("RemovePrivateSharing");
548   return ERROR_NONE;
549 }
550
551 int SharedFile::CopyPrivateFile(shared_ptr<item::AbstractItem> item) {
552   if (item == nullptr) {
553     LOGE("Invalid paramenter");
554     return ERROR_INVALID_PARAMETER;
555   }
556
557   list<map<string, string>> path_map_list = item->GetPathMapList();
558   if (path_map_list.empty())
559     return ERROR_NONE;
560
561   if (!MakeDir(GetDir((*(path_map_list.begin())).begin()->second).c_str()))
562     return ERROR_IO_ERROR;
563
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());
569     }
570   }
571
572   return ERROR_NONE;
573 }
574
575 }  // namespace item
576 }  // namespace notification