From 709a13a274d8b5edaf9c133e7bbb352ac7b920c3 Mon Sep 17 00:00:00 2001 From: taesubkim Date: Thu, 17 Mar 2016 15:22:18 +0900 Subject: [PATCH] Change/check privilege Change-Id: I730cfb16b375d8d87137a7178014fbe96805168f Signed-off-by: Taesub Kim Signed-off-by: Deepak Kumar Sahu --- daemon/CMakeLists.txt | 2 +- daemon/include/vpnsvc.h | 9 +++ daemon/src/vpnsvc.c | 155 +++++++++++++++++++++++++++++++++++++-- framework/src/capi_vpn_service.c | 39 ++++++++-- include/vpn_service.h | 16 ++++ packaging/capi-vpn-service.spec | 3 + 6 files changed, 210 insertions(+), 14 deletions(-) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index e94f838..14e080d 100755 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -9,7 +9,7 @@ SET(INCLUDEDIR "\${prefix}/include") SET(DAEMON_DIR "${CMAKE_SOURCE_DIR}/daemon") SET(VERSION 0.1) -SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-package-manager") +SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-package-manager cynara-client cynara-creds-gdbus cynara-session") SET(pc_requires "capi-base-common") SET(SRCS diff --git a/daemon/include/vpnsvc.h b/daemon/include/vpnsvc.h index b6467a8..99c037f 100755 --- a/daemon/include/vpnsvc.h +++ b/daemon/include/vpnsvc.h @@ -30,8 +30,17 @@ extern "C" { #include "generated-code.h" +typedef enum _net_vpn_service_privilege_e +{ + PRIVILEGE_VPN_SERVICE = 0x00, + PRIVILEGE_VPN_SERVICE_ADMIN, + PRIVILEGE_INTERNET, +} net_vpn_service_privilege_e; + void vpnsvc_create_and_init(void); Vpnsvc *get_vpnsvc_object(void); +gboolean vpn_service_gdbus_check_privilege(GDBusMethodInvocation *invocation, + net_vpn_service_privilege_e _privilege); #ifdef __cplusplus } diff --git a/daemon/src/vpnsvc.c b/daemon/src/vpnsvc.c index 4df05ae..be80c9f 100755 --- a/daemon/src/vpnsvc.c +++ b/daemon/src/vpnsvc.c @@ -26,6 +26,10 @@ #include "vpndbus.h" #include "vpn_service_daemon.h" +#include "cynara-client.h" +#include "cynara-creds-gdbus.h" +#include "cynara-session.h" + #ifdef LOG_TAG #undef LOG_TAG #endif @@ -43,8 +47,17 @@ gboolean handle_vpn_init(Vpnsvc *object, { LOGD("handle_vpn_init"); - vpnsvc_tun_s handle_s; int result = VPNSVC_ERROR_NONE; + + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false + || vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_INTERNET) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + + vpnsvc_tun_s handle_s; GDBusMessage *msg; GUnixFDList *fd_list; int fd_list_length; @@ -66,6 +79,8 @@ gboolean handle_vpn_init(Vpnsvc *object, LOGD("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s", handle_s.fd, handle_s.index, handle_s.name); +done: + vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name); return TRUE; @@ -75,13 +90,23 @@ gboolean handle_vpn_deinit(Vpnsvc *object, GDBusMethodInvocation *invocation, const gchar *arg_dev_name) { + LOGD("handle_vpn_deinit"); + int result = VPNSVC_ERROR_NONE; - LOGD("handle_vpn_deinit"); + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false + || vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_INTERNET) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + LOGD("vpn_deinit, %s\n", arg_dev_name); result = vpn_daemon_deinit(arg_dev_name); +done: vpnsvc_complete_vpn_deinit(object, invocation, result); return TRUE; @@ -91,15 +116,24 @@ gboolean handle_vpn_protect(Vpnsvc *object, GDBusMethodInvocation *invocation, const gchar *arg_dev_name) { + LOGD("handle_vpn_protect"); + int result = VPNSVC_ERROR_NONE; + + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false + || vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_INTERNET) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + int socket; GDBusMessage *msg; GUnixFDList *fd_list; int fd_list_length; const int *fds; - LOGD("handle_vpn_protect"); - msg = g_dbus_method_invocation_get_message(invocation); fd_list = g_dbus_message_get_unix_fd_list(msg); fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length); @@ -111,6 +145,7 @@ gboolean handle_vpn_protect(Vpnsvc *object, result = vpn_daemon_protect(socket, arg_dev_name); +done: vpnsvc_complete_vpn_protect(object, invocation, result); return TRUE; @@ -128,10 +163,10 @@ gboolean handle_vpn_up(Vpnsvc *object, const gchar *arg_dns_suffix, guint arg_mtu) { - int result = VPNSVC_ERROR_NONE; - LOGD("handle_vpn_up"); + int result = VPNSVC_ERROR_NONE; + char* routes[arg_nr_routes]; int prefix[arg_nr_routes]; char **dns_servers = NULL; @@ -144,6 +179,13 @@ gboolean handle_vpn_up(Vpnsvc *object, gchar* route_dest; gint route_prefix; + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + LOGD("iface_index : %d", arg_iface_index); LOGD("local ip : %s", arg_local_ip); LOGD("remote ip : %s", arg_remote_ip); @@ -222,12 +264,22 @@ gboolean handle_vpn_down(Vpnsvc *object, gint arg_iface_index) { LOGD("handle_vpn_down"); + int result = VPNSVC_ERROR_NONE; + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + LOGD("vpn_down, %d\n", arg_iface_index); result = vpn_daemon_down(arg_iface_index); +done: + vpnsvc_complete_vpn_down(object, invocation, result); return TRUE; @@ -241,6 +293,7 @@ gboolean handle_vpn_block_networks(Vpnsvc *object, guint arg_nr_nets_orig) { LOGD("handle_vpn_block_networks"); + int result = VPNSVC_ERROR_NONE; char *nets_vpn[arg_nr_nets_vpn]; @@ -254,6 +307,14 @@ gboolean handle_vpn_block_networks(Vpnsvc *object, gchar* route_dest; gint route_prefix; + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false + || vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_INTERNET) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + LOGD("vpn_block_networks"); /* arg_nets_vpn check */ @@ -299,6 +360,8 @@ gboolean handle_vpn_block_networks(Vpnsvc *object, /* call function */ result = vpn_daemon_block_networks(nets_vpn, prefix_vpn, arg_nr_nets_vpn, nets_orig, prefix_orig, arg_nr_nets_orig); +done: + vpnsvc_complete_vpn_block_networks(object, invocation, result); return TRUE; @@ -307,13 +370,23 @@ gboolean handle_vpn_block_networks(Vpnsvc *object, gboolean handle_vpn_unblock_networks(Vpnsvc *object, GDBusMethodInvocation *invocation) { + LOGD("handle_vpn_unblock_networks"); + int result = VPNSVC_ERROR_NONE; - LOGD("handle_vpn_unblock_networks"); + /* check privilege */ + if (vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_VPN_SERVICE_ADMIN) == false + || vpn_service_gdbus_check_privilege(invocation, PRIVILEGE_INTERNET) == false) { + LOGE("permission denied, and finished request."); + result = VPNSVC_ERROR_PERMISSION_DENIED; + goto done; + } + LOGD("vpn_unblock_networks"); result = vpn_daemon_unblock_networks(); +done: vpnsvc_complete_vpn_unblock_networks(object, invocation, result); return TRUE; @@ -367,3 +440,71 @@ void vpnsvc_create_and_init(void) return; } + +gboolean vpn_service_gdbus_check_privilege(GDBusMethodInvocation *invocation, net_vpn_service_privilege_e _privilege) +{ + + int ret = 0; + int pid = 0; + char *user; + char *client; + char *client_session; + char *privilege = NULL; + cynara *p_cynara = NULL; + const char *sender_unique_name; + GDBusConnection *connection; + + connection = g_dbus_method_invocation_get_connection(invocation); + sender_unique_name = g_dbus_method_invocation_get_sender(invocation); + + ret = cynara_initialize(&p_cynara, NULL); + if (ret != CYNARA_API_SUCCESS) { + LOGD("cynara_initialize() failed"); + return FALSE; + } + + ret = cynara_creds_gdbus_get_pid(connection, sender_unique_name, &pid); + if (ret != CYNARA_API_SUCCESS) { + LOGD("cynara_creds_gdbus_get_pid() failed"); + return FALSE; + } + + ret = cynara_creds_gdbus_get_user(connection, sender_unique_name, USER_METHOD_DEFAULT, &user); + if (ret != CYNARA_API_SUCCESS) { + LOGD("cynara_creds_gdbus_get_user() failed"); + return FALSE; + } + + ret = cynara_creds_gdbus_get_client(connection, sender_unique_name, CLIENT_METHOD_DEFAULT, &client); + if (ret != CYNARA_API_SUCCESS) { + LOGD("cynara_creds_gdbus_get_client() failed"); + return FALSE; + } + + switch (_privilege) + { + case PRIVILEGE_VPN_SERVICE: + privilege = "http://tizen.org/privilege/vpnservice"; + break; + + case PRIVILEGE_VPN_SERVICE_ADMIN : + privilege = "http://tizen.org/privilege/vpnservice.admin"; + break; + + case PRIVILEGE_INTERNET : + privilege = "http://tizen.org/privilege/internet"; + break; + default : + LOGD("Undifined privilege"); + return FALSE; + break; + } + + client_session = cynara_session_from_pid(pid); + + ret = cynara_check(p_cynara, client, client_session, user, privilege); + if (ret == CYNARA_API_ACCESS_ALLOWED); + LOGD("cynara PASS"); + + return (ret == CYNARA_API_ACCESS_ALLOWED) ? TRUE : FALSE; +} diff --git a/framework/src/capi_vpn_service.c b/framework/src/capi_vpn_service.c index 2afd277..08e6aa6 100755 --- a/framework/src/capi_vpn_service.c +++ b/framework/src/capi_vpn_service.c @@ -145,13 +145,20 @@ GVariant *_vpnsvc_invoke_dbus_method(GDBusConnection *connection, if (reply == NULL) { if (error != NULL) { - LOGE("g_dbus_connection_call_sync() failed" //LCOV_EXCL_LINE - "error [%d: %s]", error->code, error->message); - *dbus_error = VPNSVC_ERROR_IO_ERROR; //LCOV_EXCL_LINE - g_error_free(error); //LCOV_EXCL_LINE + if (error->code == G_DBUS_ERROR_ACCESS_DENIED){ + LOGE("g_dbus_connection_call_sync() failed" + "error [%d: %s]", error->code, error->message);//LCOV_EXCL_LINE + *dbus_error = VPNSVC_ERROR_PERMISSION_DENIED;//LCOV_EXCL_LINE + g_error_free(error);//LCOV_EXCL_LINE + } else { + LOGE("g_dbus_connection_call_sync() failed" + "error [%d: %s]", error->code, error->message);//LCOV_EXCL_LINE + *dbus_error = VPNSVC_ERROR_IO_ERROR;//LCOV_EXCL_LINE + g_error_free(error);//LCOV_EXCL_LINE + } } else { - LOGE("g_dbus_connection_call_sync() failed"); //LCOV_EXCL_LINE - *dbus_error = VPNSVC_ERROR_IPC_FAILED; //LCOV_EXCL_LINE + LOGE("g_dbus_connection_call_sync() failed");//LCOV_EXCL_LINE + *dbus_error = VPNSVC_ERROR_IPC_FAILED;//LCOV_EXCL_LINE } return NULL; @@ -257,6 +264,10 @@ EXPORT_API int vpnsvc_init(const char* iface_name, vpnsvc_h *handle) g_variant_new("(su)", VPNSVC_DBUS_SERVICE_NAME, 0), &dbus_result); + if (dbus_result == VPNSVC_ERROR_PERMISSION_DENIED){ + return VPNSVC_ERROR_PERMISSION_DENIED; + } + if (op == NULL) { _vpnsvc_deinit_vpnsvc_tun_s(tmp_s); //LCOV_EXCL_LINE LOGD("Service [%s] Start Failed!", VPNSVC_DBUS_SERVICE_NAME); //LCOV_EXCL_LINE @@ -355,6 +366,10 @@ EXPORT_API int vpnsvc_deinit(vpnsvc_h handle) g_variant_new("(s)", tun_s->name), &dbus_result); + if (dbus_result == VPNSVC_ERROR_PERMISSION_DENIED){ + return VPNSVC_ERROR_PERMISSION_DENIED; + } + if (op == NULL) { return VPNSVC_ERROR_IPC_FAILED; //LCOV_EXCL_LINE } else { @@ -410,6 +425,10 @@ EXPORT_API int vpnsvc_protect(vpnsvc_h handle, int socket_fd, const char* iface_ socket_fd, &dbus_result); + if (dbus_result == VPNSVC_ERROR_PERMISSION_DENIED){ + return VPNSVC_ERROR_PERMISSION_DENIED; + } + if (op == NULL) { return VPNSVC_ERROR_IPC_FAILED; //LCOV_EXCL_LINE } else { @@ -688,6 +707,10 @@ EXPORT_API int vpnsvc_block_networks(vpnsvc_h handle, nets_param_orig, num_allow_routes_orig), &dbus_result); + if (dbus_result == VPNSVC_ERROR_PERMISSION_DENIED){ + return VPNSVC_ERROR_PERMISSION_DENIED; + } + if (op == NULL) { return VPNSVC_ERROR_IPC_FAILED; //LCOV_EXCL_LINE } else { @@ -734,6 +757,10 @@ EXPORT_API int vpnsvc_unblock_networks(vpnsvc_h handle) g_variant_new("()"), &dbus_result); + if (dbus_result == VPNSVC_ERROR_PERMISSION_DENIED){ + return VPNSVC_ERROR_PERMISSION_DENIED; + } + if (op == NULL) { return VPNSVC_ERROR_IPC_FAILED; //LCOV_EXCL_LINE } else { diff --git a/include/vpn_service.h b/include/vpn_service.h index c1091ef..adefef3 100755 --- a/include/vpn_service.h +++ b/include/vpn_service.h @@ -108,11 +108,15 @@ int vpnsvc_init(const char* iface_name, vpnsvc_h *handle); /** * @brief De-Initializes VPN interface. * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/vpnservice \n + * %http://tizen.org/privilege/internet * @param[in] handle The VPN interface handle * @return 0 on success. otherwise, a negative error value. * @retval #VPNSVC_ERROR_NONE Success * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon + * @retval #VPNSVC_ERROR_PERMISSION_DENIED Permission Denied * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported * @pre Before calling this function, VPN interface should be initialized already. * @see vpnsvc_init() @@ -123,6 +127,9 @@ int vpnsvc_deinit(vpnsvc_h handle); * @brief Protect a socket from VPN connections. * @details After protecting, data sent through this socket will go directly to the underlying network. * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/vpnservice \n + * %http://tizen.org/privilege/internet * @param[in] handle The VPN interface handle * @param[in] socket_fd The opened socket file descriptor * @param[in] iface_name The network interface name (e.g., interface name such as eth0, ppp0, etc) through which the VPN is working @@ -131,6 +138,7 @@ int vpnsvc_deinit(vpnsvc_h handle); * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VPNSVC_ERROR_IO_ERROR I/O Error (e.g. socket I/O error) * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon + * @retval #VPNSVC_ERROR_PERMISSION_DENIED Permission Denied * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported */ int vpnsvc_protect(vpnsvc_h handle, int socket_fd, const char* iface_name); @@ -170,6 +178,9 @@ int vpnsvc_write(vpnsvc_h handle, const char* data, size_t size); /** * @brief Blocks all traffics except specified allowing networks. * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/vpnservice \n + * %http://tizen.org/privilege/internet * @param[in] handle The VPN interface handle * @param[in] routes_dest_vpn_addr Destination address of the routes, the list of allowing networks over VPN interface (e.g., VPN interface such as tun0, etc). * @param[in] routes_vpn_prefix The prefix of VPN interface, netmask length (also called a prefix, e.g. 8, 16, 24, 32). @@ -181,6 +192,7 @@ int vpnsvc_write(vpnsvc_h handle, const char* data, size_t size); * @retval #VPNSVC_ERROR_NONE Success * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon + * @retval #VPNSVC_ERROR_PERMISSION_DENIED Permission Denied * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported * @post Please call vpnsvc_unblock_networks() if you want to allow all traffics. * @see vpnsvc_unblock_networks() @@ -196,11 +208,15 @@ int vpnsvc_block_networks(vpnsvc_h handle, /** * @brief Removes any restrictions imposed by vpnsvc_block_networks(). * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/vpnservice \n + * %http://tizen.org/privilege/internet * @param[in] handle The VPN interface handle * @return 0 on success. otherwise, a negative error value. * @retval #VPNSVC_ERROR_NONE Success * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon + * @retval #VPNSVC_ERROR_PERMISSION_DENIED Permission Denied * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported */ int vpnsvc_unblock_networks(vpnsvc_h handle); diff --git a/packaging/capi-vpn-service.spec b/packaging/capi-vpn-service.spec index 9c6c00c..f2bcd0b 100755 --- a/packaging/capi-vpn-service.spec +++ b/packaging/capi-vpn-service.spec @@ -19,6 +19,9 @@ BuildRequires: pkgconfig(capi-appfw-application) BuildRequires: pkgconfig(capi-appfw-package-manager) BuildRequires: pkgconfig(capi-appfw-app-manager) BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-creds-gdbus) +BuildRequires: pkgconfig(cynara-session) Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig -- 2.7.4