* @file privacy_privilege_manager.c
* @author Piotr Sawicki <p.sawicki2@partner.samsung.com>
* @version 1.0
- * @brief This file contains implementation of privacy_privilege_manager.h CAPI.
+ * @brief The implementation of Privacy Privilege Manager CAPI.
*/
#include <stdlib.h>
#include <privacy_privilege_manager.h>
-askuser_client *client = NULL;
-struct ppm_private_struct {} *ppm_private = NULL;
+#define UNUSED __attribute__((unused))
+struct ppm_private_s {
+ askuser_client *client;
+ GIOChannel *channel;
+ GIOCondition condition;
+ guint watch_id;
+};
+typedef struct ppm_private_s ppm_private;
+
+struct ppm_callback_closure_s {
+ void *user_data;
+ ppm_popup_response_cb callback;
+};
+typedef struct ppm_callback_closure_s ppm_callback_closure;
+
+static ppm_private *ppm_handle = NULL;
+
+static void ppm_private_init(ppm_private *handle)
+{
+ handle->channel = NULL;
+ handle->condition = 0;
+ handle->watch_id = 0;
+}
static ppm_error_e ask_user_to_ppm_error(int ask_error)
{
ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
break;
case ASKUSER_API_UNKNOWN_ERROR:
- ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR;
+ ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN;
break;
case ASKUSER_API_OUT_OF_MEMORY:
ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
return ret;
}
-static ppm_check_result_e ask_user_check_result_to_pps(askuser_check_result result)
+static ppm_check_result_e ask_user_check_result_to_ppm(askuser_check_result result)
{
switch (result) {
case ASKUSER_CHECK_RESULT_ALLOW:
return PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY;
}
+static ppm_popup_result_e askuser_client_popup_result_to_ppm(askuser_popup_result result)
+{
+ switch (result) {
+ case ASKUSER_POPUP_RESULT_ALLOW_FOREVER:
+ return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_ALLOW_FOREVER;
+ case ASKUSER_POPUP_RESULT_DENY_FOREVER:
+ return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_FOREVER;
+ case ASKUSER_POPUP_RESULT_DENY_ONCE:
+ return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE;
+ }
+
+ return PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE;
+}
+
+static ppm_call_cause_e askuser_client_popup_cause_to_ppm(askuser_call_cause cause)
+{
+ switch (cause) {
+ case ASKUSER_CALL_CAUSE_ANSWER:
+ return PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER;
+ case ASKUSER_CALL_CAUSE_ERROR:
+ case ASKUSER_CALL_CAUSE_FINALIZE:
+ return PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR;
+ }
+
+ return ASKUSER_CALL_CAUSE_ERROR;
+}
+
static int g_io_condition_to_askuser_events(GIOCondition cond)
{
return ((cond & G_IO_IN) ? ASKUSER_READ_EVENT : 0) |
((events & ASKUSER_WRITE_EVENT) ? G_IO_OUT : 0);
}
+static gboolean ppm_error_condition(GIOCondition cond)
+{
+ return !!(cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL));
+}
+
+static gboolean ppm_is_connected(ppm_private *handle)
+{
+ return handle->channel != NULL;
+}
+
+static gboolean ppm_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+ int fd, events;
+ ppm_private *handle = (ppm_private *) data;
+
+ fd = g_io_channel_unix_get_fd(src);
+ events = g_io_condition_to_askuser_events(cond);
+
+ (void) askuser_client_process(handle->client, fd,
+ ppm_error_condition(cond) ? ASKUSER_EMPTY_EVENTS : events);
+
+ return TRUE;
+}
+
static void ask_status_callback(int fd, int events, void *p_user_data)
{
- (void) fd;
- (void) events;
- (void) p_user_data;
- g_io_condition_to_askuser_events(0);
- askuser_events_to_g_io_condition(0);
- // TODO register GIOChannel and GIOSource
+ ppm_private *handle = (ppm_private *) p_user_data;
+ GIOCondition gio_condition = askuser_events_to_g_io_condition(events);
+
+ if (events == ASKUSER_EMPTY_EVENTS) {
+ if (ppm_is_connected(handle)) {
+ g_source_remove(handle->watch_id);
+ g_io_channel_unref(handle->channel);
+ ppm_private_init(handle);
+ }
+ return;
+ }
+
+ if (!ppm_is_connected(handle)) {
+ handle->condition = gio_condition;
+ handle->channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_encoding (handle->channel, NULL, NULL);
+ g_io_channel_set_close_on_unref(handle->channel, FALSE);
- // TODO register callback
+ handle->watch_id = g_io_add_watch(handle->channel,
+ handle->condition | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ ppm_gio_cb,
+ handle);
+ return;
+ }
+
+ if (handle->condition != gio_condition) {
+ handle->condition = gio_condition;
+ g_source_remove(handle->watch_id);
+ handle->watch_id = g_io_add_watch(handle->channel,
+ handle->condition | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ ppm_gio_cb,
+ handle);
+ }
+}
+
+static void ppm_popup_response_callback(UNUSED int request_id, askuser_call_cause cause,
+ askuser_popup_result result, void *p_user_data)
+{
+ ppm_callback_closure *callback_closure = (ppm_callback_closure *) p_user_data;
+
+ /* Don't invoke callback while the application is finishing. The user data
+ * may already have been destroyed.
+ */
+ if (cause == ASKUSER_CALL_CAUSE_FINALIZE) {
+ free(callback_closure);
+ return;
+ }
+
+ ppm_call_cause_e ppm_cause = askuser_client_popup_cause_to_ppm(cause);
+ ppm_check_result_e ppm_result = askuser_client_popup_result_to_ppm(result);
+
+ callback_closure->callback(ppm_cause, ppm_result, callback_closure->user_data);
+
+ free(callback_closure);
+}
+
+static void ppm_free_client()
+{
+ if (ppm_handle != NULL) {
+ askuser_client_finalize(ppm_handle->client);
+ free(ppm_handle);
+ ppm_handle = NULL;
+ }
}
static int ppm_init_client()
{
- if (ppm_private == NULL) {
- ppm_private = (struct ppm_private_struct *) malloc(sizeof(struct ppm_private_struct));
- if (ppm_private == NULL) {
+ if (ppm_handle == NULL) {
+ ppm_handle = (ppm_private *) calloc(1, sizeof(ppm_private));
+ if (ppm_handle == NULL) {
return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
}
- int ret = askuser_client_initialize(&client, ask_status_callback, ppm_private);
+ ppm_private_init(ppm_handle);
+
+ int ret = askuser_client_initialize(&ppm_handle->client, ask_status_callback, ppm_handle);
if (ret != ASKUSER_API_SUCCESS) {
- free(ppm_private);
- ppm_private = NULL;
+ free(ppm_handle);
+ ppm_handle = NULL;
return ask_user_to_ppm_error(ret);
}
+
+ ret = atexit(ppm_free_client);
+ if (ret != 0) {
+ askuser_client_finalize(ppm_handle->client);
+ free(ppm_handle);
+ ppm_handle = NULL;
+ return PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN;
+ }
}
return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
EXPORT_API
int ppm_check_privilege(const char *privilege, ppm_check_result_e *result)
{
- if (!privilege || !result)
+ if (!privilege || !result) {
return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+ }
int ret = ppm_init_client();
if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
}
askuser_check_result check_result;
- ret = askuser_client_check_privilege(client, privilege, &check_result);
+ ret = askuser_client_check_privilege(ppm_handle->client, privilege, &check_result);
if (ret != ASKUSER_API_SUCCESS) {
return ask_user_to_ppm_error(ret);
}
- *result = ask_user_check_result_to_pps(check_result);
+ *result = ask_user_check_result_to_ppm(check_result);
return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
}
-static void ppm_popup_response_callback(int request_id, askuser_call_cause cause,
- askuser_popup_result result, void *p_user_data)
-{
- (void) request_id;
- (void) cause;
- (void) result;
- (void) p_user_data;
-
- // TODO find callback (request_id) and user_data
-
- // TODO convert cause and result
-
- // TODO call callback
-
- // TODO unregister callback and user_data
-}
-
EXPORT_API
-int ppm_popup_request(const char *privilege, ppm_popup_response_cb callback,
- void *user_data)
+int ppm_popup_request(const char *privilege, ppm_popup_response_cb callback, void *user_data)
{
if (!privilege || !callback) {
return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
return ret;
}
- int request_id;
- ret = askuser_client_popup_request(client, privilege, ppm_popup_response_callback,
- ppm_private, &request_id);
+ ppm_callback_closure *callback_closure = (ppm_callback_closure *) calloc(1, sizeof(ppm_callback_closure));
+ if (callback_closure == NULL) {
+ return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
+ }
+
+ callback_closure->callback = callback;
+ callback_closure->user_data = user_data;
+
+ ret = askuser_client_popup_request(ppm_handle->client, privilege, ppm_popup_response_callback,
+ callback_closure, NULL);
if (ret != ASKUSER_API_SUCCESS) {
+ free(callback_closure);
return ask_user_to_ppm_error(ret);
}
- // TODO store callback and user_data under request_id key
- (void) callback;
- (void) user_data;
-
return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
}
+
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/**
+ * @file privacy_privilege_manager.c
+ * @author Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @version 1.0
+ * @brief This file contains test of CAPI for Privacy Privilege Manager
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <privacy_privilege_manager.h>
+
+const char *result_to_str(ppm_popup_result_e result)
+{
+ switch (result) {
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_ALLOW_FOREVER:
+ return "ALLOW_FOREVER";
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_FOREVER:
+ return "DENY_FOREVER";
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESULT_DENY_ONCE:
+ return "DENY_ONCE";
+ }
+
+ return "UNKNOWN";
+}
+
+void popup_response_cb(ppm_call_cause_e cause, ppm_popup_result_e result, void *user_data)
+{
+ int id = (int) user_data;
+
+ printf("resp_id: %d ", id);
+ switch (cause) {
+ case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ANSWER:
+ printf("popup answer: %s\n", result_to_str(result));
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR:
+ printf("popup cause PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR\n");
+ break;
+ }
+
+ printf(">");
+ fflush(stdout);
+}
+
+static void print_help()
+{
+ printf("0 <privilege> - check privilege status\n");
+ printf("1 <privilege> - send popup request\n");
+ printf("h - print help\n");
+ printf("q - quit\n");
+ printf(">");
+ fflush(stdout);
+}
+
+static void print_error(ppm_error_e error)
+{
+ switch (error) {
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE:
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR:
+ printf("I/O error\n");
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER:
+ printf("Invalid parameters\n");
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY:
+ printf("Out of memory\n");
+ case PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN:
+ printf("Unknown error\n");
+ break;
+ }
+}
+
+static void print_check_result(ppm_check_result_e result)
+{
+ printf("res: ");
+
+ switch (result) {
+ case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
+ printf("ALLOW\n");
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
+ printf("DENY\n");
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
+ printf("ASK\n");
+ break;
+ }
+
+ printf(">");
+ fflush(stdout);
+}
+
+gboolean main_loop_cb(GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+ int ret;
+ char buffer[4096];
+ ppm_check_result_e result;
+
+ (void) channel; (void) cond; (void) user_data;
+
+ ret = read(0, buffer, sizeof(buffer));
+ if (ret < 0) {
+ printf("read from stdin failed\n");
+ exit(1);
+ }
+
+ buffer[ret - 1] = '\0';
+ int id = rand() % 1024;
+
+ switch (buffer[0]) {
+ case '0':
+ if (strlen(buffer) < 3) {
+ print_help();
+ break;
+ }
+ ret = ppm_check_privilege(&buffer[2], &result);
+ if (ret == PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
+ print_check_result(result);
+ }
+ else {
+ print_error(ret);
+ }
+ break;
+ case '1':
+ if (strlen(buffer) < 3) {
+ print_help();
+ break;
+ }
+ buffer[ret - 1] = '\0';
+ print_error(ppm_popup_request(&buffer[2], popup_response_cb, (void *)id));
+ break;
+ case 'q':
+ exit(0);
+ case 'h':
+ default:
+ print_help();
+ break;
+ }
+
+ return TRUE;
+}
+
+int main(int argc, char **argv)
+{
+ (void) argc; (void) argv;
+
+ srand(time(0));
+ print_help();
+
+ GMainLoop *mainloop = g_main_loop_new(NULL, FALSE);
+
+ GIOChannel *channel = g_io_channel_unix_new(0);
+ g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, main_loop_cb, NULL);
+
+ g_main_loop_run(mainloop);
+
+ return 0;
+}