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)