diff --git a/.packit/polkit.spec b/.packit/polkit.spec index ce5712bc..e9b92195 100644 --- a/.packit/polkit.spec +++ b/.packit/polkit.spec @@ -125,6 +125,8 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.la %{_datadir}/dbus-1/system.d/org.freedesktop.PolicyKit1.conf %{_datadir}/dbus-1/system-services/* %{_unitdir}/polkit.service +%{_unitdir}/polkit-agent-helper.socket +%{_unitdir}/polkit-agent-helper@.service %dir %{_datadir}/polkit-1/ %dir %{_datadir}/polkit-1/actions %attr(0750,root,polkitd) %dir %{_datadir}/polkit-1/rules.d diff --git a/data/meson.build b/data/meson.build index 5b2db9d2..bce75d7b 100644 --- a/data/meson.build +++ b/data/meson.build @@ -39,6 +39,19 @@ if not get_option('libs-only') install_dir: systemdsystemunitdir, ) + configure_file( + input: 'polkit-agent-helper@.service.in', + output: '@BASENAME@', + configuration: service_conf, + install: true, + install_dir: systemdsystemunitdir, + ) + + install_data( + 'polkit-agent-helper.socket', + install_dir: systemdsystemunitdir, + ) + configure_file( input: 'polkit.conf.in', output: '@BASENAME@', diff --git a/data/polkit-agent-helper.socket b/data/polkit-agent-helper.socket new file mode 100644 index 00000000..e8fa80b5 --- /dev/null +++ b/data/polkit-agent-helper.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Authorization Manager Agent Helper +Documentation=man:polkit(8) + +[Socket] +Accept=yes +RemoveOnStop=yes +ListenStream=/run/polkit/agent-helper.socket + +[Install] +WantedBy=sockets.target diff --git a/data/polkit-agent-helper@.service.in b/data/polkit-agent-helper@.service.in new file mode 100644 index 00000000..6f8cf683 --- /dev/null +++ b/data/polkit-agent-helper@.service.in @@ -0,0 +1,34 @@ +[Unit] +Description=Authorization Manager Agent Helper +Documentation=man:polkit(8) + +[Service] +Type=oneshot +DeviceAllow=/dev/null rw +DevicePolicy=strict +ExecStart=@libprivdir@/polkit-agent-helper-1 --socket-activated +StandardInput=socket +StandardOutput=socket +LimitMEMLOCK=0 +LockPersonality=yes +MemoryDenyWriteExecute=yes +NoNewPrivileges=yes +PrivateDevices=yes +PrivateNetwork=yes +PrivateTmp=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectKernelModules=yes +ProtectKernelLogs=yes +ProtectKernelTunables=yes +ProtectSystem=strict +ProtectClock=yes +ProtectHostname=yes +RemoveIPC=yes +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=yes +RestrictRealtime=yes +RestrictSUIDSGID=yes +SystemCallArchitectures=native +SystemCallFilter=@system-service +UMask=0077 diff --git a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml index 91fc6441..216aba17 100644 --- a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml +++ b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml @@ -44,6 +44,9 @@ Structure TemporaryAuth IN Identity identity) AuthenticationAgentResponse2 (IN uint32 uid, IN String cookie, IN Identity identity) +AuthenticationAgentResponse3 (IN String cookie, + IN Identity identity, + IN Subject subject) EnumerateTemporaryAuthorizations (IN Subject subject, OUT Array<TemporaryAuthorization> temporary_authorizations) RevokeTemporaryAuthorizations (IN Subject subject) @@ -316,7 +319,7 @@ Details about the subject. Depending of the value of subject_kind -This struct describes identities such as UNIX users and UNIX groups. It is typically used to check if a given process is authorized for an action.The following kinds of identities are known: Unix Useridentity_kind should be set to unix-user with key uid (of type uint32). Unix Groupidentity_kind should be set to unix-group with key gid (of type uint32). +This struct describes identities such as UNIX users and UNIX groups. It is typically used to check if a given process is authorized for an action.The following kinds of identities are known: Unix Useridentity_kind should be set to unix-user with key uid (of type uint32). Unix Groupidentity_kind should be set to unix-group with key gid (of type uint32). @@ -853,6 +856,47 @@ A Identity struct describing what + + + + AuthenticationAgentResponse3 () + +AuthenticationAgentResponse3 (IN String cookie, + IN Identity identity, + IN Subject subject) + + +Method for authentication agents to invoke on successful +authentication, intended only for use by a privileged helper process +running via socket activation. This method will fail unless a sufficiently privileged +caller invokes it. In contract to other methods this takes a subject as input, which +allows reliably tracking the requester via PID FD. + + + + IN String cookie: + + +The cookie identifying the authentication request that was passed to the authentication agent. + + + + + IN Identity identity: + + +A Identity struct describing what identity was authenticated. + + + + + IN Subject subject: + + +A Subject struct describing what entity requested the authentication. + + + diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt index e7db6e37..6dcd2269 100644 --- a/docs/polkit/polkit-1-sections.txt +++ b/docs/polkit/polkit-1-sections.txt @@ -48,6 +48,8 @@ polkit_authority_unregister_authentication_agent_sync polkit_authority_authentication_agent_response polkit_authority_authentication_agent_response_finish polkit_authority_authentication_agent_response_sync +polkit_authority_authentication_agent_response_with_subject +polkit_authority_authentication_agent_response_with_subject_sync polkit_authority_enumerate_temporary_authorizations polkit_authority_enumerate_temporary_authorizations_finish polkit_authority_enumerate_temporary_authorizations_sync diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c index f0986d77..afdd04d6 100644 --- a/src/polkit/polkitauthority.c +++ b/src/polkit/polkitauthority.c @@ -1488,6 +1488,67 @@ polkit_authority_unregister_authentication_agent_sync (PolkitAuthority *auth /* ---------------------------------------------------------------------------------------------------- */ +/** + * polkit_authority_authentication_agent_response: + * @authority: A #PolkitAuthority. + * @cookie: The cookie passed to the authentication agent from the authority. + * @identity: The identity that was authenticated. + * @subject: The subject that requested the authentication. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied. + * @user_data: The data to pass to @callback. + * + * Asynchronously provide response that @identity successfully authenticated + * for the authentication request identified by @cookie as requested by @subject. + * + * This function is only used by the socket-activated agent helper, running as uiid + * 0, and will fail otherwise. The requesting process is identified via @subject + * which will contain a PID FD identifying the process. + * + * When the operation is finished, @callback will be invoked in the + * thread-default + * main loop of the thread you are calling this method + * from. You can then call + * polkit_authority_authentication_agent_response_finish() to get the + * result of the operation. + **/ +void +polkit_authority_authentication_agent_response_with_subject (PolkitAuthority *authority, + const gchar *cookie, + PolkitIdentity *identity, + PolkitSubject *subject, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* Unlike the polkit_authority_authentication_agent_response variant, + * this one is called from a socket-activated service, rather than a + * setuid helper invoked directly by the authenticating process. + */ + g_return_if_fail (POLKIT_IS_AUTHORITY (authority)); + g_return_if_fail (cookie != NULL); + g_return_if_fail (POLKIT_IS_IDENTITY (identity)); + g_return_if_fail (POLKIT_IS_SUBJECT (subject)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + g_dbus_proxy_call (authority->proxy, + "AuthenticationAgentResponse3", + g_variant_new ("(s@(sa{sv})@(sa{sv}))", + cookie, + polkit_identity_to_gvariant (identity), /* Floating value */ + polkit_subject_to_gvariant (subject)), /* Floating value */ + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + generic_async_cb, + g_simple_async_result_new (G_OBJECT (authority), + callback, + user_data, + polkit_authority_authentication_agent_response)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + /** * polkit_authority_authentication_agent_response: * @authority: A #PolkitAuthority. @@ -1630,6 +1691,53 @@ polkit_authority_authentication_agent_response_sync (PolkitAuthority *author return ret; } + +/** + * polkit_authority_authentication_agent_response_with_subject_sync: + * @authority: A #PolkitAuthority. + * @cookie: The cookie passed to the authentication agent from the authority. + * @identity: The identity that was authenticated. + * @subject: The subject that requested the authentication. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @error: (allow-none): Return location for error or %NULL. + * + * Provide response that @identity successfully authenticated for the + * authentication request identified by @cookie. See polkit_authority_authentication_agent_response_with_subject() + * for limitations on who is allowed is to call this method. + * + * The calling thread is blocked until a reply is received. See + * polkit_authority_authentication_agent_response_with_subject() for the + * asynchronous version. + * + * Returns: %TRUE if @authority acknowledged the call, %FALSE if @error is set. + **/ +gboolean +polkit_authority_authentication_agent_response_with_subject_sync (PolkitAuthority *authority, + const gchar *cookie, + PolkitIdentity *identity, + PolkitSubject *subject, + GCancellable *cancellable, + GError **error) +{ + gboolean ret; + CallSyncData *data; + + g_return_val_if_fail (POLKIT_IS_AUTHORITY (authority), FALSE); + g_return_val_if_fail (cookie != NULL, FALSE); + g_return_val_if_fail (POLKIT_IS_IDENTITY (identity), FALSE); + g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + data = call_sync_new (); + polkit_authority_authentication_agent_response_with_subject (authority, cookie, identity, subject, cancellable, call_sync_cb, data); + call_sync_block (data); + ret = polkit_authority_authentication_agent_response_finish (authority, data->res, error); + call_sync_free (data); + + return ret; +} + /* ---------------------------------------------------------------------------------------------------- */ /** diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h index 921b7125..cd0986c0 100644 --- a/src/polkit/polkitauthority.h +++ b/src/polkit/polkitauthority.h @@ -103,6 +103,13 @@ gboolean polkit_authority_authentication_agent_response_sync ( GCancellable *cancellable, GError **error); +gboolean polkit_authority_authentication_agent_response_with_subject_sync (PolkitAuthority *authority, + const gchar *cookie, + PolkitIdentity *identity, + PolkitSubject *subject, + GCancellable *cancellable, + GError **error); + GList *polkit_authority_enumerate_temporary_authorizations_sync (PolkitAuthority *authority, PolkitSubject *subject, GCancellable *cancellable, @@ -186,6 +193,14 @@ void polkit_authority_authentication_agent_response (Polki GAsyncReadyCallback callback, gpointer user_data); +void polkit_authority_authentication_agent_response_with_subject (PolkitAuthority *authority, + const gchar *cookie, + PolkitIdentity *identity, + PolkitSubject *subject, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean polkit_authority_authentication_agent_response_finish (PolkitAuthority *authority, GAsyncResult *res, GError **error); diff --git a/src/polkitagent/polkitagenthelper-bsdauth.c b/src/polkitagent/polkitagenthelper-bsdauth.c index 6aeb953b..95d99629 100644 --- a/src/polkitagent/polkitagenthelper-bsdauth.c +++ b/src/polkitagent/polkitagenthelper-bsdauth.c @@ -114,7 +114,7 @@ main (int argc, char *argv[]) /* now send a D-Bus message to the polkit daemon that * includes a) the cookie; and b) the user we authenticated */ - if (!send_dbus_message (cookie, user_to_auth)) + if (!send_dbus_message (cookie, user_to_auth, -1, -1)) { #ifdef PAH_DEBUG fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to polkit daemon\n"); diff --git a/src/polkitagent/polkitagenthelper-pam.c b/src/polkitagent/polkitagenthelper-pam.c index 2054bcd1..0b23e29a 100644 --- a/src/polkitagent/polkitagenthelper-pam.c +++ b/src/polkitagent/polkitagenthelper-pam.c @@ -27,11 +27,22 @@ #include #include #include +#include #include #include #include +#ifndef SO_PEERPIDFD +# if defined(__parisc__) +# define SO_PEERPIDFD 0x404B +# elif defined(__sparc__) +# define SO_PEERPIDFD 0x0056 +# else +# define SO_PEERPIDFD 77 +# endif +#endif + static int conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data); static void @@ -73,7 +84,10 @@ int main (int argc, char *argv[]) { int rc; + int pidfd = -1; + int uid = -1; const char *user_to_auth; + char *user_to_auth_free = NULL; char *cookie = NULL; struct pam_conv pam_conversation; pam_handle_t *pam_h; @@ -113,7 +127,47 @@ main (int argc, char *argv[]) goto error; } - user_to_auth = argv[1]; + /* We are socket activated and the socket has been set up as stdio/stdout, read user from it */ + if (argv[1] != NULL && strcmp (argv[1], "--socket-activated") == 0) + { + socklen_t socklen = sizeof(int); + struct ucred ucred; + + user_to_auth_free = read_cookie (argc, argv); + if (!user_to_auth_free) + goto error; + user_to_auth = user_to_auth_free; + + rc = getsockopt(STDIN_FILENO, SOL_SOCKET, SO_PEERPIDFD, &pidfd, &socklen); + if (rc < 0) + { + if (errno == ENOPROTOOPT || errno == ENODATA) + { + syslog (LOG_ERR, "Pidfd not supported on this platform, disable polkit-agent-helper.socket and use setuid helper"); + fprintf (stderr, "polkit-agent-helper-1: pidfd not supported on this platform, disable polkit-agent-helper.socket and use setuid helper.\n"); + } + if (errno == EINVAL) + { + syslog (LOG_ERR, "Caller already exited, unable to get pidfd"); + fprintf (stderr, "polkit-agent-helper-1: caller already exited, unable to get pidfd.\n"); + } + + goto error; + } + + socklen = sizeof(ucred); + rc = getsockopt(STDIN_FILENO, SOL_SOCKET, SO_PEERCRED, &ucred, &socklen); + if (rc < 0) + { + syslog (LOG_ERR, "Unable to get credentials from socket"); + fprintf (stderr, "polkit-agent-helper-1: unable to get credentials from socket.\n"); + goto error; + } + + uid = ucred.uid; + } + else + user_to_auth = argv[1]; cookie = read_cookie (argc, argv); if (!cookie) @@ -205,9 +259,10 @@ main (int argc, char *argv[]) #endif /* PAH_DEBUG */ /* now send a D-Bus message to the PolicyKit daemon that - * includes a) the cookie; and b) the user we authenticated + * includes a) the cookie; b) the user we authenticated; + * c) the pidfd and uid of the caller, if socket-activated */ - if (!send_dbus_message (cookie, user_to_auth)) + if (!send_dbus_message (cookie, user_to_auth, pidfd, uid)) { #ifdef PAH_DEBUG fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to PolicyKit daemon\n"); @@ -216,6 +271,9 @@ main (int argc, char *argv[]) } free (cookie); + free (user_to_auth_free); + if (pidfd >= 0) + close (pidfd); #ifdef PAH_DEBUG fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n"); @@ -227,6 +285,9 @@ main (int argc, char *argv[]) error: free (cookie); + free (user_to_auth_free); + if (pidfd >= 0) + close (pidfd); if (pam_h != NULL) pam_end (pam_h, rc); diff --git a/src/polkitagent/polkitagenthelper-shadow.c b/src/polkitagent/polkitagenthelper-shadow.c index f45d9aaf..e194b993 100644 --- a/src/polkitagent/polkitagenthelper-shadow.c +++ b/src/polkitagent/polkitagenthelper-shadow.c @@ -147,7 +147,7 @@ main (int argc, char *argv[]) /* now send a D-Bus message to the PolicyKit daemon that * includes a) the cookie; and b) the user we authenticated */ - if (!send_dbus_message (cookie, user_to_auth)) + if (!send_dbus_message (cookie, user_to_auth, -1, -1)) { #ifdef PAH_DEBUG fprintf (stderr, "polkit-agent-helper-1: error sending D-Bus message to PolicyKit daemon\n"); diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c index 7358b178..dc1fc97f 100644 --- a/src/polkitagent/polkitagenthelperprivate.c +++ b/src/polkitagent/polkitagenthelperprivate.c @@ -78,10 +78,11 @@ read_cookie (int argc, char **argv) } gboolean -send_dbus_message (const char *cookie, const char *user) +send_dbus_message (const char *cookie, const char *user, int pidfd, int uid) { PolkitAuthority *authority = NULL; PolkitIdentity *identity = NULL; + PolkitSubject *subject = NULL; GError *error; gboolean ret; @@ -104,11 +105,23 @@ send_dbus_message (const char *cookie, const char *user) goto out; } - if (!polkit_authority_authentication_agent_response_sync (authority, - cookie, - identity, - NULL, - &error)) + if (pidfd >= 0 && uid >= 0) + { + subject = polkit_unix_process_new_pidfd (pidfd, uid, NULL); + ret = polkit_authority_authentication_agent_response_with_subject_sync (authority, + cookie, + identity, + subject, + NULL, + &error); + } + else + ret = polkit_authority_authentication_agent_response_sync (authority, + cookie, + identity, + NULL, + &error); + if (!ret) { g_printerr ("polkit-agent-helper-1: error response to PolicyKit daemon: %s\n", error->message); g_error_free (error); @@ -125,6 +138,9 @@ send_dbus_message (const char *cookie, const char *user) if (authority != NULL) g_object_unref (authority); + if (subject != NULL) + g_object_unref (subject); + return ret; } diff --git a/src/polkitagent/polkitagenthelperprivate.h b/src/polkitagent/polkitagenthelperprivate.h index c5145b5e..e8bafdae 100644 --- a/src/polkitagent/polkitagenthelperprivate.h +++ b/src/polkitagent/polkitagenthelperprivate.h @@ -39,7 +39,7 @@ int _polkit_clearenv (void); char *read_cookie (int argc, char **argv); -gboolean send_dbus_message (const char *cookie, const char *user); +gboolean send_dbus_message (const char *cookie, const char *user, int pidfd, int uid); void flush_and_wait (); diff --git a/src/polkitagent/polkitagentsession.c b/src/polkitagent/polkitagentsession.c index d4a3f46f..5c72f6b1 100644 --- a/src/polkitagent/polkitagentsession.c +++ b/src/polkitagent/polkitagentsession.c @@ -91,6 +91,7 @@ struct _PolkitAgentSession GOutputStream *child_stdin; int child_stdout; GPid child_pid; + GSocketConnection *helper_socket; GSource *child_stdout_watch_source; GIOChannel *child_stdout_channel; @@ -366,6 +367,14 @@ kill_helper (PolkitAgentSession *session) if (!session->helper_is_running) goto out; + if (session->helper_socket) + { + g_io_stream_close (G_IO_STREAM (session->helper_socket), NULL, NULL); + g_object_unref (session->helper_socket); + session->helper_socket = NULL; + session->child_stdout = -1; + } + if (session->child_pid > 0) { gint status; @@ -595,35 +604,70 @@ polkit_agent_session_initiate (PolkitAgentSession *session) goto error; } - helper_argv[0] = PACKAGE_PREFIX "/lib/polkit-1/polkit-agent-helper-1"; - helper_argv[1] = passwd->pw_name; - helper_argv[2] = NULL; - session->child_stdout = -1; - error = NULL; - if (!g_spawn_async_with_pipes (NULL, - (char **) helper_argv, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD | - 0,//G_SPAWN_STDERR_TO_DEV_NULL, - NULL, - NULL, - &session->child_pid, - &stdin_fd, - &session->child_stdout, - NULL, - &error)) + /* Let's check if there is a socket, so that we can do the authentication without SETUID */ + if (g_file_test ("/run/polkit/agent-helper.socket", G_FILE_TEST_EXISTS)) { - g_warning ("Cannot spawn helper: %s\n", error->message); - g_error_free (error); - goto error; + error = NULL; + session->helper_socket = g_socket_client_connect (g_socket_client_new (), + G_SOCKET_CONNECTABLE (g_unix_socket_address_new ("/run/polkit/agent-helper.socket")), + NULL, + &error); + if (session->helper_socket == NULL) + { + g_warning ("Cannot connect to helper via /run/polkit/agent-helper.socket, falling back to spawn suid helper instead: %s\n", error->message); + g_error_free (error); + /* Fallback to setuid helper */ + } + else + { + int fd; + + if (G_UNLIKELY (_show_debug ())) + g_print ("PolkitAgentSession: connected to helper via /run/polkit/agent-helper.socket\n"); + + fd = g_socket_get_fd (g_socket_connection_get_socket (session->helper_socket )); + session->child_stdout = fd; + + session->child_stdin = (GOutputStream*)g_unix_output_stream_new (fd, FALSE); + + (void) g_output_stream_write_all (session->child_stdin, passwd->pw_name, strlen (passwd->pw_name), + NULL, NULL, NULL); + (void) g_output_stream_write_all (session->child_stdin, "\n", 1, NULL, NULL, NULL); + } } - if (G_UNLIKELY (_show_debug ())) - g_print ("PolkitAgentSession: spawned helper with pid %d\n", (gint) session->child_pid); + if (session->child_stdout == -1) + { + helper_argv[0] = PACKAGE_PREFIX "/lib/polkit-1/polkit-agent-helper-1"; + helper_argv[1] = passwd->pw_name; + helper_argv[2] = NULL; + + error = NULL; + if (!g_spawn_async_with_pipes (NULL, + (char **) helper_argv, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD | + 0,//G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + &session->child_pid, + &stdin_fd, + &session->child_stdout, + NULL, + &error)) + { + g_warning ("Cannot spawn helper: %s\n", error->message); + g_error_free (error); + goto error; + } - session->child_stdin = (GOutputStream*)g_unix_output_stream_new (stdin_fd, TRUE); + if (G_UNLIKELY (_show_debug ())) + g_print ("PolkitAgentSession: spawned helper with pid %d\n", (gint) session->child_pid); + + session->child_stdin = (GOutputStream*)g_unix_output_stream_new (stdin_fd, TRUE); + } /* Write the cookie on stdin so it can't be seen by other processes */ (void) g_output_stream_write_all (session->child_stdin, session->cookie, strlen (session->cookie), diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index 6981491f..47c6faf3 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -639,6 +639,11 @@ static const gchar *server_introspection_data = " " " " " " + " " + " " + " " + " " + " " " " " " " " @@ -1166,6 +1171,87 @@ server_handle_authentication_agent_response2 (Server *server, g_object_unref (identity); } +static void +server_handle_authentication_agent_response3 (Server *server, + GVariant *parameters, + PolkitSubject *caller, + GDBusMethodInvocation *invocation) +{ + const gchar *cookie; + GVariant *identity_gvariant; + GVariant *subject_gvariant; + PolkitIdentity *identity; + PolkitSubject *subject; + GError *error; + + identity = NULL; + subject = NULL; + + g_variant_get (parameters, + "(&s@(sa{sv})@(sa{sv}))", + &cookie, + &identity_gvariant, + &subject_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; + subject = polkit_subject_new_for_gvariant (subject_gvariant, &error); + if (subject == NULL) + { + g_prefix_error (&error, "Error getting subject: "); + g_dbus_method_invocation_return_gerror (invocation, error); + g_error_free (error); + goto out; + } + + error = NULL; + if (polkit_unix_process_get_pidfd (POLKIT_UNIX_PROCESS (subject)) < 0 || + polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject)) <= 0) + { + g_set_error (&error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Subject's PIDFD '%d' for PID '%d' is no longer valid.", + polkit_unix_process_get_pidfd (POLKIT_UNIX_PROCESS (subject)), + polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject))); + 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, + polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)), + 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: + g_variant_unref (identity_gvariant); + g_variant_unref (subject_gvariant); + if (identity != NULL) + g_object_unref (identity); + if (subject != NULL) + g_object_unref (subject); +} + /* ---------------------------------------------------------------------------------------------------- */ static void @@ -1338,6 +1424,8 @@ server_handle_method_call (GDBusConnection *connection, 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, "AuthenticationAgentResponse3") == 0) + server_handle_authentication_agent_response3 (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)