Commit 986d7c29 authored by David Zeuthen's avatar David Zeuthen
Browse files

Bug 30653 – No way to detect cancellation in pkexec

https://bugs.freedesktop.org/show_bug.cgi?id=30653

Signed-off-by: default avatarDavid Zeuthen <davidz@redhat.com>
parent 8d96c2ec
......@@ -61,7 +61,10 @@
of <replaceable>PROGRAM</replaceable>. If the calling process is
not authorized or an authorization could not be obtained through
authentication or an error occured, <command>pkexec</command>
exits with a return value of 127.
exits with a return value of 127. If the authorization could not
be obtained because the user dismissed the authentication
dialog, <command>pkexec</command> exits with a return value of
126.
</para>
</refsect1>
......
......@@ -40,8 +40,24 @@ BeginAuthentication (IN String action_id,
IN Array&lt;<link linkend="eggdbus-struct-Identity">Identity</link>&gt; identities)
</programlisting>
<para>
<para>Called by the PolicyKit daemon when the authentication agent needs the user to authenticate as one of the identities in <parameter>identities</parameter> for the action with the identifier <parameter>action_id</parameter>.</para><para>Upon succesful authentication, the authentication agent must invoke the <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link> method on the <link linkend="eggdbus-interface-org.freedesktop.PolicyKit1.Authority">org.freedesktop.PolicyKit1.Authority</link> interface of the PolicyKit daemon before returning.</para><para>If the user dismisses the authentication dialog, the authentication agent should return an error.</para>
<para>
Called by the PolicyKit daemon when the authentication agent
needs the user to authenticate as one of the identities in
<parameter>identities</parameter> for the action with the
identifier <parameter>action_id</parameter>.</para><para>Upon
succesful authentication, the authentication agent must invoke
the <link
linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link>
method on the <link
linkend="eggdbus-interface-org.freedesktop.PolicyKit1.Authority">org.freedesktop.PolicyKit1.Authority</link>
interface of the PolicyKit daemon before returning.
</para>
<para>
The authentication agent should not return until after authentication is complete.
If the user dismisses the authentication dialog, the authentication agent should return the <link linkend="eggdbus-constant-Error.org.freedesktop.PolicyKit1.Error.Cancelled">org.freedesktop.PolicyKit1.Error.Cancelled</link> error.
</para>
</para>
<variablelist role="params">
<varlistentry>
<term><literal>IN String <parameter>action_id</parameter></literal>:</term>
......@@ -71,7 +87,7 @@ The themed icon describing the action or the empty string if no icon is set.
<term><literal>IN Dict&lt;String,String&gt; <parameter>details</parameter></literal>:</term>
<listitem>
<para>
Details about the authentication request. This is a dictionary of key/value pairs where both key and value are strings. These strings are translated into the locale passed when registering the authentication agent using <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent().</link>.
Details about the authentication request. This is a dictionary of key/value pairs where both key and value are strings. These strings are translated into the locale passed when registering the authentication agent using <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link>.
Keys starting with <literal>polkit.</literal> are reserved for internal use and should never be displayed in the UI.
Known key/value-pairs include <literal>polkit.caller-pid</literal> (the process id of the mechanism making the authorization check) and <literal>polkit.subject-pid</literal> (the process id of the subject the check is for).
</para>
......
......@@ -461,7 +461,7 @@ TRUE if the given <link linkend="eggdbus-struct-Subject">Subject</link> could be
<term><literal>Dict&lt;String,String&gt; <structfield>details</structfield></literal></term>
<listitem>
<para>
Details for the result or empty if not authorized. Known key/value-pairs include <literal>polkit.temporary_authorization_id</literal> (if the authorization is temporary, this is set to the opaque temporary authorization id), <literal>polkit.retains_authorization_after_challenge</literal> (Set to a non-empty string if the authorization will be retained after authentication (if is_challenge is TRUE)).
Details for the result or empty if not authorized. Known key/value-pairs include <literal>polkit.temporary_authorization_id</literal> (if the authorization is temporary, this is set to the opaque temporary authorization id), <literal>polkit.retains_authorization_after_challenge</literal> (Set to a non-empty string if the authorization will be retained after authentication (if is_challenge is TRUE)), <literal>polkit.dismissed</literal> (Set to a non-empty string if the authentication dialog was dismissed by the user).
</para>
</listitem>
</varlistentry>
......
......@@ -71,6 +71,7 @@ polkit_authorization_result_get_is_authorized
polkit_authorization_result_get_is_challenge
polkit_authorization_result_get_retains_authorization
polkit_authorization_result_get_temporary_authorization_id
polkit_authorization_result_get_dismissed
polkit_authorization_result_get_details
<SUBSECTION Standard>
PolkitAuthorizationResultClass
......
......@@ -238,6 +238,35 @@ polkit_authorization_result_get_temporary_authorization_id (PolkitAuthorizationR
return ret;
}
/**
* polkit_authorization_result_get_dismissed:
* @result: A #PolkitAuthorizationResult.
*
* Gets whether the authentication request was dismissed / canceled by the user.
*
* This method simply reads the value of the key/value pair in @details with the
* key <literal>polkit.dismissed</literal>.
*
* Returns: %TRUE if the authentication request was dismissed, %FALSE otherwise.
*
* Since: 0.101
*/
gboolean
polkit_authorization_result_get_dismissed (PolkitAuthorizationResult *result)
{
gboolean ret;
PolkitDetails *details;
g_return_val_if_fail (POLKIT_IS_AUTHORIZATION_RESULT (result), FALSE);
ret = FALSE;
details = polkit_authorization_result_get_details (result);
if (details != NULL && polkit_details_lookup (details, "polkit.dismissed") != NULL)
ret = TRUE;
return ret;
}
PolkitAuthorizationResult *
polkit_authorization_result_new_for_gvariant (GVariant *value)
{
......
......@@ -52,6 +52,7 @@ gboolean polkit_authorization_result_get_is_authorized (P
gboolean polkit_authorization_result_get_is_challenge (PolkitAuthorizationResult *result);
gboolean polkit_authorization_result_get_retains_authorization (PolkitAuthorizationResult *result);
const gchar *polkit_authorization_result_get_temporary_authorization_id (PolkitAuthorizationResult *result);
gboolean polkit_authorization_result_get_dismissed (PolkitAuthorizationResult *result);
/* ---------------------------------------------------------------------------------------------------- */
......
......@@ -552,11 +552,22 @@ acquire_cb (GObject *source_object,
process_result (data->permission, result);
if (!polkit_authorization_result_get_is_authorized (result))
{
g_simple_async_result_set_error (data->simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Failed to acquire permission for action-id %s",
data->permission->action_id);
if (polkit_authorization_result_get_dismissed (result))
{
g_simple_async_result_set_error (data->simple,
G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"User dismissed authentication dialog while trying to acquire permission for action-id %s",
data->permission->action_id);
}
else
{
g_simple_async_result_set_error (data->simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Failed to acquire permission for action-id %s",
data->permission->action_id);
}
}
g_object_unref (result);
}
......@@ -640,6 +651,14 @@ acquire (GPermission *gpermission,
{
ret = TRUE;
}
else if (polkit_authorization_result_get_dismissed (result))
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"User dismissed authentication dialog while trying to acquire permission for action-id %s",
permission->action_id);
}
else
{
g_set_error (error,
......
......@@ -82,6 +82,7 @@ typedef void (*AuthenticationAgentCallback) (AuthenticationAgent *agent,
const gchar *action_id,
PolkitImplicitAuthorization implicit_authorization,
gboolean authentication_success,
gboolean was_dismissed,
PolkitIdentity *authenticated_identity,
gpointer user_data);
......@@ -274,6 +275,10 @@ polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *au
PolkitBackendInteractiveAuthorityPrivate *priv;
GFile *directory;
GError *error;
static volatile GQuark domain = 0;
/* Force registering error domain */
domain = POLKIT_ERROR;
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
......@@ -582,6 +587,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
const gchar *action_id,
PolkitImplicitAuthorization implicit_authorization,
gboolean authentication_success,
gboolean was_dismissed,
PolkitIdentity *authenticated_identity,
gpointer user_data)
{
......@@ -613,9 +619,11 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
g_debug ("In check_authorization_challenge_cb\n"
" subject %s\n"
" action_id %s\n"
" was_dismissed %d\n"
" authentication_success %d\n",
subject_str,
action_id,
was_dismissed,
authentication_success);
is_temp = FALSE;
......@@ -649,8 +657,15 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
}
else
{
PolkitDetails *details;
/* TODO: maybe return set is_challenge? */
result = polkit_authorization_result_new (FALSE, FALSE, NULL);
details = polkit_details_new ();
if (was_dismissed)
polkit_details_insert (details, "polkit.dismissed", "true");
result = polkit_authorization_result_new (FALSE, FALSE, details);
g_object_unref (details);
}
/* Log the event */
......@@ -1633,16 +1648,24 @@ authentication_agent_begin_cb (GDBusProxy *proxy,
{
AuthenticationSession *session = user_data;
gboolean gained_authorization;
gboolean was_dismissed;
GError *error;
was_dismissed = FALSE;
gained_authorization = FALSE;
error = NULL;
if (!g_dbus_proxy_call_finish (proxy,
res,
&error))
{
g_printerr ("Error performing authentication: %s\n", error->message);
g_printerr ("Error performing authentication: %s (%s %d)\n",
error->message,
g_quark_to_string (error->domain),
error->code);
if (error->domain == POLKIT_ERROR && error->code == POLKIT_ERROR_CANCELLED)
was_dismissed = TRUE;
g_error_free (error);
gained_authorization = FALSE;
}
else
{
......@@ -1660,6 +1683,7 @@ authentication_agent_begin_cb (GDBusProxy *proxy,
session->action_id,
session->implicit_authorization,
gained_authorization,
was_dismissed,
session->authenticated_identity,
session->user_data);
......
......@@ -714,10 +714,19 @@ main (int argc, char *argv[])
}
else
{
log_message (LOG_WARNING, TRUE,
"Error executing command as another user: Not authorized");
g_printerr ("\n"
"This incident has been reported.\n");
if (polkit_authorization_result_get_dismissed (result))
{
log_message (LOG_WARNING, TRUE,
"Error executing command as another user: Request dismissed");
ret = 126;
}
else
{
log_message (LOG_WARNING, TRUE,
"Error executing command as another user: Not authorized");
g_printerr ("\n"
"This incident has been reported.\n");
}
goto out;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment