Change UI and policy setup to use privilege groups instead of privileges
[platform/core/security/askuser.git] / src / agent / notification-daemon / AskUserTalker.cpp
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co.
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  * @file        src/notification-daemon/GuiRunner.h
18  * @author      Oskar Ĺšwitalski <o.switalski@samsung.com>
19  * @brief       Definition of AskUserTalker class
20  */
21
22 #include "AskUserTalker.h"
23
24 #include <iostream>
25 #include <string>
26
27 #include <socket/Socket.h>
28 #include <socket/SelectRead.h>
29 #include <types/NotificationResponse.h>
30 #include <types/Protocol.h>
31 #include <types/NotificationRequest.h>
32 #include <exception/ErrnoException.h>
33 #include <exception/Exception.h>
34 #include <translator/Translator.h>
35 #include <config/Path.h>
36 #include <config/Limits.h>
37
38 #include <security-manager.h>
39 #include <privilegemgr/privilege_info.h>
40 #include <glib.h>
41
42 namespace AskUser {
43
44 namespace Notification {
45
46 namespace {
47
48 inline void throwOnSecurityPrivilegeError(std::string err, int ret)
49 {
50     if (ret != SECURITY_MANAGER_SUCCESS)
51         throw Exception(err + " : " + std::to_string(ret));
52 }
53
54 inline const char *dropPrefix(const char* app)
55 {
56     constexpr char prefix[] = "User::App::";
57     constexpr size_t prefixSize = sizeof(prefix) - 1;
58     return strncmp(app, prefix, prefixSize) ? app : app + prefixSize;
59 }
60
61 void setSecurityLevel(const std::string &app, const std::string &perm, const std::string &level)
62 {
63     int ret;
64
65     try {
66         if (level != "Allow" && level != "Deny")
67             throw std::invalid_argument("Not allowed security level <" + level + ">");
68
69         ALOGD("SecurityManager: Setting security level to " << level);
70
71         policy_update_req *policyUpdateRequest = nullptr;
72
73         ret = security_manager_policy_update_req_new(&policyUpdateRequest);
74         throwOnSecurityPrivilegeError("security_manager_policy_update_req_new", ret);
75
76         std::unique_ptr<policy_update_req, decltype(security_manager_policy_update_req_free)*>
77             policyUpdateRequestPtr(policyUpdateRequest, security_manager_policy_update_req_free);
78
79         char* privacy_name = nullptr;
80
81         ret = privilege_info_get_privacy_by_privilege(perm.c_str(), &privacy_name);
82         if (ret != PRVMGR_ERR_NONE || !privacy_name) {
83             ALOGE("Unable to get privacy group for privilege: <" << perm << ">, err: <" << ret << ">");
84             throw Exception("Can't get privacy group name for privilege " + perm);
85         }
86
87         GList *privilege_list = nullptr;
88
89         ret = privilege_info_get_privilege_list_by_privacy(privacy_name, &privilege_list);
90         free(privacy_name); // not needed anymore below this place
91
92         if (ret != PRVMGR_ERR_NONE || !privilege_list) {
93             ALOGE("Unable to get privacy group list of privileges; err: <" << ret <<  ">" );
94             throw Exception("Unable to get privacy list of privielges");
95         }
96
97         auto list_deleter = [](GList* l) { g_list_free_full(l, free); };
98         std::unique_ptr<GList,
99             decltype(list_deleter)> privilge_listPtr(privilege_list, list_deleter);
100         std::vector<std::unique_ptr<policy_entry,
101             decltype(security_manager_policy_entry_free)*>> policyEntries;
102
103         for (GList *l = privilege_list; l != NULL; l = l->next) {
104             char *privilege_name = static_cast<char*>(l->data);
105             policy_entry *policyEntry = nullptr;
106
107             ret = security_manager_policy_entry_new(&policyEntry);
108             throwOnSecurityPrivilegeError("security_manager_policy_entry_new", ret);
109
110             policyEntries.push_back(std::unique_ptr<policy_entry,
111                 decltype(security_manager_policy_entry_free)*>(policyEntry, security_manager_policy_entry_free));
112
113             ret = security_manager_policy_entry_set_application(policyEntry,
114                                                         dropPrefix(app.c_str()));
115             throwOnSecurityPrivilegeError("security_manager_policy_entry_set_application", ret);
116
117             ret = security_manager_policy_entry_set_privilege(policyEntry, privilege_name);
118             throwOnSecurityPrivilegeError("security_manager_policy_entry_set_privilege", ret);
119
120             ret = security_manager_policy_entry_set_level(policyEntry, level.c_str());
121             throwOnSecurityPrivilegeError("security_manager_policy_entry_admin_set_level", ret);
122
123             ret = security_manager_policy_update_req_add_entry(policyUpdateRequest, policyEntry);
124             throwOnSecurityPrivilegeError("security_manager_policy_update_req_add_entry", ret);
125         }
126
127         ret = security_manager_policy_update_send(policyUpdateRequest);
128         throwOnSecurityPrivilegeError("security_manager_policy_update_send", ret);
129
130         ALOGD("SecurityManager: Setting level succeeded");
131     } catch (std::exception &e) {
132         ALOGE("SecurityManager: Failed <" << e.what() << ">");
133     }
134 }
135
136 } /* namespace */
137
138
139 AskUserTalker::AskUserTalker(GuiRunner *gui) : m_gui(gui) {
140     m_gui->setDropHandler([&](){return this->shouldDismiss();});
141 }
142
143 AskUserTalker::~AskUserTalker()
144 {
145     try {
146         Socket::close(sockfd);
147     } catch (const std::exception &e) {
148         ALOGE(std::string("~AskUserTalker") + e.what());
149     } catch (...) {
150         ALOGE("~AskUserTalker: Unknow error");
151     }
152 }
153
154 void AskUserTalker::run()
155 {
156     sockfd = Socket::connect(Path::getSocketPath());
157
158     while (!stopFlag) {
159         size_t size;
160         char *buf;
161         NotificationResponse response;
162
163         ALOGD("Waiting for request...");
164
165         if (!Socket::recv(sockfd, &size, sizeof(size))) {
166             ALOGI("Askuserd closed connection, closing...");
167             break;
168         }
169
170         Limits::checkSizeLimit(size);
171
172         buf = new char[size];
173
174         if (!Socket::recv(sockfd, buf, size)) {
175             ALOGI("Askuserd closed connection, closing...");
176             break;
177         }
178
179         NotificationRequest request = Translator::Gui::dataToNotificationRequest(buf);
180         delete[] buf;
181         ALOGD("Recieved data " << request.data.client << " " << request.data.privilege);
182
183         response.response = m_gui->popupRun(request.data.client, request.data.privilege);
184         response.id = request.id;
185
186         if (response.response == NResponseType::None) {
187             continue;
188         }
189
190         if (!Socket::send(sockfd, &response, sizeof(response))) {
191             ALOGI("Askuserd closed connection, closing...");
192             break;
193         }
194
195         uint8_t ack = 0x00;
196         if (!Socket::recv(sockfd, &ack, sizeof(ack))) {
197             ALOGI("Askuserd closed connection, closing...");
198             break;
199         }
200
201         if (ack != Protocol::ackCode)
202             throw Exception("Incorrect ack");
203
204         switch (response.response) {
205         case NResponseType::Error:
206             throw Exception(m_gui->getErrorMsg());
207         case NResponseType::Allow:
208         case NResponseType::Never:
209             setSecurityLevel(request.data.client, request.data.privilege,
210                              Translator::Gui::responseToString(response.response));
211         default:
212             break;
213         }
214     }
215 }
216
217 void AskUserTalker::stop()
218 {
219     m_gui->stop();
220     Socket::close(sockfd);
221 }
222
223 bool AskUserTalker::shouldDismiss()
224 {
225     Socket::SelectRead select;
226     select.add(sockfd);
227     if (select.exec() == 0)
228         return false;
229
230     uint8_t a = 0x00;
231     Socket::recv(sockfd, &a, sizeof(a));
232
233     if (a != Protocol::dissmisCode)
234         throw Exception("Incorrect dismiss flag");
235
236     return true;
237 }
238
239 } /* namespace Notification */
240
241 } /* namespace AskUser */