Include header file about string
[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
45 using namespace std;
46
47 namespace notification {
48 namespace item {
49 SharedFile::SharedFile() = default;
50 SharedFile::~SharedFile() = default;
51 SharedFile::SharingData::SharingData() = default;
52 SharedFile::SharingData::~SharingData() = default;
53 SharedFile::SharingTarget::SharingTarget() = default;
54 SharedFile::SharingTarget::~SharingTarget() = default;
55
56 const char* SharedFile::GetLastIndex(const char* path, const char* search) {
57   int i;
58   int search_len;
59   const char* index;
60
61   if (path == nullptr || search == nullptr)
62     return nullptr;
63
64   search_len = strlen(search);
65   index = path + strlen(path) - search_len;
66
67   while (index >= path) {
68     for (i = 0; i < search_len; i++) {
69       if (index[i] != search[i])
70         break;
71     }
72
73     if (i == search_len)
74       return index;
75
76     index--;
77   }
78
79   return nullptr;
80 }
81
82 bool SharedFile::MakeDir(const char* path) {
83   if (access(path, R_OK) == 0)
84     return true;
85
86   auto noti_dir = unique_ptr<GFile, decltype(&g_object_unref)>(
87                         g_file_new_for_path(path), g_object_unref);
88   if (noti_dir == nullptr)
89     return false;
90
91   GError* g_err = nullptr;
92   if (!g_file_make_directory(noti_dir.get(), nullptr, &g_err)) {
93     if (g_err) {
94       LOGE("Failed to make sharing dir[%s]", g_err->message);
95       g_error_free(g_err);
96     }
97     return false;
98   }
99
100   return true;
101 }
102
103 string SharedFile::GetDir(string path) {
104   int dir_len;
105   const char* index;
106   string dir;
107
108   if (path.empty())
109     return "";
110
111   index = GetLastIndex(path.c_str(), "/");
112   if (index == nullptr) {
113     LOGE("Failed to find directory separator");
114     return "";
115   }
116
117   dir_len = index - path.c_str() + 1;
118   if (dir_len <= 0 || dir_len > PATH_MAX)
119     return "";
120
121   dir.reserve(PATH_MAX);
122   snprintf(&dir[0], dir_len, "%s", path.c_str());
123
124   return dir;
125 }
126
127 int SharedFile::CopyFile(const char* source, const char* dest) {
128   GError* g_err = nullptr;
129   struct utimbuf ut = {0, };
130
131   if (source == nullptr || dest == nullptr) {
132     LOGE("Invalid parameter");
133     return ERROR_INVALID_PARAMETER;
134   }
135
136   auto dst = unique_ptr<GFile, decltype(&g_object_unref)>(
137                 g_file_new_for_path(dest), g_object_unref);
138   if (dst == nullptr) {
139     LOGE("dest path is wrong [%s]", dest);
140     return ERROR_IO_ERROR;
141   }
142
143   if (g_file_query_exists(dst.get(), nullptr)) {
144     LOGD("dst path already existed [%s]", dest);
145     return  ERROR_ALREADY_EXIST_ID;
146   }
147
148   auto src = unique_ptr<GFile, decltype(&g_object_unref)>(
149                 g_file_new_for_path(source), g_object_unref);
150   if (src == nullptr) {
151     LOGE("src path is wrong [%s]", source);
152     return ERROR_IO_ERROR;
153   }
154
155   if (!g_file_copy(src.get(), dst.get(), G_FILE_COPY_NOFOLLOW_SYMLINKS, nullptr,
156                 nullptr, nullptr, &g_err)) {
157     if (g_err) {
158       LOGE("Copying file from [%s] to [%s] is failed [%s]", source, dest,
159           g_err->message);
160       g_error_free(g_err);
161     }
162     return ERROR_IO_ERROR;
163   }
164
165   ut.modtime = time(nullptr);
166   if (g_utime(dest, &ut) != 0)
167     LOGD("Failed to set g_utime %d ", errno);
168
169   return ERROR_NONE;
170 }
171
172 vector<char*> SharedFile::ConvertListToArray(const list<string>& data) {
173   vector<char*> v;
174
175   if (data.empty())
176     return {};
177
178   for (const auto& i : data)
179     v.push_back(const_cast<char*>(i.c_str()));
180
181   return v;
182 }
183
184 bool SharedFile::IsPrivatePath(string path) const {
185   char* smack_label = nullptr;
186   bool ret = false;
187
188   if (path.empty()) {
189     LOGE("Invalid parameter");
190     return false;
191   }
192
193   if (smack_new_label_from_path(path.c_str(), XATTR_NAME_SMACK, 1, &smack_label)
194         <= 0) {
195     LOGE("smack_new_label_from_path failed");
196     return false;
197   }
198
199   if (GetLastIndex(smack_label, CHECK_LABEL) != nullptr)
200     ret = true;
201
202   free(smack_label);
203   return ret;
204 }
205
206 string SharedFile::GetDataPath(string app_id, string path) const {
207   string user_app;
208   string dir;
209
210   if (app_id.empty() || path.empty()) {
211     LOGE("Invalid parameter");
212     return nullptr;
213   }
214
215   tzplatform_set_user(getuid());
216   user_app = tzplatform_getenv(TZ_USER_APP);
217   tzplatform_reset_user();
218
219   dir = user_app + "/" + app_id + "/" + NOTI_PRIV_DATA_DIR + "/";
220   dir += string(GetLastIndex(path.c_str(), "/") + 1);
221
222   return dir;
223 }
224
225 int SharedFile::SetSharingData(SharingData sharing_data,
226     list<string> new_shared_file_list, list<string> new_receiver_group_list,
227     multimap<string, string> receiver_group_map) {
228   private_sharing_req* handle = nullptr;
229   vector<char*> path_array;
230   vector<char*> target_array;
231   const char* appid = nullptr;
232   int ret;
233
234   if (new_shared_file_list.empty() || new_receiver_group_list.empty()) {
235     LOGE("Invalid parameter");
236     return ERROR_INVALID_PARAMETER;
237   }
238
239   ret = security_manager_private_sharing_req_new(&handle);
240   if (ret != SECURITY_MANAGER_SUCCESS) {
241     LOGE("Failed to create private sharing request handle[%d]", ret);
242     return ERROR_IO_ERROR;
243   }
244
245   auto req = unique_ptr<private_sharing_req,
246                 decltype(&security_manager_private_sharing_req_free)>(
247                 handle, security_manager_private_sharing_req_free);
248   if (req == nullptr)
249     return ERROR_IO_ERROR;
250
251   appid = strdup(sharing_data.app_id.c_str());
252   if (appid == nullptr) {
253     LOGE("Failed to get Sender appid");
254     return ERROR_OUT_OF_MEMORY;
255   }
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 = strdup(sharing_data.app_id.c_str());
331   if (appid == nullptr) {
332     LOGE("Failed to get Sender appid");
333     return ERROR_OUT_OF_MEMORY;
334   }
335
336   ret = security_manager_private_sharing_req_set_owner_appid(req.get(), appid);
337   if (ret != SECURITY_MANAGER_SUCCESS) {
338     LOGE("Failed to set owner appid[%s][%d]", appid, ret);
339     return ERROR_IO_ERROR;
340   }
341
342   path_array = ConvertListToArray(sharing_data.shared_file_list);
343   if (path_array.empty()) {
344     LOGE("path_array is null");
345     return ERROR_IO_ERROR;
346   }
347
348   ret = security_manager_private_sharing_req_add_paths(req.get(),
349             const_cast<const char**>(path_array.data()), path_array.size());
350   if (ret != SECURITY_MANAGER_SUCCESS) {
351     LOGE("Failed to add paths [%d]", ret);
352     return ERROR_IO_ERROR;
353   }
354
355   target_array = ConvertListToArray(sharing_data.receiver_group_list);
356   if (target_array.empty()) {
357     LOGE("target_array is null");
358     return ERROR_IO_ERROR;
359   }
360
361   for (int i = 0; i < static_cast<int>(target_array.size()); i++) {
362     multimap<string, string>::iterator it;
363     for (it = receiver_group_map.begin(); it != receiver_group_map.end(); it++) {
364       if (it->first.compare(target_array[i]) == 0) {
365         ret = security_manager_private_sharing_req_set_target_appid(req.get(),
366                 it->second.c_str());
367         if (ret != SECURITY_MANAGER_SUCCESS) {
368           LOGE("Failed to set target appid [%s]", appid);
369           return ERROR_IO_ERROR;
370         }
371
372         ret = security_manager_private_sharing_drop(req.get());
373         if (ret != SECURITY_MANAGER_SUCCESS) {
374           LOGE("Failed to drop private sharing [%d]", ret);
375           return ERROR_IO_ERROR;
376         }
377       }
378     }
379   }
380
381   return ERROR_NONE;
382 }
383
384 SharedFile::SharingData SharedFile::FindSharingData(string appid) {
385   if (sharing_data_list_.size() == 0 || appid.empty())
386     return {};
387
388   for (auto sharing_data : sharing_data_list_) {
389     if (sharing_data.app_id.compare(appid) == 0)
390       return sharing_data;
391   }
392
393   return {};
394 }
395
396 int SharedFile::SetPrivateSharing(list<shared_ptr<AbstractItem>> notiList,
397     multimap<string, string> receiver_group_map) {
398   if (notiList.empty() || receiver_group_map.empty()) {
399     LOGE("Invalid parameter");
400     return ERROR_INVALID_PARAMETER;
401   }
402
403   for (auto& i : notiList) {
404     SharingData sharing_data;
405     list<string> new_shared_file_list;
406     list<string> new_receiver_group_list;
407
408     list<string> shared_path_list = i->GetSharedPath();
409     if (shared_path_list.empty())
410       continue;
411
412     string appid = i->GetSenderAppId();
413     if (appid.empty())
414       continue;
415
416     sharing_data = FindSharingData(appid);
417     if (!sharing_data.app_id.empty()) {
418       string noti_id = i->GetId();
419       list<string>::iterator it;
420       it = find_if(sharing_data.noti_id_list.begin(),
421                     sharing_data.noti_id_list.end(),
422                     [&noti_id](std::string id){
423                       return id.compare(noti_id) == 0;
424                     });
425       if (it == sharing_data.noti_id_list.end())
426         sharing_data.noti_id_list.push_back(noti_id);
427
428       for (auto& shared_path : shared_path_list) {
429         list<string>::iterator it;
430         it = find_if(sharing_data.shared_file_list.begin(),
431                     sharing_data.shared_file_list.end(),
432                     [&shared_path](std::string shared_file){
433                       return shared_file.compare(shared_path) == 0;
434                     });
435         if (it == sharing_data.shared_file_list.end()) {
436           sharing_data.shared_file_list.push_back(shared_path);
437           new_shared_file_list.push_back(shared_path);
438         }
439       }
440
441       list<string> receiver_list = i->GetReceiverList();
442       for (auto& receiver : receiver_list) {
443         list<string>::iterator it;
444         it = find_if(sharing_data.receiver_group_list.begin(),
445                     sharing_data.receiver_group_list.end(),
446                     [&receiver](std::string receiver_group){
447                       return receiver_group.compare(receiver) == 0;
448                     });
449         if (it == sharing_data.receiver_group_list.end()) {
450           sharing_data.receiver_group_list.push_back(receiver);
451           new_receiver_group_list.push_back(receiver);
452         }
453       }
454     } else {
455       sharing_data.app_id = appid;
456       sharing_data.dir = GetDir(*(shared_path_list.begin()));
457       sharing_data.noti_id_list.emplace_back(i->GetId());
458       sharing_data.shared_file_list = shared_path_list;
459       sharing_data.receiver_group_list = i->GetReceiverList();
460       sharing_data_list_.emplace_back(sharing_data);
461
462       new_shared_file_list = shared_path_list;
463       new_receiver_group_list = i->GetReceiverList();
464     }
465
466     if (SetSharingData(sharing_data, new_shared_file_list,
467                 new_receiver_group_list, receiver_group_map) == ERROR_NONE)
468       i->SetSharedPath();
469   }
470
471   LOGD("SetPrivateSharing");
472   return ERROR_NONE;
473 }
474
475 int SharedFile::UpdatePrivateSharing(list<shared_ptr<AbstractItem>> notiList,
476     multimap<string, string> receiver_group_map) {
477   if (notiList.empty() || receiver_group_map.empty()) {
478     LOGE("Invalid parameter");
479     return ERROR_INVALID_PARAMETER;
480   }
481
482   for (auto& i : notiList) {
483     list<string> new_shared_file_list;
484     list<string> new_receiver_group_list;
485     list<string> shared_path_list = i->GetSharedPath();
486     if (shared_path_list.empty())
487       continue;
488
489     string appid = i->GetSenderAppId();
490     SharingData sharing_data = FindSharingData(appid);
491     if (appid.empty() || sharing_data.app_id.empty())
492       continue;
493
494     for (auto& shared_path : shared_path_list) {
495       std::list<std::string>::iterator it;
496       it = std::find_if(sharing_data.shared_file_list.begin(),
497                     sharing_data.shared_file_list.end(),
498                     [&shared_path](std::string shared_file){
499                       return shared_file.compare(shared_path) == 0;
500                     });
501       if (it == sharing_data.shared_file_list.end()) {
502         sharing_data.shared_file_list.push_back(shared_path);
503         new_shared_file_list.push_back(shared_path);
504       }
505     }
506
507     new_receiver_group_list = i->GetReceiverList();
508     if (SetSharingData(sharing_data, new_shared_file_list,
509         new_receiver_group_list, receiver_group_map) == ERROR_NONE)
510       i->SetSharedPath();
511   }
512
513   LOGD("UpdatePrivateSharing");
514   return ERROR_NONE;
515 }
516
517 int SharedFile::RemovePrivateSharing(list<shared_ptr<AbstractItem>> notiList,
518     multimap<string, string> receiver_group_map) {
519   if (notiList.empty() || receiver_group_map.empty()) {
520     LOGE("Invalid parameter");
521     return ERROR_INVALID_PARAMETER;
522   }
523
524   for (auto& i : notiList) {
525     string appid = i->GetSenderAppId();
526     if (appid.empty())
527       continue;
528
529     SharingData sharing_data = FindSharingData(appid);
530     if (sharing_data.app_id.empty())
531       continue;
532
533     sharing_data.noti_id_list.remove(i->GetId());
534     if (sharing_data.noti_id_list.size() == 0) {
535       UnsetSharingData(sharing_data, receiver_group_map);
536
537       vector<char*> path_array = ConvertListToArray(sharing_data.shared_file_list);
538       if (!path_array.empty()) {
539         for (int i = 0; i < static_cast<int>(path_array.size()); i++) {
540           if (g_remove(path_array[i]) == -1)
541           LOGE("Failed to remove shared_file(%s)", path_array[i]);
542         }
543       }
544       g_rmdir(sharing_data.dir.c_str());
545     }
546   }
547
548   LOGD("RemovePrivateSharing");
549   return ERROR_NONE;
550 }
551
552 int SharedFile::CopyPrivateFile(shared_ptr<item::AbstractItem> item) {
553   if (item == nullptr) {
554     LOGE("Invalid paramenter");
555     return ERROR_INVALID_PARAMETER;
556   }
557
558   list<map<string, string>> path_map_list = item->GetPathMapList();
559   if (path_map_list.empty())
560     return ERROR_NONE;
561
562   if (!MakeDir(GetDir((*(path_map_list.begin())).begin()->second).c_str()))
563     return ERROR_IO_ERROR;
564
565   list<map<string, string>>::iterator list_it;
566   for (list_it = path_map_list.begin(); list_it != path_map_list.end(); ++list_it) {
567     map<string, string>::iterator map_it;
568     for (map_it = (*list_it).begin(); map_it != (*list_it).end(); map_it++) {
569       CopyFile((map_it->first).c_str(), (map_it->second).c_str());
570     }
571   }
572
573   return ERROR_NONE;
574 }
575
576 }  // namespace item
577 }  // namespace notification