From de0985aaeb9a44090f3cb37e4ea6308c0152797a Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Sun, 26 Jul 2009 22:05:38 -0400 Subject: [PATCH] Allow unprivileged callers to check authorizations But only allow this if - the caller and the subject being checked is the same user - no details are passed (otherwise dialogs can be spoofed) Also add a RevokeTemporaryAuthorizationById() method. --- data/org.freedesktop.PolicyKit1.Authority.xml | 12 +- docs/polkit/polkit-1-sections.txt | 4 +- src/polkit/polkitauthority.c | 197 ++++++++++++++++- src/polkit/polkitauthority.h | 15 ++ src/polkit/polkitauthorizationresult.c | 6 + src/polkitbackend/polkitbackendauthority.c | 86 +++++++- src/polkitbackend/polkitbackendauthority.h | 14 ++ .../polkitbackendinteractiveauthority.c | 235 +++++++++++++++------ src/polkitbackend/polkitbackendlocalauthority.c | 14 ++ 9 files changed, 505 insertions(+), 78 deletions(-) diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml index 6b29e8e..9b49334 100644 --- a/data/org.freedesktop.PolicyKit1.Authority.xml +++ b/data/org.freedesktop.PolicyKit1.Authority.xml @@ -129,7 +129,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -348,6 +348,14 @@ + + + + + + + + diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt index f096d2d..c06a55a 100644 --- a/docs/polkit/polkit-1-sections.txt +++ b/docs/polkit/polkit-1-sections.txt @@ -35,6 +35,8 @@ polkit_authority_enumerate_temporary_authorizations polkit_authority_enumerate_temporary_authorizations_finish polkit_authority_revoke_temporary_authorizations polkit_authority_revoke_temporary_authorizations_finish +polkit_authority_revoke_temporary_authorization_by_id +polkit_authority_revoke_temporary_authorization_by_id_finish polkit_authority_check_authorization_sync polkit_authority_enumerate_actions_sync polkit_authority_register_authentication_agent_sync @@ -42,6 +44,7 @@ polkit_authority_unregister_authentication_agent_sync polkit_authority_authentication_agent_response_sync polkit_authority_enumerate_temporary_authorizations_sync polkit_authority_revoke_temporary_authorizations_sync +polkit_authority_revoke_temporary_authorization_by_id_sync PolkitAuthorityClass POLKIT_AUTHORITY @@ -439,7 +442,6 @@ POLKIT_AGENT_LISTENER_GET_CLASS polkittemporaryauthorization PolkitTemporaryAuthorization PolkitTemporaryAuthorization -PolkitTemporaryAuthorizationClass polkit_temporary_authorization_get_id polkit_temporary_authorization_get_action_id polkit_temporary_authorization_get_subject diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c index 4d34b16..7d2c235 100644 --- a/src/polkit/polkitauthority.c +++ b/src/polkit/polkitauthority.c @@ -396,7 +396,8 @@ polkit_authority_check_authorization_async (PolkitAuthority *autho * @authority: A #PolkitAuthority. * @subject: A #PolkitSubject. * @action_id: The action to check for. - * @details: Details about the action or %NULL. + * @details: Details about the action or %NULL. Keys starting with polkit. are reserved + * for internal use and cannot be used. * @flags: A set of #PolkitCheckAuthorizationFlags. * @cancellable: A #GCancellable or %NULL. * @callback: A #GAsyncReadyCallback to call when the request is satisfied. @@ -528,7 +529,8 @@ polkit_authority_check_authorization_finish (PolkitAuthority *authority * @authority: A #PolkitAuthority. * @subject: A #PolkitSubject. * @action_id: The action to check for. - * @details: Details about the action or %NULL. + * @details: Details about the action or %NULL. Keys starting with polkit. are reserved + * for internal use and cannot be used. * @flags: A set of #PolkitCheckAuthorizationFlags. * @cancellable: A #GCancellable or %NULL. * @error: Return location for error or %NULL. @@ -1035,6 +1037,20 @@ polkit_authority_enumerate_temporary_authorizations_async (PolkitAuthority * return call_id; } +/** + * polkit_authority_enumerate_temporary_authorizations: + * @authority: A #PolkitAuthority. + * @subject: A #PolkitSubject, typically a #PolkitUnixSession. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously gets all temporary authorizations for @subject. + * + * When the operation is finished, @callback will be invoked. You can then + * call polkit_authority_enumerate_temporary_authorizations_finish() to get the result of + * the operation. + **/ void polkit_authority_enumerate_temporary_authorizations (PolkitAuthority *authority, PolkitSubject *subject, @@ -1045,6 +1061,17 @@ polkit_authority_enumerate_temporary_authorizations (PolkitAuthority *author polkit_authority_enumerate_temporary_authorizations_async (authority, subject, cancellable, callback, user_data); } +/** + * polkit_authority_enumerate_temporary_authorizations_finish: + * @authority: A #PolkitAuthority. + * @res: A #GAsyncResult obtained from the callback. + * @error: Return location for error or %NULL. + * + * Finishes retrieving all registered actions. + * + * Returns: A list of #PolkitTemporaryAuthorization objects or %NULL if @error is set. The returned list + * should be freed with g_list_free() after each element have been freed with g_object_unref(). + **/ GList * polkit_authority_enumerate_temporary_authorizations_finish (PolkitAuthority *authority, GAsyncResult *res, @@ -1087,6 +1114,18 @@ polkit_authority_enumerate_temporary_authorizations_finish (PolkitAuthority *aut return result; } +/** + * polkit_authority_enumerate_temporary_authorizations_sync: + * @authority: A #PolkitAuthority. + * @subject: A #PolkitSubject, typically a #PolkitUnixSession. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronousky gets all temporary authorizations for @subject. + * + * Returns: A list of #PolkitTemporaryAuthorization objects or %NULL if @error is set. The returned list + * should be freed with g_list_free() after each element have been freed with g_object_unref(). + **/ GList * polkit_authority_enumerate_temporary_authorizations_sync (PolkitAuthority *authority, PolkitSubject *subject, @@ -1140,6 +1179,20 @@ polkit_authority_revoke_temporary_authorizations_async (PolkitAuthority *aut return call_id; } +/** + * polkit_authority_revoke_temporary_authorizations: + * @authority: A #PolkitAuthority. + * @subject: The subject to revoke authorizations from, typically a #PolkitUnixSession. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously revokes all temporary authorizations for @subject. + * + * When the operation is finished, @callback will be invoked. You can then + * call polkit_authority_revoke_temporary_authorizations_finish() to get the result of + * the operation. + **/ void polkit_authority_revoke_temporary_authorizations (PolkitAuthority *authority, PolkitSubject *subject, @@ -1150,6 +1203,16 @@ polkit_authority_revoke_temporary_authorizations (PolkitAuthority *authority polkit_authority_revoke_temporary_authorizations_async (authority, subject, cancellable, callback, user_data); } +/** + * polkit_authority_revoke_temporary_authorizations_finish: + * @authority: A #PolkitAuthority. + * @res: A #GAsyncResult obtained from the callback. + * @error: Return location for error or %NULL. + * + * Finished revoking temporary authorizations. + * + * Returns: %TRUE if all the temporary authorizations was revoked, %FALSE if error is set. + **/ gboolean polkit_authority_revoke_temporary_authorizations_finish (PolkitAuthority *authority, GAsyncResult *res, @@ -1176,6 +1239,17 @@ polkit_authority_revoke_temporary_authorizations_finish (PolkitAuthority *author return ret; } +/** + * polkit_authority_revoke_temporary_authorizations_sync: + * @authority: A #PolkitAuthority. + * @subject: The subject to revoke authorizations from, typically a #PolkitUnixSession. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronously revokes all temporary authorization from @subject. + * + * Returns: %TRUE if the temporary authorization was revoked, %FALSE if error is set. + **/ gboolean polkit_authority_revoke_temporary_authorizations_sync (PolkitAuthority *authority, PolkitSubject *subject, @@ -1198,3 +1272,122 @@ polkit_authority_revoke_temporary_authorizations_sync (PolkitAuthority *auth } /* ---------------------------------------------------------------------------------------------------- */ + +static guint +polkit_authority_revoke_temporary_authorization_by_id_async (PolkitAuthority *authority, + const gchar *id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + guint call_id; + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new (G_OBJECT (authority), + callback, + user_data, + polkit_authority_revoke_temporary_authorizations_async); + + call_id = _polkit_authority_revoke_temporary_authorization_by_id (authority->real, + EGG_DBUS_CALL_FLAGS_NONE, + id, + cancellable, + generic_async_cb, + simple); + + return call_id; +} + +/** + * polkit_authority_revoke_temporary_authorization_by_id: + * @authority: A #PolkitAuthority. + * @id: The opaque identifier for the temporary authorization. + * @cancellable: A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously revoke a temporary authorization. + * + * When the operation is finished, @callback will be invoked. You can then + * call polkit_authority_revoke_temporary_authorization_by_id_finish() to get the result of + * the operation. + */ +void +polkit_authority_revoke_temporary_authorization_by_id (PolkitAuthority *authority, + const gchar *id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + polkit_authority_revoke_temporary_authorization_by_id_async (authority, id, cancellable, callback, user_data); +} + +/** + * polkit_authority_revoke_temporary_authorization_by_id_finish: + * @authority: A #PolkitAuthority. + * @res: A #GAsyncResult obtained from the callback. + * @error: Return location for error or %NULL. + * + * Finished revoking a temporary authorization by id. + * + * Returns: %TRUE if the temporary authorization was revoked, %FALSE if error is set. + **/ +gboolean +polkit_authority_revoke_temporary_authorization_by_id_finish (PolkitAuthority *authority, + GAsyncResult *res, + GError **error) +{ + GSimpleAsyncResult *simple; + GAsyncResult *real_res; + gboolean ret; + + 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_revoke_temporary_authorizations_async); + + ret = _polkit_authority_revoke_temporary_authorization_by_id_finish (authority->real, + real_res, + error); + + if (!ret) + goto out; + + out: + g_object_unref (real_res); + return ret; +} + +/** + * polkit_authority_revoke_temporary_authorization_by_id_sync: + * @authority: A #PolkitAuthority. + * @id: The opaque identifier for the temporary authorization. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronously revokes a temporary authorization. + * + * Returns: %TRUE if the temporary authorization was revoked, %FALSE if error is set. + **/ +gboolean +polkit_authority_revoke_temporary_authorization_by_id_sync (PolkitAuthority *authority, + const gchar *id, + GCancellable *cancellable, + GError **error) +{ + guint call_id; + GAsyncResult *res; + gboolean result; + + call_id = polkit_authority_revoke_temporary_authorization_by_id_async (authority, id, cancellable, generic_cb, &res); + + egg_dbus_connection_pending_call_block (authority->system_bus, call_id); + + result = polkit_authority_revoke_temporary_authorization_by_id_finish (authority, res, error); + + g_object_unref (res); + + return result; +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h index 61a6e7c..e45b3a1 100644 --- a/src/polkit/polkitauthority.h +++ b/src/polkit/polkitauthority.h @@ -99,6 +99,11 @@ gboolean polkit_authority_revoke_temporary_authorizations_sync GCancellable *cancellable, GError **error); +gboolean polkit_authority_revoke_temporary_authorization_by_id_sync (PolkitAuthority *authority, + const gchar *id, + GCancellable *cancellable, + GError **error); + /* ---------------------------------------------------------------------------------------------------- */ void polkit_authority_enumerate_actions (PolkitAuthority *authority, @@ -177,6 +182,16 @@ gboolean polkit_authority_revoke_temporary_authorizations_fini GAsyncResult *res, GError **error); +void polkit_authority_revoke_temporary_authorization_by_id (PolkitAuthority *authority, + const gchar *id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean polkit_authority_revoke_temporary_authorization_by_id_finish (PolkitAuthority *authority, + GAsyncResult *res, + GError **error); + /* ---------------------------------------------------------------------------------------------------- */ G_END_DECLS diff --git a/src/polkit/polkitauthorizationresult.c b/src/polkit/polkitauthorizationresult.c index 6786a5a..08911ef 100644 --- a/src/polkit/polkitauthorizationresult.c +++ b/src/polkit/polkitauthorizationresult.c @@ -187,6 +187,12 @@ polkit_authorization_result_get_is_challenge (PolkitAuthorizationResult *result) * * Gets the details about the result. * + * If the authorization is temporary the opaque identifier for the + * temporary authorization + * (cf. polkit_temporary_authorization_get_id()) is set available as + * the value for the + * polkit.temporary_authorization_id key. + * * Returns: A #PolkitDetails object. This object is owned by @result * and should not be freed by the caller. */ diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index eec0664..63caf0f 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -381,7 +381,7 @@ polkit_backend_authority_enumerate_temporary_authorizations (PolkitBackendAuthor * * Revokes temporary authorizations for @subject. * - * Returns: %TRUE if the operatoin succeeded, %FALSE if @error is set. + * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. **/ gboolean polkit_backend_authority_revoke_temporary_authorizations (PolkitBackendAuthority *authority, @@ -407,6 +407,41 @@ polkit_backend_authority_revoke_temporary_authorizations (PolkitBackendAuthority } } +/** + * polkit_backend_authority_revoke_temporary_authorization_by_id: + * @authority: A #PolkitBackendAuthority. + * @caller: The system bus name that initiated the query. + * @id: The opaque identifier of the temporary authorization. + * @error: Return location for error. + * + * Revokes a temporary authorizations with opaque identifier @id. + * + * Returns: %TRUE if the operatoin succeeded, %FALSE if @error is set. + **/ +gboolean +polkit_backend_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority, + PolkitSubject *caller, + const gchar *id, + GError **error) +{ + PolkitBackendAuthorityClass *klass; + + klass = POLKIT_BACKEND_AUTHORITY_GET_CLASS (authority); + + if (klass->revoke_temporary_authorization_by_id == NULL) + { + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_NOT_SUPPORTED, + "Operation not supported"); + return FALSE; + } + else + { + return klass->revoke_temporary_authorization_by_id (authority, caller, id, error); + } +} + /* ---------------------------------------------------------------------------------------------------- */ @@ -917,16 +952,49 @@ authority_handle_revoke_temporary_authorizations (_PolkitAuthority *insta /* ---------------------------------------------------------------------------------------------------- */ static void +authority_handle_revoke_temporary_authorization_by_id (_PolkitAuthority *instance, + const gchar *id, + EggDBusMethodInvocation *method_invocation) +{ + Server *server = SERVER (instance); + GError *error; + PolkitSubject *caller; + + error = NULL; + + caller = polkit_system_bus_name_new (egg_dbus_method_invocation_get_caller (method_invocation)); + + polkit_backend_authority_revoke_temporary_authorization_by_id (server->authority, + caller, + id, + &error); + if (error != NULL) + { + egg_dbus_method_invocation_return_gerror (method_invocation, error); + g_error_free (error); + goto out; + } + + _polkit_authority_handle_revoke_temporary_authorization_by_id_finish (method_invocation); + + out: + g_object_unref (caller); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void 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_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; - authority_iface->handle_enumerate_temporary_authorizations = authority_handle_enumerate_temporary_authorizations; - authority_iface->handle_revoke_temporary_authorizations = authority_handle_revoke_temporary_authorizations; + 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_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; + authority_iface->handle_enumerate_temporary_authorizations = authority_handle_enumerate_temporary_authorizations; + authority_iface->handle_revoke_temporary_authorizations = authority_handle_revoke_temporary_authorizations; + authority_iface->handle_revoke_temporary_authorization_by_id = authority_handle_revoke_temporary_authorization_by_id; } static void diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h index ca784ef..56d46be 100644 --- a/src/polkitbackend/polkitbackendauthority.h +++ b/src/polkitbackend/polkitbackendauthority.h @@ -94,6 +94,10 @@ struct _PolkitBackendAuthority * authorizations or %NULL if the backend doesn't support the operation. * See polkit_backend_authority_revoke_temporary_authorizations() * for details. + * @revoke_temporary_authorization_by_id: Called to revoke a temporary + * authorization identified by id or %NULL if the backend doesn't support + * the operation. See polkit_backend_authority_revoke_temporary_authorization_by_id() + * for details. * @system_bus_name_owner_changed: temporary VFunc, to be removed before 1.0. * * VFuncs that authority backends need to implement. @@ -156,6 +160,11 @@ struct _PolkitBackendAuthorityClass PolkitSubject *subject, GError **error); + gboolean (*revoke_temporary_authorization_by_id) (PolkitBackendAuthority *authority, + PolkitSubject *caller, + const gchar *id, + GError **error); + /* TODO: need something more efficient such that we don't watch all name changes */ void (*system_bus_name_owner_changed) (PolkitBackendAuthority *authority, const gchar *name, @@ -255,6 +264,11 @@ gboolean polkit_backend_authority_revoke_temporary_authorizations (PolkitBackend PolkitSubject *subject, GError **error); +gboolean polkit_backend_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority, + PolkitSubject *caller, + const gchar *id, + GError **error); + /* --- */ PolkitBackendAuthority *polkit_backend_authority_get (void); diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c index 1677404..af58ed3 100644 --- a/src/polkitbackend/polkitbackendinteractiveauthority.c +++ b/src/polkitbackend/polkitbackendinteractiveauthority.c @@ -55,12 +55,13 @@ static void temporary_authorization_store_free (Temporar static gboolean temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store, PolkitSubject *subject, - const gchar *action_id); + const gchar *action_id, + const gchar **out_tmp_authz_id); -static void temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store, - PolkitSubject *subject, - PolkitSubject *session, - const gchar *action_id); +static const gchar *temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store, + PolkitSubject *subject, + PolkitSubject *session, + const gchar *action_id); /* ---------------------------------------------------------------------------------------------------- */ @@ -173,6 +174,11 @@ static gboolean polkit_backend_interactive_authority_revoke_temporary_authorizat PolkitSubject *subject, GError **error); +static gboolean polkit_backend_interactive_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority, + PolkitSubject *caller, + const gchar *id, + GError **error); + /* ---------------------------------------------------------------------------------------------------- */ @@ -275,6 +281,7 @@ polkit_backend_interactive_authority_class_init (PolkitBackendInteractiveAuthori authority_class->authentication_agent_response = polkit_backend_interactive_authority_authentication_agent_response; authority_class->enumerate_temporary_authorizations = polkit_backend_interactive_authority_enumerate_temporary_authorizations; authority_class->revoke_temporary_authorizations = polkit_backend_interactive_authority_revoke_temporary_authorizations; + authority_class->revoke_temporary_authorization_by_id = polkit_backend_interactive_authority_revoke_temporary_authorization_by_id; @@ -333,19 +340,29 @@ check_authorization_challenge_cb (AuthenticationAgent *agent, if (authentication_success) { - result = polkit_authorization_result_new (TRUE, FALSE, NULL); + PolkitDetails *details; + + details = polkit_details_new (); /* store temporary authorization depending on value of implicit_authorization */ if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED || implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED) { - temporary_authorization_store_add_authorization (priv->temporary_authorization_store, - subject, - authentication_agent_get_session (agent), - action_id); + const gchar *id; + + id = temporary_authorization_store_add_authorization (priv->temporary_authorization_store, + subject, + authentication_agent_get_session (agent), + action_id); + + polkit_details_insert (details, "polkit.temporary_authorization_id", id); + /* we've added a temporary authorization, let the user know */ g_signal_emit_by_name (authority, "changed"); } + + result = polkit_authorization_result_new (TRUE, FALSE, details); + g_object_unref (details); } else { @@ -387,14 +404,14 @@ polkit_backend_interactive_authority_check_authorization_finish (PolkitBackendAu static void polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority, - PolkitSubject *caller, - PolkitSubject *subject, - const gchar *action_id, - PolkitDetails *details, - PolkitCheckAuthorizationFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) + PolkitSubject *caller, + PolkitSubject *subject, + const gchar *action_id, + PolkitDetails *details, + PolkitCheckAuthorizationFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { PolkitBackendInteractiveAuthority *interactive_authority; PolkitBackendInteractiveAuthorityPrivate *priv; @@ -408,6 +425,8 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority PolkitImplicitAuthorization implicit_authorization; GError *error; GSimpleAsyncResult *simple; + gboolean has_details; + gchar **detail_keys; interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority); priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority); @@ -449,20 +468,6 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority user_of_caller_str = polkit_identity_to_string (user_of_caller); g_debug (" user of caller is %s", user_of_caller_str); - /* we only allow trusted callers (uid 0 + others) to check authorizations */ - if (!POLKIT_IS_UNIX_USER (user_of_caller) || - polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0) /* TODO: allow other uids like 'haldaemon'? */ - { - g_simple_async_result_set_error (simple, - POLKIT_ERROR, - POLKIT_ERROR_NOT_AUTHORIZED, - "Only trusted callers can use CheckAuthorization(), %s is not trusted", - user_of_caller_str); - g_simple_async_result_complete (simple); - g_object_unref (simple); - goto out; - } - user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &error); @@ -478,6 +483,38 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority user_of_subject_str = polkit_identity_to_string (user_of_subject); g_debug (" user of subject is %s", user_of_subject_str); + has_details = FALSE; + if (details != NULL) + { + detail_keys = polkit_details_get_keys (details); + if (detail_keys != NULL) + { + if (g_strv_length (detail_keys) > 0) + has_details = TRUE; + g_strfreev (detail_keys); + } + } + if (!polkit_identity_equal (user_of_caller, user_of_subject) || has_details) + { + /* we only allow trusted callers (uid 0 + others) to check authorizations for subjects + * they don't own - and only if there are no details passed (to avoid spoofing dialogs). + * + * TODO: allow other uids like 'haldaemon'? + */ + if (!POLKIT_IS_UNIX_USER (user_of_caller) || + polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0) + { + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_NOT_AUTHORIZED, + "Only trusted callers can use CheckAuthorization() for subjects " + "belonging to other identities and/or pass details"); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + } + implicit_authorization = POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED; result = check_authorization_sync (authority, caller, @@ -571,6 +608,7 @@ check_authorization_sync (PolkitBackendAuthority *authority, gboolean session_is_local; gboolean session_is_active; PolkitImplicitAuthorization implicit_authorization; + const gchar *tmp_authz_id; interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority); priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority); @@ -673,37 +711,19 @@ check_authorization_sync (PolkitBackendAuthority *authority, /* then see if there's a temporary authorization for the subject */ if (temporary_authorization_store_has_authorization (priv->temporary_authorization_store, subject, - action_id)) + action_id, + &tmp_authz_id)) { - g_debug (" is authorized (has temporary authorization)"); - result = polkit_authorization_result_new (TRUE, FALSE, NULL); - goto out; - } + PolkitDetails *details; -#if 0 - /* then see if we have an authorization for the user */ - if (check_authorization_for_identity (interactive_authority, user_of_subject, action_id)) - { - g_debug (" is authorized (user identity has authorization)"); - result = polkit_authorization_result_new (TRUE, FALSE, NULL); + g_debug (" is authorized (has temporary authorization)"); + details = polkit_details_new (); + polkit_details_insert (details, "polkit.temporary_authorization_id", tmp_authz_id); + result = polkit_authorization_result_new (TRUE, FALSE, details); + g_object_unref (details); goto out; } - /* then see if we have a permanent authorization for any of the groups the user is in */ - groups_of_user = get_groups_for_user (interactive_authority, user_of_subject); - for (l = groups_of_user; l != NULL; l = l->next) - { - PolkitIdentity *group = POLKIT_IDENTITY (l->data); - - if (check_authorization_for_identity (interactive_authority, group, action_id)) - { - g_debug (" is authorized (group identity has authorization)"); - result = polkit_authorization_result_new (TRUE, FALSE, NULL); - goto out; - } - } -#endif - if (implicit_authorization != POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED) { result = polkit_authorization_result_new (FALSE, TRUE, NULL); @@ -1900,7 +1920,8 @@ temporary_authorization_store_free (TemporaryAuthorizationStore *store) static gboolean temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store, PolkitSubject *subject, - const gchar *action_id) + const gchar *action_id, + const gchar **out_tmp_authz_id) { GList *l; gboolean ret; @@ -1918,6 +1939,8 @@ temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *st polkit_subject_equal (subject, authorization->subject)) { ret = TRUE; + if (out_tmp_authz_id != NULL) + *out_tmp_authz_id = authorization->id; goto out; } } @@ -1941,7 +1964,7 @@ on_expiration_timeout (gpointer user_data) return FALSE; } -static void +static const gchar * temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store, PolkitSubject *subject, PolkitSubject *session, @@ -1950,10 +1973,10 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st TemporaryAuthorization *authorization; guint expiration_seconds; - g_return_if_fail (store != NULL); - g_return_if_fail (POLKIT_IS_SUBJECT (subject)); - g_return_if_fail (action_id != NULL); - g_return_if_fail (!temporary_authorization_store_has_authorization (store, subject, action_id)); + g_return_val_if_fail (store != NULL, NULL); + g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), NULL); + g_return_val_if_fail (action_id != NULL, NULL); + g_return_val_if_fail (!temporary_authorization_store_has_authorization (store, subject, action_id, NULL), NULL); /* TODO: right now this is hard-coded - we could make it a propery on the * PolkitBackendInteractiveAuthority class. Or we could even read @@ -1974,6 +1997,8 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st authorization); store->authorizations = g_list_prepend (store->authorizations, authorization); + + return authorization->id; } /* ---------------------------------------------------------------------------------------------------- */ @@ -2131,3 +2156,85 @@ polkit_backend_interactive_authority_revoke_temporary_authorizations (PolkitBack } /* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +polkit_backend_interactive_authority_revoke_temporary_authorization_by_id (PolkitBackendAuthority *authority, + PolkitSubject *caller, + const gchar *id, + GError **error) +{ + PolkitBackendInteractiveAuthority *interactive_authority; + PolkitBackendInteractiveAuthorityPrivate *priv; + PolkitSubject *session_for_caller; + gboolean ret; + GList *l; + GList *ll; + guint num_removed; + + interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority); + priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority); + + ret = FALSE; + session_for_caller = NULL; + + session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor, + caller, + NULL); + if (session_for_caller == NULL) + { + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Cannot determine session the caller is in"); + goto out; + } + + num_removed = 0; + for (l = priv->temporary_authorization_store->authorizations; l != NULL; l = ll) + { + TemporaryAuthorization *ta = l->data; + + ll = l->next; + + if (strcmp (ta->id, id) != 0) + continue; + + if (!polkit_subject_equal (session_for_caller, ta->session)) + { + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Cannot remove a temporary authorization belonging to another subject."); + goto out; + } + + priv->temporary_authorization_store->authorizations = g_list_remove (priv->temporary_authorization_store->authorizations, ta); + temporary_authorization_free (ta); + + num_removed++; + } + + if (num_removed > 0) + { + g_signal_emit_by_name (authority, "changed"); + } + else + { + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "No such authorization with id `%s'", + id); + goto out; + } + + ret = TRUE; + + out: + if (session_for_caller != NULL) + g_object_unref (session_for_caller); + + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c index 06073cf..e100c56 100644 --- a/src/polkitbackend/polkitbackendlocalauthority.c +++ b/src/polkitbackend/polkitbackendlocalauthority.c @@ -95,6 +95,15 @@ G_DEFINE_TYPE_WITH_CODE (PolkitBackendLocalAuthority, /* ---------------------------------------------------------------------------------------------------- */ static void +on_store_changed (PolkitBackendLocalAuthorizationStore *store, + gpointer user_data) +{ + PolkitBackendLocalAuthority *authority = POLKIT_BACKEND_LOCAL_AUTHORITY (user_data); + + g_signal_emit_by_name (authority, "changed"); +} + +static void polkit_backend_local_authority_init (PolkitBackendLocalAuthority *authority) { PolkitBackendLocalAuthorityPrivate *priv; @@ -124,6 +133,11 @@ polkit_backend_local_authority_init (PolkitBackendLocalAuthority *authority) store = polkit_backend_local_authorization_store_new (directory, ".pkla"); priv->authorization_stores = g_list_prepend (priv->authorization_stores, store); g_object_unref (directory); + + g_signal_connect (store, + "changed", + G_CALLBACK (on_store_changed), + authority); } priv->authorization_stores = g_list_reverse (priv->authorization_stores); } -- 2.7.4