From: David Zeuthen Date: Mon, 9 Feb 2009 20:53:51 +0000 (-0500) Subject: add the ObtainAuthorization() method and use in for the 'polkit-1 run' command X-Git-Tag: 0.91~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b891d8a3245d364975cecb2289c442f54b2327c6;p=platform%2Fupstream%2Fpolkit.git add the ObtainAuthorization() method and use in for the 'polkit-1 run' command Also add an example for this. --- diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml index 34a2b4b..a3d5741 100644 --- a/data/org.freedesktop.PolicyKit1.Authority.xml +++ b/data/org.freedesktop.PolicyKit1.Authority.xml @@ -6,6 +6,8 @@ + + @@ -21,6 +23,8 @@ + + @@ -38,6 +42,8 @@ + + @@ -88,6 +94,8 @@ + + @@ -98,6 +106,8 @@ + + @@ -114,6 +124,8 @@ + + @@ -145,6 +157,8 @@ + + @@ -170,6 +184,8 @@ + + @@ -183,6 +199,8 @@ + + @@ -218,6 +236,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/polkit/polkit-sections.txt b/docs/polkit/polkit-sections.txt index 2094a3f..9f21599 100644 --- a/docs/polkit/polkit-sections.txt +++ b/docs/polkit/polkit-sections.txt @@ -54,6 +54,7 @@ PolkitAuthorizationResult polkit_authority_get polkit_authority_enumerate_actions_sync polkit_authority_check_authorization_sync +polkit_authority_obtain_authorization_sync polkit_authority_register_authentication_agent_sync polkit_authority_unregister_authentication_agent_sync polkit_authority_authentication_agent_response_sync @@ -61,6 +62,8 @@ polkit_authority_enumerate_actions polkit_authority_enumerate_actions_finish polkit_authority_check_authorization polkit_authority_check_authorization_finish +polkit_authority_obtain_authorization +polkit_authority_obtain_authorization_finish polkit_authority_register_authentication_agent polkit_authority_register_authentication_agent_finish polkit_authority_unregister_authentication_agent diff --git a/docs/polkitbackend/polkitbackend-sections.txt b/docs/polkitbackend/polkitbackend-sections.txt index 5af0b97..1c8f925 100644 --- a/docs/polkitbackend/polkitbackend-sections.txt +++ b/docs/polkitbackend/polkitbackend-sections.txt @@ -6,6 +6,8 @@ PolkitBackendAuthority PolkitBackendAuthorityClass polkit_backend_authority_check_authorization polkit_backend_authority_check_authorization_finish +polkit_backend_authority_obtain_authorization +polkit_backend_authority_obtain_authorization_finish polkit_backend_authority_register_authentication_agent polkit_backend_authority_unregister_authentication_agent polkit_backend_authority_authentication_agent_response diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am index 1c40863..524e67b 100644 --- a/src/examples/Makefile.am +++ b/src/examples/Makefile.am @@ -15,7 +15,7 @@ INCLUDES = \ -D_REENTRANT \ $(NULL) -noinst_PROGRAMS = cancel +noinst_PROGRAMS = cancel cancelobtain cancel_SOURCES = cancel.c @@ -28,5 +28,16 @@ cancel_LDADD = \ $(top_builddir)/src/polkit/libpolkit-gobject-1.la \ $(NULL) +cancelobtain_SOURCES = cancelobtain.c + +cancelobtain_CFLAGS = \ + $(GLIB_CFLAGS) \ + $(NULL) + +cancelobtain_LDADD = \ + $(GLIB_LDADD) \ + $(top_builddir)/src/polkit/libpolkit-gobject-1.la \ + $(NULL) + clean-local : rm -f *~ diff --git a/src/examples/cancelobtain.c b/src/examples/cancelobtain.c new file mode 100644 index 0000000..ea37d8f --- /dev/null +++ b/src/examples/cancelobtain.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +/* Simple example that shows how to obtain an authorization including + * cancelling the request. + */ + +#include + +static void +obtain_authorization_cb (PolkitAuthority *authority, + GAsyncResult *res, + GMainLoop *loop) +{ + GError *error; + + error = NULL; + if (!polkit_authority_obtain_authorization_finish (authority, res, &error)) + { + g_print ("Error obtaining authorization: %s\n", error->message); + g_error_free (error); + } + + g_main_loop_quit (loop); +} + +static gboolean +do_cancel (GCancellable *cancellable) +{ + g_print ("Timer has expired; cancelling request\n"); + g_cancellable_cancel (cancellable); + return FALSE; +} + +int +main (int argc, char *argv[]) +{ + int ret; + GMainLoop *loop; + PolkitSubject *calling_process; + PolkitAuthority *authority; + GCancellable *cancellable; + + g_type_init (); + + ret = 1; + + if (argc != 2) + { + g_printerr ("usage: cancelobtain \n"); + goto out; + } + + loop = g_main_loop_new (NULL, FALSE); + + authority = polkit_authority_get (); + + calling_process = polkit_unix_process_new (getppid ()); + + cancellable = g_cancellable_new (); + + g_print ("Will cancel request in 10 seconds\n"); + g_timeout_add (10 * 1000, + (GSourceFunc) do_cancel, + cancellable); + + polkit_authority_obtain_authorization (authority, + calling_process, + argv[1], + cancellable, + (GAsyncReadyCallback) obtain_authorization_cb, + loop); + + g_main_loop_run (loop); + + g_object_unref (authority); + g_object_unref (calling_process); + g_object_unref (cancellable); + g_main_loop_unref (loop); + + ret = 0; + + out: + + return ret; +} diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c index c4ab0da..cbd2cc8 100644 --- a/src/polkit/polkitauthority.c +++ b/src/polkit/polkitauthority.c @@ -325,6 +325,7 @@ polkit_authority_enumerate_actions_sync (PolkitAuthority *authority, } /* ---------------------------------------------------------------------------------------------------- */ + static guint polkit_authority_check_authorization_async (PolkitAuthority *authority, PolkitSubject *subject, @@ -490,7 +491,7 @@ polkit_authority_check_authorization_finish (PolkitAuthority *authority } /** - * polkit_authority_check_authorization: + * polkit_authority_check_authorization_sync: * @authority: A #PolkitAuthority. * @subject: A #PolkitSubject. * @action_id: The action to check for. @@ -535,6 +536,208 @@ polkit_authority_check_authorization_sync (PolkitAuthority *author /* ---------------------------------------------------------------------------------------------------- */ static guint +polkit_authority_obtain_authorization_async (PolkitAuthority *authority, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _PolkitSubject *real_subject; + guint call_id; + GSimpleAsyncResult *simple; + gchar *cancellation_id; + + real_subject = polkit_subject_get_real (subject); + + simple = g_simple_async_result_new (G_OBJECT (authority), + callback, + user_data, + polkit_authority_obtain_authorization_async); + + cancellation_id = NULL; + if (cancellable != NULL) + { + cancellation_id = g_strdup_printf ("cancellation-id-%d", authority->cancellation_id_counter++); + g_object_set_data_full (G_OBJECT (simple), "polkit-1-cancellation-id", cancellation_id, g_free); + } + + call_id = _polkit_authority_obtain_authorization (authority->real, + EGG_DBUS_CALL_FLAGS_TIMEOUT_NONE, + real_subject, + action_id, + cancellation_id, + cancellable, + generic_async_cb, + simple); + + g_object_unref (real_subject); + + return call_id; +} + +/** + * polkit_authority_obtain_authorization: + * @authority: A #PolkitAuthority. + * @subject: A #PolkitSubject. + * @action_id: The action to obtain an authorization for. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously obtains a temporary authorization for @subject to + * perform the action represented by @action_id. + * + * When the operation is finished, @callback will be invoked. You can + * then call polkit_authority_obtain_authorization_finish() to get the + * result of the operation. + **/ +void +polkit_authority_obtain_authorization (PolkitAuthority *authority, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + polkit_authority_obtain_authorization_async (authority, + subject, + action_id, + cancellable, + callback, + user_data); +} + +static void +authorization_obtain_cancelled_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error; + + error = NULL; + if (!_polkit_authority_cancel_obtain_authorization_finish (_POLKIT_AUTHORITY (source_object), + res, + &error)) + { + g_warning ("Error cancelling obtain authorization call: %s", error->message); + g_error_free (error); + } +} + +/** + * polkit_authority_obtain_authorization_finish: + * @authority: A #PolkitAuthority. + * @res: A #GAsyncResult obtained from the callback. + * @error: Return location for error or %NULL. + * + * Finishes obtaining an authorization. + * + * Returns: %TRUE if the authorization was obtained, %FALSE if @error is set. + **/ +gboolean +polkit_authority_obtain_authorization_finish (PolkitAuthority *authority, + GAsyncResult *res, + GError **error) +{ + gboolean result; + GSimpleAsyncResult *simple; + GAsyncResult *real_res; + GError *local_error; + + simple = G_SIMPLE_ASYNC_RESULT (res); + real_res = G_ASYNC_RESULT (g_simple_async_result_get_op_res_gpointer (simple)); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_authority_obtain_authorization_async); + + result = _POLKIT_AUTHORIZATION_RESULT_NOT_AUTHORIZED; + + local_error = NULL; + result = _polkit_authority_obtain_authorization_finish (authority->real, + real_res, + &local_error); + + if (local_error != NULL) + { + if (local_error->domain == EGG_DBUS_ERROR && local_error->code == EGG_DBUS_ERROR_CANCELLED) + { + const gchar *cancellation_id; + + /* if the operation was cancelled locally, make sure to tell the daemon so the authentication + * dialog etc. can be removed + */ + cancellation_id = g_object_get_data (G_OBJECT (simple), "polkit-1-cancellation-id"); + if (cancellation_id != NULL) + { + _polkit_authority_cancel_obtain_authorization (authority->real, + EGG_DBUS_CALL_FLAGS_NONE, + cancellation_id, + NULL, + authorization_obtain_cancelled_cb, + NULL); + } + + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_CANCELLED, + "The operation was cancelled"); + g_error_free (local_error); + } + else + { + g_propagate_error (error, local_error); + } + } + + g_object_unref (real_res); + return result; +} + +/** + * polkit_authority_obtain_authorization_sync: + * @authority: A #PolkitAuthority. + * @subject: A #PolkitSubject. + * @action_id: The action to obtain for. + * @flags: A set of #PolkitObtainAuthorizationFlags. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Obtains a temporary authorization for @subject to perform the + * action represented by @action_id. + * + * Returns: %TRUE if the authorization was obtained, %FALSE if @error is set. + */ +gboolean +polkit_authority_obtain_authorization_sync (PolkitAuthority *authority, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GError **error) +{ + guint call_id; + GAsyncResult *res; + gboolean result; + + call_id = polkit_authority_obtain_authorization_async (authority, + subject, + action_id, + cancellable, + generic_cb, + &res); + + egg_dbus_connection_pending_call_block (authority->system_bus, call_id); + + result = polkit_authority_obtain_authorization_finish (authority, res, error); + + g_object_unref (res); + + return result; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static guint polkit_authority_register_authentication_agent_async (PolkitAuthority *authority, const gchar *session_id, const gchar *object_path, diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h index 24d7a94..1337d48 100644 --- a/src/polkit/polkitauthority.h +++ b/src/polkit/polkitauthority.h @@ -65,6 +65,12 @@ PolkitAuthorizationResult polkit_authority_check_authorization_sync (PolkitAuth GCancellable *cancellable, GError **error); +gboolean polkit_authority_obtain_authorization_sync (PolkitAuthority *authority, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GError **error); + gboolean polkit_authority_register_authentication_agent_sync (PolkitAuthority *authority, const gchar *session_id, const gchar *object_path, @@ -106,6 +112,16 @@ PolkitAuthorizationResult polkit_authority_check_authorization_finish (PolkitAu GAsyncResult *res, GError **error); +void polkit_authority_obtain_authorization (PolkitAuthority *authority, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean polkit_authority_obtain_authorization_finish (PolkitAuthority *authority, + GAsyncResult *res, + GError **error); void polkit_authority_register_authentication_agent (PolkitAuthority *authority, const gchar *session_id, diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index bf40283..961fc49 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -195,6 +195,8 @@ polkit_backend_authority_enumerate_groups (PolkitBackendAuthority *authority, } } +/* ---------------------------------------------------------------------------------------------------- */ + /** * polkit_backend_authority_check_authorization: * @authority: A #PolkitBackendAuthority. @@ -279,6 +281,91 @@ polkit_backend_authority_check_authorization_finish (PolkitBackendAuthority *au } } +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * polkit_backend_authority_obtain_authorization: + * @authority: A #PolkitBackendAuthority. + * @caller: The system bus name that initiated the query. + * @subject: A #PolkitSubject. + * @action_id: The action to obtain. + * @cancellable: A #GCancellable. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously obtains a temporary authorization for @subject to + * perform the action represented by @action_id. If @subject is already + * authorized for @action_id, return %TRUE. If @action_id doesn't allow + * temporary authorizations, return a %POLKIT_ERROR_FAILED error. + * + * When the operation is finished, @callback will be invoked. You can then + * call polkit_backend_authority_obtain_authorization_finish() to get the result of + * the operation. + **/ +void +polkit_backend_authority_obtain_authorization (PolkitBackendAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PolkitBackendAuthorityClass *klass; + + klass = POLKIT_BACKEND_AUTHORITY_GET_CLASS (authority); + + if (klass->obtain_authorization == NULL) + { + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new_error (G_OBJECT (authority), + callback, + user_data, + POLKIT_ERROR, + POLKIT_ERROR_NOT_SUPPORTED, + "Operation not supported"); + g_simple_async_result_complete (simple); + g_object_unref (simple); + } + else + { + klass->obtain_authorization (authority, caller, subject, action_id, cancellable, callback, user_data); + } +} + +/** + * polkit_backend_authority_obtain_authorization_finish: + * @authority: A #PolkitBackendAuthority. + * @res: A #GAsyncResult obtained from the callback. + * @error: Return location for error or %NULL. + * + * Finishes obtaining an authorization. + * + * Returns: %TRUE if the authorization was obtained, %FALSE if @error is set. + **/ +gboolean +polkit_backend_authority_obtain_authorization_finish (PolkitBackendAuthority *authority, + GAsyncResult *res, + GError **error) +{ + PolkitBackendAuthorityClass *klass; + + klass = POLKIT_BACKEND_AUTHORITY_GET_CLASS (authority); + + if (klass->obtain_authorization_finish == NULL) + { + g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); + return FALSE; + } + else + { + return klass->obtain_authorization_finish (authority, res, error); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + /** * polkit_backend_authority_enumerate_authorizations: * @authority: A #PolkitBackendAuthority. @@ -904,6 +991,136 @@ authority_handle_cancel_check_authorization (_PolkitAuthority *ins /* ---------------------------------------------------------------------------------------------------- */ static void +obtain_auth_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + EggDBusMethodInvocation *method_invocation = EGG_DBUS_METHOD_INVOCATION (user_data); + const gchar *full_cancellation_id; + GError *error; + + error = NULL; + polkit_backend_authority_obtain_authorization_finish (POLKIT_BACKEND_AUTHORITY (source_object), + res, + &error); + + full_cancellation_id = g_object_get_data (G_OBJECT (method_invocation), "cancellation-id"); + if (full_cancellation_id != NULL) + { + Server *server; + server = SERVER (g_object_get_data (G_OBJECT (method_invocation), "server")); + g_hash_table_remove (server->cancellation_id_to_cancellable, full_cancellation_id); + } + + if (error != NULL) + { + egg_dbus_method_invocation_return_gerror (method_invocation, error); + g_error_free (error); + } + else + { + _polkit_authority_handle_obtain_authorization_finish (method_invocation); + } +} + +static void +authority_handle_obtain_authorization (_PolkitAuthority *instance, + _PolkitSubject *real_subject, + const gchar *action_id, + const gchar *cancellation_id, + EggDBusMethodInvocation *method_invocation) +{ + Server *server = SERVER (instance); + const gchar *caller_name; + PolkitSubject *subject; + PolkitSubject *caller; + GCancellable *cancellable; + + caller_name = egg_dbus_method_invocation_get_caller (method_invocation); + caller = polkit_system_bus_name_new (caller_name); + + subject = polkit_subject_new_for_real (real_subject); + + g_object_set_data_full (G_OBJECT (method_invocation), "caller", caller, (GDestroyNotify) g_object_unref); + g_object_set_data_full (G_OBJECT (method_invocation), "subject", subject, (GDestroyNotify) g_object_unref); + + cancellable = NULL; + if (cancellation_id != NULL && strlen (cancellation_id) > 0) + { + gchar *full_cancellation_id; + + full_cancellation_id = g_strdup_printf ("%s-%s", caller_name, cancellation_id); + + if (g_hash_table_lookup (server->cancellation_id_to_cancellable, full_cancellation_id) != NULL) + { + egg_dbus_method_invocation_return_error (method_invocation, + _POLKIT_ERROR, + _POLKIT_ERROR_CANCELLATION_ID_NOT_UNIQUE, + "Given cancellation_id %s is already in use for name %s", + cancellation_id, + caller_name); + g_free (full_cancellation_id); + goto out; + } + + cancellable = g_cancellable_new (); + + g_hash_table_insert (server->cancellation_id_to_cancellable, + full_cancellation_id, + cancellable); + + g_object_set_data (G_OBJECT (method_invocation), "server", server); + g_object_set_data (G_OBJECT (method_invocation), "cancellation-id", full_cancellation_id); + } + + polkit_backend_authority_obtain_authorization (server->authority, + caller, + subject, + action_id, + cancellable, + obtain_auth_cb, + method_invocation); + out: + ; +} + +static void +authority_handle_cancel_obtain_authorization (_PolkitAuthority *instance, + const gchar *cancellation_id, + EggDBusMethodInvocation *method_invocation) +{ + Server *server = SERVER (instance); + GCancellable *cancellable; + const gchar *caller_name; + gchar *full_cancellation_id; + + caller_name = egg_dbus_method_invocation_get_caller (method_invocation); + + full_cancellation_id = g_strdup_printf ("%s-%s", caller_name, cancellation_id); + + cancellable = g_hash_table_lookup (server->cancellation_id_to_cancellable, full_cancellation_id); + if (cancellable == NULL) + { + egg_dbus_method_invocation_return_error (method_invocation, + _POLKIT_ERROR, + _POLKIT_ERROR_FAILED, + "No such cancellation_id %s for name %s", + cancellation_id, + caller_name); + goto out; + } + + g_cancellable_cancel (cancellable); + + _polkit_authority_handle_cancel_obtain_authorization_finish (method_invocation); + + out: + g_free (full_cancellation_id); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void authority_manager_handle_enumerate_authorizations (_PolkitAuthorityManager *instance, _PolkitIdentity *real_identity, EggDBusMethodInvocation *method_invocation) @@ -1153,6 +1370,8 @@ authority_iface_init (_PolkitAuthorityIface *authority_iface) authority_iface->handle_enumerate_actions = authority_handle_enumerate_actions; authority_iface->handle_check_authorization = authority_handle_check_authorization; authority_iface->handle_cancel_check_authorization = authority_handle_cancel_check_authorization; + authority_iface->handle_obtain_authorization = authority_handle_obtain_authorization; + authority_iface->handle_cancel_obtain_authorization = authority_handle_cancel_obtain_authorization; authority_iface->handle_register_authentication_agent = authority_handle_register_authentication_agent; authority_iface->handle_unregister_authentication_agent = authority_handle_unregister_authentication_agent; authority_iface->handle_authentication_agent_response = authority_handle_authentication_agent_response; diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h index e08360b..ce63f5d 100644 --- a/src/polkitbackend/polkitbackendauthority.h +++ b/src/polkitbackend/polkitbackendauthority.h @@ -70,6 +70,13 @@ struct _PolkitBackendAuthority * @check_authorization_finish: Called when finishing an authorization * check. See polkit_backend_authority_check_authorization_finish() * for details. + * @obtain_authorization: Called to obtain an authorization or %NULL + * if the backend doesn't support the operation. See + * polkit_backend_authority_obtain_authorization() for details. + * @obtain_authorization_finish: Called when finishing obtaining + * an authorization or %NULL if the backend doesn't support the + * operation. See polkit_backend_authority_obtain_authorization_finish() + * for details. * @register_authentication_agent: Called when an authentication agent * is attempting to register or %NULL if the backend doesn't support * the operation. See @@ -132,6 +139,18 @@ struct _PolkitBackendAuthorityClass GAsyncResult *res, GError **error); + void (*obtain_authorization) (PolkitBackendAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + + gboolean (*obtain_authorization_finish) (PolkitBackendAuthority *authority, + GAsyncResult *res, + GError **error); + gboolean (*register_authentication_agent) (PolkitBackendAuthority *authority, PolkitSubject *caller, const gchar *session_id, @@ -228,6 +247,18 @@ PolkitAuthorizationResult polkit_backend_authority_check_authorization_finish (P GAsyncResult *res, GError **error); +void polkit_backend_authority_obtain_authorization (PolkitBackendAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean polkit_backend_authority_obtain_authorization_finish (PolkitBackendAuthority *authority, + GAsyncResult *res, + GError **error); + GList *polkit_backend_authority_enumerate_authorizations (PolkitBackendAuthority *authority, PolkitSubject *caller, PolkitIdentity *identity, diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c index c735c8c..be09d37 100644 --- a/src/polkitbackend/polkitbackendlocalauthority.c +++ b/src/polkitbackend/polkitbackendlocalauthority.c @@ -167,6 +167,18 @@ static PolkitAuthorizationResult polkit_backend_local_authority_check_authorizat GAsyncResult *res, GError **error); +static void polkit_backend_local_authority_obtain_authorization (PolkitBackendAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +static gboolean polkit_backend_local_authority_obtain_authorization_finish (PolkitBackendAuthority *authority, + GAsyncResult *res, + GError **error); + static PolkitAuthorizationResult check_authorization_sync (PolkitBackendAuthority *authority, PolkitSubject *subject, const gchar *action_id, @@ -297,6 +309,8 @@ polkit_backend_local_authority_class_init (PolkitBackendLocalAuthorityClass *kla authority_class->enumerate_groups = polkit_backend_local_authority_enumerate_groups; authority_class->check_authorization = polkit_backend_local_authority_check_authorization; authority_class->check_authorization_finish = polkit_backend_local_authority_check_authorization_finish; + authority_class->obtain_authorization = polkit_backend_local_authority_obtain_authorization; + authority_class->obtain_authorization_finish = polkit_backend_local_authority_obtain_authorization_finish; authority_class->enumerate_authorizations = polkit_backend_local_authority_enumerate_authorizations; authority_class->add_authorization = polkit_backend_local_authority_add_authorization; authority_class->remove_authorization = polkit_backend_local_authority_remove_authorization; @@ -426,6 +440,251 @@ polkit_backend_local_authority_enumerate_groups (PolkitBackendAuthority *autho /* ---------------------------------------------------------------------------------------------------- */ static void +obtain_authorization_challenge_cb (AuthenticationAgent *agent, + PolkitSubject *subject, + PolkitIdentity *user_of_subject, + PolkitBackendLocalAuthority *authority, + const gchar *action_id, + PolkitImplicitAuthorization implicit_authorization, + gboolean authentication_success, + gpointer user_data) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); + gchar *subject_str; + + subject_str = polkit_subject_to_string (subject); + + g_debug ("In obtain_authorization_challenge_cb\n" + " subject %s\n" + " action_id %s\n" + " authentication_success %d\n", + subject_str, + action_id, + authentication_success); + + if (authentication_success) + { + GError *error; + PolkitAuthorization *authorization; + + authorization = polkit_authorization_new (action_id, + subject, + FALSE); + + if (!add_authorization_for_identity (authority, + user_of_subject, + authorization, + &error)) + { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } + } + else + { + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Could not obtain authorization"); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); + + g_free (subject_str); +} + +static gboolean +polkit_backend_local_authority_obtain_authorization_finish (PolkitBackendAuthority *authority, + GAsyncResult *res, + GError **error) +{ + GSimpleAsyncResult *simple; + + simple = G_SIMPLE_ASYNC_RESULT (res); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_backend_local_authority_obtain_authorization); + + return g_simple_async_result_propagate_error (simple, error); +} + +static void +polkit_backend_local_authority_obtain_authorization (PolkitBackendAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PolkitBackendLocalAuthority *local_authority; + PolkitBackendLocalAuthorityPrivate *priv; + gchar *caller_str; + gchar *subject_str; + PolkitIdentity *user_of_caller; + PolkitIdentity *user_of_subject; + gchar *user_of_caller_str; + gchar *user_of_subject_str; + PolkitAuthorizationResult result; + PolkitImplicitAuthorization implicit_authorization; + GError *error; + GSimpleAsyncResult *simple; + + local_authority = POLKIT_BACKEND_LOCAL_AUTHORITY (authority); + priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (local_authority); + + error = NULL; + caller_str = NULL; + subject_str = NULL; + user_of_caller = NULL; + user_of_subject = NULL; + user_of_caller_str = NULL; + user_of_subject_str = NULL; + + simple = g_simple_async_result_new (G_OBJECT (authority), + callback, + user_data, + polkit_backend_local_authority_obtain_authorization); + + caller_str = polkit_subject_to_string (caller); + subject_str = polkit_subject_to_string (subject); + + g_debug ("%s is attempting to obtain an temporary authorization for %s to perform %s", + caller_str, + subject_str, + action_id); + + user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, + caller, + &error); + if (error != NULL) + { + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + goto out; + } + + user_of_caller_str = polkit_identity_to_string (user_of_caller); + g_debug (" user of caller is %s", user_of_caller_str); + + user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, + subject, + &error); + if (error != NULL) + { + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + goto out; + } + + user_of_subject_str = polkit_identity_to_string (user_of_subject); + g_debug (" user of subject is %s", user_of_subject_str); + + /* if the user of the caller and the user of the subject isn't the same, then fail */ + if (!polkit_identity_equal (user_of_caller, user_of_subject)) + { + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_NOT_AUTHORIZED, + "%s is not authorized to request an authorization for %s", + caller_str, + subject_str); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + + /* see if subject already has an authorization */ + result = check_authorization_sync (authority, + subject, + action_id, + POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, + &implicit_authorization, + &error); + if (error != NULL) + { + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + goto out; + } + + /* If the user can indeed obtain the authorization and the authorization can be retained, then do so */ + if (result == POLKIT_AUTHORIZATION_RESULT_CHALLENGE && + (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED || + implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)) + { + AuthenticationAgent *agent; + + agent = get_authentication_agent_for_subject (local_authority, subject); + if (agent == NULL) + { + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Authorization can be obtained, but no suitable authentication agent is available"); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + else + { + g_debug (" using authentication agent for challenge to obtain an authorization"); + + authentication_agent_initiate_challenge (agent, + subject, + user_of_subject, + local_authority, + action_id, + caller, + implicit_authorization, + cancellable, + obtain_authorization_challenge_cb, + simple); + + /* keep going */ + goto out; + } + } + + /* if the subject is already authorized, return without an error */ + if (result == POLKIT_AUTHORIZATION_RESULT_AUTHORIZED) + { + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + + /* otherwise return an error */ + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Desired authorization cannot be obtained. This incident has been logged."); + g_simple_async_result_complete (simple); + g_object_unref (simple); + + out: + + if (user_of_caller != NULL) + g_object_unref (user_of_caller); + + if (user_of_subject != NULL) + g_object_unref (user_of_subject); + + g_free (caller_str); + g_free (subject_str); + g_free (user_of_caller_str); + g_free (user_of_subject_str); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void check_authorization_challenge_cb (AuthenticationAgent *agent, PolkitSubject *subject, PolkitIdentity *user_of_subject, diff --git a/src/programs/polkit.c b/src/programs/polkit.c index ea2cacd..1bc2579 100644 --- a/src/programs/polkit.c +++ b/src/programs/polkit.c @@ -632,35 +632,24 @@ list_groups (void) static gint do_run (gint argc, gchar *argv[]) { - PolkitAuthorizationResult result; PolkitSubject *calling_process; GError *error; - gboolean ret; - ret = FALSE; - error = NULL; calling_process = polkit_unix_process_new (getpid ()); - result = polkit_authority_check_authorization_sync (authority, - calling_process, - action_id, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - NULL, - &error); - if (error != NULL) + error = NULL; + if (!polkit_authority_obtain_authorization_sync (authority, + calling_process, + action_id, + NULL, + &error)) { - g_printerr ("Error checking authorization for action %s: %s\n", action_id, error->message); + g_printerr ("Error obtaining authorization for action %s: %s\n", action_id, error->message); g_error_free (error); goto out; } - if (result != POLKIT_AUTHORIZATION_RESULT_AUTHORIZED) - { - g_printerr ("Error obtaining authorization for action %s (%d)\n", action_id, result); - goto out; - } - execvp (argv[0], argv); g_printerr ("Error launching program: %m\n"); @@ -669,7 +658,7 @@ do_run (gint argc, gchar *argv[]) g_object_unref (calling_process); - return ret; + return FALSE; } /* ---------------------------------------------------------------------------------------------------- */