Add the 'privilege' parameter to popup response callback
[platform/core/security/askuser.git] / src / capi / impl / privacy_privilege_manager.c
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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 /**
18  * @file        privacy_privilege_manager.c
19  * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
20  * @brief       The implementation of Privacy Privilege Manager CAPI.
21  */
22
23 #include <stdlib.h>
24 #include <glib.h>
25 #include <askuser-notification-client.h>
26
27 #include <privacy_privilege_manager.h>
28
29 #define UNUSED __attribute__((unused))
30
31 struct ppm_private_s {
32     askuser_client *client;
33     GIOChannel *channel;
34     GIOCondition condition;
35     guint watch_id;
36 };
37 typedef struct ppm_private_s ppm_private;
38
39 struct ppm_callback_closure_s {
40     void *user_data;
41     ppm_popup_response_cb callback;
42 };
43 typedef struct ppm_callback_closure_s ppm_callback_closure;
44
45 static ppm_private *ppm_handle = NULL;
46
47 static void ppm_private_init(ppm_private *handle)
48 {
49     handle->channel = NULL;
50     handle->condition = 0;
51     handle->watch_id = 0;
52 }
53
54 static ppm_error_e ask_user_to_ppm_error(int ask_error)
55 {
56     ppm_error_e ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
57
58     switch (ask_error) {
59         case ASKUSER_API_SUCCESS:
60             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
61                 break;
62         case ASKUSER_API_UNKNOWN_ERROR:
63             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN;
64             break;
65         case ASKUSER_API_OUT_OF_MEMORY:
66             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
67             break;
68         case ASKUSER_API_INVALID_PARAM:
69             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
70             break;
71         case ASKUSER_API_CONNECTION_ERROR:
72             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR;
73             break;
74         case ASKUSER_API_ALREADY_IN_PROGRESS:
75             ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS;
76         default:
77             break;
78     }
79
80     return ret;
81 }
82
83 static ppm_check_result_e ask_user_check_result_to_ppm(askuser_check_result result)
84 {
85     switch (result) {
86         case ASKUSER_CHECK_RESULT_ALLOW:
87             return PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW;
88         case ASKUSER_CHECK_RESULT_DENY:
89             return PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY;
90         case ASKUSER_CHECK_RESULT_ASK:
91             return PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK;
92     }
93
94     return PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY;
95 }
96
97 static ppm_popup_result_e askuser_client_popup_result_to_ppm(askuser_popup_result result)
98 {
99     switch (result) {
100         case ASKUSER_POPUP_RESULT_ALLOW_FOREVER:
101                return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_ALLOW_FOREVER;
102         case ASKUSER_POPUP_RESULT_DENY_FOREVER:
103             return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_FOREVER;
104         case ASKUSER_POPUP_RESULT_DENY_ONCE:
105             return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE;
106     }
107
108     return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE;
109 }
110
111 static ppm_call_cause_e askuser_client_popup_cause_to_ppm(askuser_call_cause cause)
112 {
113     switch (cause) {
114         case ASKUSER_CALL_CAUSE_ANSWER:
115             return PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER;
116         case ASKUSER_CALL_CAUSE_ERROR:
117         case ASKUSER_CALL_CAUSE_FINALIZE:
118             return PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR;
119     }
120
121     return ASKUSER_CALL_CAUSE_ERROR;
122 }
123
124 static int g_io_condition_to_askuser_events(GIOCondition cond)
125 {
126     return ((cond & G_IO_IN) ? ASKUSER_READ_EVENT : 0) |
127            ((cond & G_IO_OUT) ? ASKUSER_WRITE_EVENT : 0);
128 }
129
130 static GIOCondition askuser_events_to_g_io_condition(int events)
131 {
132     return ((events & ASKUSER_READ_EVENT) ? G_IO_IN : 0) |
133            ((events & ASKUSER_WRITE_EVENT) ? G_IO_OUT : 0);
134 }
135
136 static gboolean ppm_error_condition(GIOCondition cond)
137 {
138     return !!(cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL));
139 }
140
141 static gboolean ppm_is_connected(ppm_private *handle)
142 {
143     return handle->channel != NULL;
144 }
145
146 static gboolean ppm_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
147 {
148     int fd, events;
149     ppm_private *handle = (ppm_private *) data;
150
151     fd = g_io_channel_unix_get_fd(src);
152     events = g_io_condition_to_askuser_events(cond);
153
154     (void) askuser_client_process(handle->client, fd,
155                                   ppm_error_condition(cond) ? ASKUSER_EMPTY_EVENTS : events);
156
157     return TRUE;
158 }
159
160 static void ask_status_callback(int fd, int events, void *p_user_data)
161 {
162     ppm_private *handle = (ppm_private *) p_user_data;
163     GIOCondition gio_condition = askuser_events_to_g_io_condition(events);
164
165     if (events == ASKUSER_EMPTY_EVENTS) {
166         if (ppm_is_connected(handle)) {
167             g_source_remove(handle->watch_id);
168             g_io_channel_unref(handle->channel);
169             ppm_private_init(handle);
170         }
171         return;
172     }
173
174     if (!ppm_is_connected(handle)) {
175         handle->condition = gio_condition;
176         handle->channel = g_io_channel_unix_new(fd);
177
178         g_io_channel_set_encoding (handle->channel, NULL, NULL);
179         g_io_channel_set_close_on_unref(handle->channel, FALSE);
180
181         handle->watch_id = g_io_add_watch(handle->channel,
182                                           handle->condition | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
183                                           ppm_gio_cb,
184                                           handle);
185         return;
186     }
187
188     if (handle->condition != gio_condition) {
189         handle->condition = gio_condition;
190         g_source_remove(handle->watch_id);
191         handle->watch_id = g_io_add_watch(handle->channel,
192                                           handle->condition | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
193                                           ppm_gio_cb,
194                                           handle);
195     }
196 }
197
198 static void ppm_popup_response_callback(UNUSED int request_id, askuser_call_cause cause,
199                                         askuser_popup_result result, const char *privilege,
200                                         void *p_user_data)
201 {
202     ppm_callback_closure *callback_closure = (ppm_callback_closure *) p_user_data;
203
204     /* Don't invoke callback while the application is finishing. The user data
205      * may already have been destroyed.
206      */
207     if (cause == ASKUSER_CALL_CAUSE_FINALIZE) {
208         free(callback_closure);
209         return;
210     }
211
212     ppm_call_cause_e ppm_cause = askuser_client_popup_cause_to_ppm(cause);
213     ppm_check_result_e ppm_result = askuser_client_popup_result_to_ppm(result);
214
215     callback_closure->callback(ppm_cause, ppm_result, privilege, callback_closure->user_data);
216
217     free(callback_closure);
218 }
219
220 static void ppm_free_client()
221 {
222     if (ppm_handle != NULL) {
223         askuser_client_finalize(ppm_handle->client);
224         free(ppm_handle);
225         ppm_handle = NULL;
226     }
227 }
228
229 static int ppm_init_client()
230 {
231     if (ppm_handle == NULL) {
232         ppm_handle = (ppm_private *) calloc(1, sizeof(ppm_private));
233         if (ppm_handle == NULL) {
234             return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
235         }
236
237         ppm_private_init(ppm_handle);
238
239         int ret = askuser_client_initialize(&ppm_handle->client, ask_status_callback, ppm_handle);
240         if (ret != ASKUSER_API_SUCCESS) {
241             free(ppm_handle);
242             ppm_handle = NULL;
243             return ask_user_to_ppm_error(ret);
244         }
245
246         ret = atexit(ppm_free_client);
247         if (ret != 0) {
248             askuser_client_finalize(ppm_handle->client);
249             free(ppm_handle);
250             ppm_handle = NULL;
251             return PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN;
252         }
253     }
254
255     return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
256 }
257
258 EXPORT_API
259 int ppm_check_privilege(const char *privilege, ppm_check_result_e *result)
260 {
261     if (!privilege || !result) {
262         return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
263     }
264
265     int ret = ppm_init_client();
266     if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
267         return ret;
268     }
269
270     askuser_check_result check_result = ASKUSER_CHECK_RESULT_DENY;
271     ret = askuser_client_check_privilege(ppm_handle->client, privilege, &check_result);
272     if (ret != ASKUSER_API_SUCCESS) {
273         return ask_user_to_ppm_error(ret);
274     }
275
276     *result = ask_user_check_result_to_ppm(check_result);
277
278     return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
279 }
280
281 EXPORT_API
282 int ppm_popup_request(const char *privilege, ppm_popup_response_cb callback, void *user_data)
283 {
284     if (!privilege || !callback) {
285         return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
286     }
287
288     int ret = ppm_init_client();
289     if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
290         return ret;
291     }
292
293     ppm_callback_closure *callback_closure = (ppm_callback_closure *) calloc(1, sizeof(ppm_callback_closure));
294     if (callback_closure == NULL) {
295         return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
296     }
297
298     callback_closure->callback = callback;
299     callback_closure->user_data = user_data;
300
301     ret = askuser_client_popup_request(ppm_handle->client, privilege, ppm_popup_response_callback,
302                                        callback_closure, NULL);
303     if (ret != ASKUSER_API_SUCCESS) {
304         free(callback_closure);
305         return ask_user_to_ppm_error(ret);
306     }
307
308     return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
309 }
310