diff options
-rw-r--r-- | data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml | 14 | ||||
-rw-r--r-- | data/org.freedesktop.PolicyKit1.Authority.xml | 24 | ||||
-rw-r--r-- | docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml | 46 | ||||
-rw-r--r-- | docs/polkit/overview.xml | 18 | ||||
-rw-r--r-- | src/polkit/polkitauthority.c | 13 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendauthority.c | 61 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendauthority.h | 2 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendinteractiveauthority.c | 39 |
8 files changed, 198 insertions, 19 deletions
diff --git a/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml b/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml index 3b519c2..5beef7d 100644 --- a/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml +++ b/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml @@ -8,7 +8,19 @@ <annotation name="org.gtk.EggDBus.DocString" value="<para>This D-Bus interface is used for communication between the system-wide PolicyKit daemon and one or more authentication agents each running in a user session.</para><para>An authentication agent must implement this interface and register (passing the object path of the object implementing the interface) using the org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent() and org.freedesktop.PolicyKit1.Authority.UnregisterAuthenticationAgent() methods on the #org.freedesktop.PolicyKit1.Authority interface of the PolicyKit daemon.</para>"/> <method name="BeginAuthentication"> - <annotation name="org.gtk.EggDBus.DocString" value="<para>Called by the PolicyKit daemon when the authentication agent needs the user to authenticate as one of the identities in @identities for the action with the identifier @action_id.</para><para>Upon succesful authentication, the authentication agent must invoke the org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse() method on the #org.freedesktop.PolicyKit1.Authority interface of the PolicyKit daemon before returning.</para><para>If the user dismisses the authentication dialog, the authentication agent should return an error.</para>"/> + <annotation name="org.gtk.EggDBus.DocString" value="<para>Called + by the PolicyKit daemon when the authentication agent needs the + user to authenticate as one of the identities in @identities for + the action with the identifier @action_id.</para><para>This + authentication is normally achieved via the + polkit_agent_session_response() API, which invokes a private + setuid helper process to verify the authentication. When + successful, it calls the + org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2() + method on the #org.freedesktop.PolicyKit1.Authority interface of + the PolicyKit daemon before returning. If the user dismisses the + authentication dialog, the authentication agent should call + polkit_agent_session_cancel().</para>"/> <arg name="action_id" direction="in" type="s"> <annotation name="org.gtk.EggDBus.DocString" value="The identifier for the action that the user is authentication for."/> diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml index fbfb9cd..f9021ee 100644 --- a/data/org.freedesktop.PolicyKit1.Authority.xml +++ b/data/org.freedesktop.PolicyKit1.Authority.xml @@ -313,7 +313,29 @@ </method> <method name="AuthenticationAgentResponse"> - <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful authentication. This method will fail unless a sufficiently privileged caller invokes it."/> + <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful +authentication, intended only for use by a privileged helper process +internal to polkit."/> + + <arg name="cookie" direction="in" type="s"> + <annotation name="org.gtk.EggDBus.DocString" value="The cookie identifying the authentication request that was passed to the authentication agent."/> + </arg> + + <arg name="identity" direction="in" type="(sa{sv})"> + <annotation name="org.gtk.EggDBus.Type" value="Identity"/> + <annotation name="org.gtk.EggDBus.DocString" value="A #Identity struct describing what identity was authenticated."/> + </arg> + </method> + + <method name="AuthenticationAgentResponse2"> + <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful +authentication, intended only for use by a privileged helper process +internal to polkit. Note this method was added in 0.114, and should be preferred over AuthenticationAgentResponse +as it fixes a security issue."/> + + <arg name="uid" direction="in" type="u"> + <annotation name="org.gtk.EggDBus.DocString" value="The real uid of the agent. Normally set by the setuid helper program."/> + </arg> <arg name="cookie" direction="in" type="s"> <annotation name="org.gtk.EggDBus.DocString" value="The cookie identifying the authentication request that was passed to the authentication agent."/> diff --git a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml index 6525e25..e66bf53 100644 --- a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml +++ b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml @@ -42,6 +42,8 @@ Structure <link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuth IN String object_path) <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse</link> (IN String cookie, IN <link linkend="eggdbus-struct-Identity">Identity</link> identity) +<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse2</link> (IN uint32 uid, IN String cookie, + IN <link linkend="eggdbus-struct-Identity">Identity</link> identity) <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.EnumerateTemporaryAuthorizations">EnumerateTemporaryAuthorizations</link> (IN <link linkend="eggdbus-struct-Subject">Subject</link> subject, OUT Array<<link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuthorization</link>> temporary_authorizations) <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RevokeTemporaryAuthorizations">RevokeTemporaryAuthorizations</link> (IN <link linkend="eggdbus-struct-Subject">Subject</link> subject) @@ -777,10 +779,52 @@ AuthenticationAgentResponse (IN String cookie, IN <link linkend="eggdbus-struct-Identity">Identity</link> identity) </programlisting> <para> -Method for authentication agents to invoke on successful authentication. This method will fail unless a sufficiently privileged caller invokes it. +Method for authentication agents to invoke on successful +authentication, intended only for use by a privileged helper process +internal to polkit. Deprecated in favor of AuthenticationAgentResponse2. + </para> +<variablelist role="params"> + <varlistentry> + <term><literal>IN String <parameter>cookie</parameter></literal>:</term> + <listitem> + <para> +The cookie identifying the authentication request that was passed to the authentication agent. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>IN <link linkend="eggdbus-struct-Identity">Identity</link> <parameter>identity</parameter></literal>:</term> + <listitem> + <para> +A <link linkend="eggdbus-struct-Identity">Identity</link> struct describing what identity was authenticated. + </para> + </listitem> + </varlistentry> +</variablelist> + </refsect2> + <refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2"> + <title>AuthenticationAgentResponse2 ()</title> + <programlisting> +AuthenticationAgentResponse2 (IN uint32 uid, + IN String cookie, + IN <link linkend="eggdbus-struct-Identity">Identity</link> identity) + </programlisting> + <para> +Method for authentication agents to invoke on successful +authentication, intended only for use by a privileged helper process +internal to polkit. Note this method was introduced in 0.114 to fix a security issue. </para> <variablelist role="params"> <varlistentry> + <term><literal>IN uint32 <parameter>uid</parameter></literal>:</term> + <listitem> + <para> +The user id of the agent; normally this is the owner of the parent pid +of the process that invoked the internal setuid helper. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>IN String <parameter>cookie</parameter></literal>:</term> <listitem> <para> diff --git a/docs/polkit/overview.xml b/docs/polkit/overview.xml index 150a7bc..176d2ea 100644 --- a/docs/polkit/overview.xml +++ b/docs/polkit/overview.xml @@ -314,16 +314,18 @@ <para> Authentication agents are provided by desktop environments. When an user session starts, the agent registers with the polkit - Authority using - the <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link> + Authority using the <link + linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link> method. When services are needed, the authority will invoke - methods on - the <link linkend="eggdbus-interface-org.freedesktop.PolicyKit1.AuthenticationAgent">org.freedesktop.PolicyKit1.AuthenticationAgent</link> + methods on the <link + linkend="eggdbus-interface-org.freedesktop.PolicyKit1.AuthenticationAgent">org.freedesktop.PolicyKit1.AuthenticationAgent</link> D-Bus interface. Once the user is authenticated, (a privileged - part of) the agent invokes - the <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link> - method. Note that the polkit Authority itself does not care - how the agent authenticates the user. + part of) the agent invokes the <link + linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link> + method. This method should be treated as an internal + implementation detail, and callers should use the public shared + library API to invoke it, which currently uses a setuid helper + program. </para> <para> The <link linkend="ref-authentication-agent-api">libpolkit-agent-1</link> diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c index ab6d3cd..6bd684a 100644 --- a/src/polkit/polkitauthority.c +++ b/src/polkit/polkitauthority.c @@ -1492,6 +1492,14 @@ polkit_authority_authentication_agent_response (PolkitAuthority *authority, gpointer user_data) { GVariant *identity_value; + /* Note that in reality, this API is only accessible to root, and + * only called from the setuid helper `polkit-agent-helper-1`. + * + * However, because this is currently public API, we avoid + * triggering warnings from ABI diff type programs by just grabbing + * the real uid of the caller here. + */ + uid_t uid = getuid (); g_return_if_fail (POLKIT_IS_AUTHORITY (authority)); g_return_if_fail (cookie != NULL); @@ -1501,8 +1509,9 @@ polkit_authority_authentication_agent_response (PolkitAuthority *authority, identity_value = polkit_identity_to_gvariant (identity); g_variant_ref_sink (identity_value); g_dbus_proxy_call (authority->proxy, - "AuthenticationAgentResponse", - g_variant_new ("(s@(sa{sv}))", + "AuthenticationAgentResponse2", + g_variant_new ("(us@(sa{sv}))", + (guint32)uid, cookie, identity_value), G_DBUS_CALL_FLAGS_NONE, diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index 601a974..03a4e84 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -355,6 +355,7 @@ polkit_backend_authority_unregister_authentication_agent (PolkitBackendAuthority gboolean polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority *authority, PolkitSubject *caller, + uid_t uid, const gchar *cookie, PolkitIdentity *identity, GError **error) @@ -373,7 +374,7 @@ polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority } else { - return klass->authentication_agent_response (authority, caller, cookie, identity, error); + return klass->authentication_agent_response (authority, caller, uid, cookie, identity, error); } } @@ -587,6 +588,11 @@ static const gchar *server_introspection_data = " <arg type='s' name='cookie' direction='in'/>" " <arg type='(sa{sv})' name='identity' direction='in'/>" " </method>" + " <method name='AuthenticationAgentResponse2'>" + " <arg type='u' name='uid' direction='in'/>" + " <arg type='s' name='cookie' direction='in'/>" + " <arg type='(sa{sv})' name='identity' direction='in'/>" + " </method>" " <method name='EnumerateTemporaryAuthorizations'>" " <arg type='(sa{sv})' name='subject' direction='in'/>" " <arg type='a(ss(sa{sv})tt)' name='temporary_authorizations' direction='out'/>" @@ -1035,6 +1041,57 @@ server_handle_authentication_agent_response (Server *server, error = NULL; if (!polkit_backend_authority_authentication_agent_response (server->authority, caller, + (uid_t)-1, + cookie, + identity, + &error)) + { + g_dbus_method_invocation_return_gerror (invocation, error); + g_error_free (error); + goto out; + } + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); + + out: + if (identity != NULL) + g_object_unref (identity); +} + +static void +server_handle_authentication_agent_response2 (Server *server, + GVariant *parameters, + PolkitSubject *caller, + GDBusMethodInvocation *invocation) +{ + const gchar *cookie; + GVariant *identity_gvariant; + PolkitIdentity *identity; + GError *error; + guint32 uid; + + identity = NULL; + + g_variant_get (parameters, + "(u&s@(sa{sv}))", + &uid, + &cookie, + &identity_gvariant); + + error = NULL; + identity = polkit_identity_new_for_gvariant (identity_gvariant, &error); + if (identity == NULL) + { + g_prefix_error (&error, "Error getting identity: "); + g_dbus_method_invocation_return_gerror (invocation, error); + g_error_free (error); + goto out; + } + + error = NULL; + if (!polkit_backend_authority_authentication_agent_response (server->authority, + caller, + (uid_t)uid, cookie, identity, &error)) @@ -1222,6 +1279,8 @@ server_handle_method_call (GDBusConnection *connection, server_handle_unregister_authentication_agent (server, parameters, caller, invocation); else if (g_strcmp0 (method_name, "AuthenticationAgentResponse") == 0) server_handle_authentication_agent_response (server, parameters, caller, invocation); + else if (g_strcmp0 (method_name, "AuthenticationAgentResponse2") == 0) + server_handle_authentication_agent_response2 (server, parameters, caller, invocation); else if (g_strcmp0 (method_name, "EnumerateTemporaryAuthorizations") == 0) server_handle_enumerate_temporary_authorizations (server, parameters, caller, invocation); else if (g_strcmp0 (method_name, "RevokeTemporaryAuthorizations") == 0) diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h index f9f7385..88df82e 100644 --- a/src/polkitbackend/polkitbackendauthority.h +++ b/src/polkitbackend/polkitbackendauthority.h @@ -147,6 +147,7 @@ struct _PolkitBackendAuthorityClass gboolean (*authentication_agent_response) (PolkitBackendAuthority *authority, PolkitSubject *caller, + uid_t uid, const gchar *cookie, PolkitIdentity *identity, GError **error); @@ -249,6 +250,7 @@ gboolean polkit_backend_authority_unregister_authentication_agent (PolkitBackend gboolean polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority *authority, PolkitSubject *caller, + uid_t uid, const gchar *cookie, PolkitIdentity *identity, GError **error); diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c index 15adc6a..96725f7 100644 --- a/src/polkitbackend/polkitbackendinteractiveauthority.c +++ b/src/polkitbackend/polkitbackendinteractiveauthority.c @@ -108,8 +108,9 @@ static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendI PolkitSubject *subject); -static AuthenticationSession *get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *authority, - const gchar *cookie); +static AuthenticationSession *get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority, + uid_t uid, + const gchar *cookie); static GList *get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendInteractiveAuthority *authority, const gchar *system_bus_unique_name); @@ -169,6 +170,7 @@ static gboolean polkit_backend_interactive_authority_unregister_authentication_a static gboolean polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority *authority, PolkitSubject *caller, + uid_t uid, const gchar *cookie, PolkitIdentity *identity, GError **error); @@ -440,6 +442,7 @@ struct AuthenticationAgent { volatile gint ref_count; + uid_t creator_uid; PolkitSubject *scope; guint64 serial; @@ -1603,6 +1606,7 @@ authentication_agent_unref (AuthenticationAgent *agent) static AuthenticationAgent * authentication_agent_new (guint64 serial, PolkitSubject *scope, + PolkitIdentity *creator, const gchar *unique_system_bus_name, const gchar *locale, const gchar *object_path, @@ -1611,6 +1615,10 @@ authentication_agent_new (guint64 serial, { AuthenticationAgent *agent; GDBusProxy *proxy; + PolkitUnixUser *creator_user; + + g_assert (POLKIT_IS_UNIX_USER (creator)); + creator_user = POLKIT_UNIX_USER (creator); if (!g_variant_is_object_path (object_path)) { @@ -1638,6 +1646,7 @@ authentication_agent_new (guint64 serial, agent->ref_count = 1; agent->serial = serial; agent->scope = g_object_ref (scope); + agent->creator_uid = (uid_t)polkit_unix_user_get_uid (creator_user); agent->object_path = g_strdup (object_path); agent->unique_system_bus_name = g_strdup (unique_system_bus_name); agent->locale = g_strdup (locale); @@ -1736,8 +1745,9 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori } static AuthenticationSession * -get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *authority, - const gchar *cookie) +get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority, + uid_t uid, + const gchar *cookie) { PolkitBackendInteractiveAuthorityPrivate *priv; GHashTableIter hash_iter; @@ -1755,6 +1765,23 @@ get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *author { GList *l; + /* We need to ensure that if somehow we have duplicate cookies + * due to wrapping, that the cookie used is matched to the user + * who called AuthenticationAgentResponse2. See + * http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html + * + * Except if the legacy AuthenticationAgentResponse is invoked, + * we don't know the uid and hence use -1. Continue to support + * the old behavior for backwards compatibility, although everyone + * who is using our own setuid helper will automatically be updated + * to the new API. + */ + if (uid != (uid_t)-1) + { + if (agent->creator_uid != uid) + continue; + } + for (l = agent->active_sessions; l != NULL; l = l->next) { AuthenticationSession *session = l->data; @@ -2544,6 +2571,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken priv->agent_serial++; agent = authentication_agent_new (priv->agent_serial, subject, + user_of_caller, polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)), locale, object_path, @@ -2757,6 +2785,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack static gboolean polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority *authority, PolkitSubject *caller, + uid_t uid, const gchar *cookie, PolkitIdentity *identity, GError **error) @@ -2799,7 +2828,7 @@ polkit_backend_interactive_authority_authentication_agent_response (PolkitBacken } /* find the authentication session */ - session = get_authentication_session_for_cookie (interactive_authority, cookie); + session = get_authentication_session_for_uid_and_cookie (interactive_authority, uid, cookie); if (session == NULL) { g_set_error (error, |