From 914df46f860c28ea29dc93d99e136fe99800a9e7 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Fri, 30 Jan 2009 20:23:02 -0500 Subject: [PATCH] rework API of polkitagent still a work in progress, supporting multiple identities (wheel style auth) is 99% complete. --- src/polkitagent/Makefile.am | 8 +- src/polkitagent/polkitagent.h | 4 +- src/polkitagent/polkitagentauthenticationagent.c | 294 ------------- src/polkitagent/polkitagentauthenticationagent.h | 68 --- src/polkitagent/polkitagentauthenticationsession.c | 362 ---------------- src/polkitagent/polkitagentauthenticationsession.h | 139 ------- src/polkitagent/polkitagenthelper.c | 2 +- src/polkitagent/polkitagentlistener.c | 439 ++++++++++++++++++++ src/polkitagent/polkitagentlistener.h | 95 +++++ src/polkitagent/polkitagentsession.c | 458 +++++++++++++++++++++ src/polkitagent/polkitagentsession.h | 53 +++ src/polkitagent/polkitagenttypes.h | 9 +- src/polkitbackend/polkitbackendlocalauthority.c | 8 +- 13 files changed, 1063 insertions(+), 876 deletions(-) delete mode 100644 src/polkitagent/polkitagentauthenticationagent.c delete mode 100644 src/polkitagent/polkitagentauthenticationagent.h delete mode 100644 src/polkitagent/polkitagentauthenticationsession.c delete mode 100644 src/polkitagent/polkitagentauthenticationsession.h create mode 100644 src/polkitagent/polkitagentlistener.c create mode 100644 src/polkitagent/polkitagentlistener.h create mode 100644 src/polkitagent/polkitagentsession.c create mode 100644 src/polkitagent/polkitagentsession.h diff --git a/src/polkitagent/Makefile.am b/src/polkitagent/Makefile.am index b792f93..7d0d857 100644 --- a/src/polkitagent/Makefile.am +++ b/src/polkitagent/Makefile.am @@ -37,15 +37,15 @@ libpolkit_agent_1includedir=$(includedir)/polkit-1/polkitagent libpolkit_agent_1include_HEADERS = \ polkitagent.h \ polkitagenttypes.h \ - polkitagentauthenticationsession.h \ - polkitagentauthenticationagent.h \ + polkitagentsession.h \ + polkitagentlistener.h \ $(NULL) libpolkit_agent_1_la_SOURCES = \ polkitagent.h \ polkitagenttypes.h \ - polkitagentauthenticationsession.h polkitagentauthenticationsession.c \ - polkitagentauthenticationagent.h polkitagentauthenticationagent.c \ + polkitagentsession.h polkitagentsession.c \ + polkitagentlistener.h polkitagentlistener.c \ $(BUILT_SOURCES) \ $(NULL) diff --git a/src/polkitagent/polkitagent.h b/src/polkitagent/polkitagent.h index 0bc8fdc..4b56683 100644 --- a/src/polkitagent/polkitagent.h +++ b/src/polkitagent/polkitagent.h @@ -23,8 +23,8 @@ #define __POLKIT_AGENT_H #define _POLKIT_AGENT_INSIDE_POLKIT_AGENT_H 1 -#include -#include +#include +#include #undef _POLKIT_AGENT_INSIDE_POLKIT_AGENT_H #endif /* __POLKIT_AGENT_H */ diff --git a/src/polkitagent/polkitagentauthenticationagent.c b/src/polkitagent/polkitagentauthenticationagent.c deleted file mode 100644 index 9917706..0000000 --- a/src/polkitagent/polkitagentauthenticationagent.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: David Zeuthen - */ - -#include "config.h" - -#include -#include "_polkitagentbindings.h" - -#include "polkitagentauthenticationagent.h" - -/** - * SECTION:polkitagentauthenticationagent - * @title: PolkitAgentAuthenticationAgent - * @short_description: Authentication Agent - * - * The #PolkitAgentAuthenticationAgent class is used for implementing authentication agents. - */ - -struct _PolkitAgentAuthenticationAgent -{ - GObject parent_instance; - - EggDBusConnection *system_bus; - - EggDBusObjectProxy *authority_proxy; - - PolkitAuthority *authority; - - gboolean is_registered; - - PolkitAgentAuthenticationAgentBeginFunc begin_func; - PolkitAgentAuthenticationAgentCancelFunc cancel_func; - gpointer user_data; -}; - -struct _PolkitAgentAuthenticationAgentClass -{ - GObjectClass parent_class; - -}; - -static void authentication_agent_iface_init (_PolkitAgentAuthenticationAgentIface *agent_iface); - -G_DEFINE_TYPE_WITH_CODE (PolkitAgentAuthenticationAgent, polkit_agent_authentication_agent, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (_POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, - authentication_agent_iface_init) - ); - -static gboolean -polkit_agent_authentication_agent_register (PolkitAgentAuthenticationAgent *agent, - GError **error) -{ - GError *local_error; - gboolean ret; - - ret = FALSE; - - local_error = NULL; - if (!polkit_authority_register_authentication_agent_sync (agent->authority, - "/org/freedesktop/PolicyKit1/AuthenticationAgent", - NULL, - &local_error)) - { - g_warning ("Unable to register authentication agent: %s", local_error->message); - g_propagate_error (error, local_error); - } - else - { - agent->is_registered = TRUE; - ret = TRUE; - } - - return ret; -} - -static void -name_owner_notify (EggDBusObjectProxy *object_proxy, - GParamSpec *pspec, - gpointer user_data) -{ - PolkitAgentAuthenticationAgent *agent = POLKIT_AGENT_AUTHENTICATION_AGENT (user_data); - gchar *owner; - - owner = egg_dbus_object_proxy_get_name_owner (agent->authority_proxy); - - if (owner == NULL) - { - g_printerr ("PolicyKit daemon disconnected from the bus.\n"); - - if (agent->is_registered) - g_printerr ("We are no longer a registered authentication agent.\n"); - - agent->is_registered = FALSE; - } - else - { - /* only register if there is a name owner */ - if (!agent->is_registered) - { - GError *error; - - g_printerr ("PolicyKit daemon reconnected to bus.\n"); - g_printerr ("Attempting to re-register as an authentication agent.\n"); - - error = NULL; - if (polkit_agent_authentication_agent_register (agent, &error)) - { - g_printerr ("We are now a registered authentication agent.\n"); - } - else - { - g_printerr ("Failed to register as an authentication agent: %s\n", error->message); - g_error_free (error); - } - } - } - - g_free (owner); -} - -static void -polkit_agent_authentication_agent_init (PolkitAgentAuthenticationAgent *agent) -{ - GError *error; - - agent->system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM); - - egg_dbus_connection_register_interface (agent->system_bus, - "/org/freedesktop/PolicyKit1/AuthenticationAgent", - _POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, - G_OBJECT (agent), - G_TYPE_INVALID); - - agent->authority = polkit_authority_get (); - - /* the only use of this proxy is to re-register with the polkit daemon - * if it jumps off the bus and comes back (which is useful for debugging) - */ - agent->authority_proxy = egg_dbus_connection_get_object_proxy (agent->system_bus, - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority"); - - g_signal_connect (agent->authority_proxy, - "notify::name-owner", - G_CALLBACK (name_owner_notify), - agent); - - error = NULL; - if (!polkit_agent_authentication_agent_register (agent, &error)) - { - g_printerr ("Failed to register as an authentication agent: %s\n", error->message); - g_error_free (error); - } -} - -static void -polkit_agent_authentication_agent_finalize (GObject *object) -{ - PolkitAgentAuthenticationAgent *agent = POLKIT_AGENT_AUTHENTICATION_AGENT (object); - GError *error; - - error = NULL; - if (!polkit_authority_unregister_authentication_agent_sync (agent->authority, - "/org/freedesktop/PolicyKit1/AuthenticationAgent", - NULL, - &error)) - { - g_warning ("Error unregistering authentication agent: %s", error->message); - g_error_free (error); - } - - g_object_unref (agent->authority); - - g_object_unref (agent->authority_proxy); - - g_object_unref (agent->system_bus); - - if (G_OBJECT_CLASS (polkit_agent_authentication_agent_parent_class)->finalize != NULL) - G_OBJECT_CLASS (polkit_agent_authentication_agent_parent_class)->finalize (object); -} - -static void -polkit_agent_authentication_agent_class_init (PolkitAgentAuthenticationAgentClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = polkit_agent_authentication_agent_finalize; -} - -PolkitAgentAuthenticationAgent * -polkit_agent_authentication_agent_new (PolkitAgentAuthenticationAgentBeginFunc begin_func, - PolkitAgentAuthenticationAgentCancelFunc cancel_func, - gpointer user_data) -{ - PolkitAgentAuthenticationAgent *agent; - - agent = POLKIT_AGENT_AUTHENTICATION_AGENT (g_object_new (POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, NULL)); - - agent->begin_func = begin_func; - agent->cancel_func = cancel_func; - agent->user_data = user_data; - - return agent; -} - -static void -handle_begin_authentication (_PolkitAgentAuthenticationAgent *instance, - const gchar *action_id, - const gchar *cookie, - EggDBusArraySeq *identities, - EggDBusMethodInvocation *method_invocation) -{ - PolkitAgentAuthenticationAgent *agent = POLKIT_AGENT_AUTHENTICATION_AGENT (instance); - GList *list; - guint n; - GError *error; - - list = NULL; - for (n = 0; n < identities->size; n++) - { - _PolkitIdentity *real_identity = _POLKIT_IDENTITY (identities->data.v_ptr[n]); - - list = g_list_prepend (list, polkit_identity_new_for_real (real_identity)); - } - - list = g_list_reverse (list); - - error = NULL; - - agent->begin_func (agent, - action_id, - cookie, - list, - (gpointer) method_invocation); - - g_list_free (list); -} - -void -polkit_agent_authentication_agent_finish (PolkitAgentAuthenticationAgent *agent, - gpointer pending_call, - GError *error) -{ - EggDBusMethodInvocation *method_invocation = EGG_DBUS_METHOD_INVOCATION (pending_call); - - if (error != NULL) - { - egg_dbus_method_invocation_return_gerror (method_invocation, error); - } - else - { - _polkit_agent_authentication_agent_handle_begin_authentication_finish (method_invocation); - } -} - - -static void -handle_cancel_authentication (_PolkitAgentAuthenticationAgent *instance, - const gchar *cookie, - EggDBusMethodInvocation *method_invocation) -{ - PolkitAgentAuthenticationAgent *agent = POLKIT_AGENT_AUTHENTICATION_AGENT (instance); - - agent->cancel_func (agent, - cookie, - agent->user_data); - - _polkit_agent_authentication_agent_handle_cancel_authentication_finish (method_invocation); -} - -static void -authentication_agent_iface_init (_PolkitAgentAuthenticationAgentIface *agent_iface) -{ - agent_iface->handle_begin_authentication = handle_begin_authentication; - agent_iface->handle_cancel_authentication = handle_cancel_authentication; -} diff --git a/src/polkitagent/polkitagentauthenticationagent.h b/src/polkitagent/polkitagentauthenticationagent.h deleted file mode 100644 index b076f8c..0000000 --- a/src/polkitagent/polkitagentauthenticationagent.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: David Zeuthen - */ - -#ifndef __POLKIT_AGENT_AUTHENTICATION_AGENT_H -#define __POLKIT_AGENT_AUTHENTICATION_AGENT_H - -#include -#include - -G_BEGIN_DECLS - -#define POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT (polkit_agent_authentication_agent_get_type ()) -#define POLKIT_AGENT_AUTHENTICATION_AGENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, PolkitAgentAuthenticationAgent)) -#define POLKIT_AGENT_AUTHENTICATION_AGENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, PolkitAgentAuthenticationAgentClass)) -#define POLKIT_AGENT_AUTHENTICATION_AGENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT,PolkitAgentAuthenticationAgentClass)) -#define POLKIT_AGENT_IS_AUTHENTICATION_AGENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT)) -#define POLKIT_AGENT_IS_AUTHENTICATION_AGENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT)) - -#if 0 -typedef struct _PolkitAgentAuthenticationAgent PolkitAgentAuthenticationAgent; -#endif -typedef struct _PolkitAgentAuthenticationAgentClass PolkitAgentAuthenticationAgentClass; - -/* TODO: we probably want to express this interface in another way but this is good enough for now */ - -typedef void (*PolkitAgentAuthenticationAgentBeginFunc) (PolkitAgentAuthenticationAgent *agent, - const gchar *action_id, - const gchar *cookie, - GList *identities, - gpointer pending_call); - -typedef void (*PolkitAgentAuthenticationAgentCancelFunc) (PolkitAgentAuthenticationAgent *agent, - const gchar *cookie, - gpointer user_data); - -GType polkit_agent_authentication_agent_get_type (void) G_GNUC_CONST; - -PolkitAgentAuthenticationAgent *polkit_agent_authentication_agent_new (PolkitAgentAuthenticationAgentBeginFunc begin_func, - PolkitAgentAuthenticationAgentCancelFunc cancel_func, - gpointer user_data); - -void polkit_agent_authentication_agent_finish (PolkitAgentAuthenticationAgent *agent, - gpointer pending_call, - GError *error); - -/* --- */ - -G_END_DECLS - -#endif /* __POLKIT_AGENT_AUTHENTICATION_AGENT_H */ diff --git a/src/polkitagent/polkitagentauthenticationsession.c b/src/polkitagent/polkitagentauthenticationsession.c deleted file mode 100644 index 8d1a165..0000000 --- a/src/polkitagent/polkitagentauthenticationsession.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: David Zeuthen - */ - -/* TODO: This whole class needs to be rewritten so it uses the main loop etc. etc. - * - * And we REALLY REALLY really really should use signals instead of callbacks... - */ - -/** - * SECTION:polkitagentauthenticationsession - * @title: PolkitAgentAuthenticationSession - * @short_description: Authentcation Sessions - * - * The #PolkitAgentAuthenticationSession class is used for implementing authentication agents. - */ - - -/* for getline(), see below */ -#define _GNU_SOURCE - -#include "config.h" -#include -#include -#include -#include -#include -#include - -#include "polkitagentauthenticationsession.h" - -struct _PolkitAgentAuthenticationSession -{ - GObject parent_instance; - - gchar *cookie; - PolkitIdentity *identity; - - int child_stdin; - int child_stdout; - GPid child_pid; - FILE *child_stdout_f; - - int child_watch_id; - int io_watch_id; - - gboolean success; - gboolean helper_is_running; - - PolkitAgentAuthenticationSessionConversationPromptEchoOff func_prompt_echo_off; - PolkitAgentAuthenticationSessionConversationPromptEchoOn func_prompt_echo_on; - PolkitAgentAuthenticationSessionConversationErrorMessage func_error_message; - PolkitAgentAuthenticationSessionConversationTextInfo func_text_info; - PolkitAgentAuthenticationSessionDone func_done; - void *user_data; -}; - -struct _PolkitAgentAuthenticationSessionClass -{ - GObjectClass parent_class; - -}; - -G_DEFINE_TYPE (PolkitAgentAuthenticationSession, polkit_agent_authentication_session, G_TYPE_OBJECT); - -static void -polkit_agent_authentication_session_init (PolkitAgentAuthenticationSession *session) -{ -} - -static void -polkit_agent_authentication_session_finalize (GObject *object) -{ - PolkitAgentAuthenticationSession *session; - - session = POLKIT_AGENT_AUTHENTICATION_SESSION (object); - - g_free (session->cookie); - if (session->identity != NULL) - g_object_unref (session->identity); - - if (G_OBJECT_CLASS (polkit_agent_authentication_session_parent_class)->finalize != NULL) - G_OBJECT_CLASS (polkit_agent_authentication_session_parent_class)->finalize (object); -} - -static void -polkit_agent_authentication_session_class_init (PolkitAgentAuthenticationSessionClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = polkit_agent_authentication_session_finalize; - - - -} - -PolkitAgentAuthenticationSession * -polkit_agent_authentication_session_new (PolkitIdentity *identity, - const gchar *cookie) -{ - PolkitAgentAuthenticationSession *session; - - session = POLKIT_AGENT_AUTHENTICATION_SESSION (g_object_new (POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION, NULL)); - - session->identity = g_object_ref (identity); - session->cookie = g_strdup (cookie); - - return session; -} - -void -polkit_agent_authentication_session_set_functions (PolkitAgentAuthenticationSession *session, - PolkitAgentAuthenticationSessionConversationPromptEchoOff func_prompt_echo_off, - PolkitAgentAuthenticationSessionConversationPromptEchoOn func_prompt_echo_on, - PolkitAgentAuthenticationSessionConversationErrorMessage func_error_message, - PolkitAgentAuthenticationSessionConversationTextInfo func_text_info, - PolkitAgentAuthenticationSessionDone func_done, - void *user_data) -{ - session->func_prompt_echo_off = func_prompt_echo_off; - session->func_prompt_echo_on = func_prompt_echo_on; - session->func_error_message = func_error_message; - session->func_text_info = func_text_info; - session->func_done = func_done; - session->user_data = user_data; -} - -static void -child_watch_func (GPid pid, gint status, gpointer user_data) -{ - PolkitAgentAuthenticationSession *session = POLKIT_AGENT_AUTHENTICATION_SESSION (user_data); - gint exit_code; - gboolean input_was_bogus; - - g_return_if_fail (session->helper_is_running); - - exit_code = WEXITSTATUS (status); - - g_debug ("pid %d terminated", pid); - waitpid (pid, &status, 0); - - if (exit_code >= 2) - input_was_bogus = TRUE; - else - input_was_bogus = FALSE; - - session->success = (exit_code == 0); - session->helper_is_running = FALSE; - session->func_done (session, session->success, input_was_bogus, session->user_data); -} - -static gboolean -io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data) -{ - PolkitAgentAuthenticationSession *session = POLKIT_AGENT_AUTHENTICATION_SESSION (user_data); - char *line; - size_t line_len; - gchar *id; - size_t id_len; - gchar *response; - gchar *response_prefix; - int fd; - - g_return_val_if_fail (session->helper_is_running, FALSE); - - fd = g_io_channel_unix_get_fd (channel); - - line = NULL; - line_len = 0; - - /* TODO: getline is GNU only, see kit_getline() in old polkit */ - while (getline (&line, &line_len, session->child_stdout_f) != -1) - { - if (strlen (line) > 0 && line[strlen (line) - 1] == '\n') - line[strlen (line) - 1] = '\0'; - - response = NULL; - response_prefix = NULL; - - id = "PAM_PROMPT_ECHO_OFF "; - if (g_str_has_prefix (line, id)) - { - id_len = strlen (id); - response_prefix = ""; - response = session->func_prompt_echo_off (session, - line + id_len, - session->user_data); - goto processed; - } - - id = "PAM_PROMPT_ECHO_ON "; - if (g_str_has_prefix (line, id)) - { - id_len = strlen (id); - response_prefix = ""; - response = session->func_prompt_echo_on (session, - line + id_len, - session->user_data); - goto processed; - } - - id = "PAM_ERROR_MSG "; - if (g_str_has_prefix (line, id)) - { - id_len = strlen (id); - session->func_error_message (session, - line + id_len, - session->user_data); - goto processed; - } - - id = "PAM_TEXT_INFO "; - if (g_str_has_prefix (line, id)) - { - id_len = strlen (id); - session->func_text_info (session, - line + id_len, - session->user_data); - goto processed; - } - - processed: - if (response != NULL && response_prefix != NULL) - { - char *buf; - gboolean add_newline; - - /* add a newline if there isn't one already... */ - add_newline = FALSE; - if (response[strlen (response) - 1] != '\n') - { - add_newline = TRUE; - } - buf = g_strdup_printf ("%s%s%c", - response_prefix, - response, - add_newline ? '\n' : '\0'); - write (session->child_stdin, buf, strlen (buf)); - g_free (buf); - g_free (response); - } - } - - if (line != NULL) - free (line); - - return FALSE; -} - -gboolean -polkit_agent_authentication_session_initiate_auth (PolkitAgentAuthenticationSession *session) -{ - uid_t uid; - GError *error; - gchar *helper_argv[4]; - GIOChannel *channel; - gboolean ret; - struct passwd *passwd; - - ret = FALSE; - - /* TODO: also support authorization for other kinds of identities */ - if (!POLKIT_IS_UNIX_USER (session->identity)) - { - g_warning ("Unsupported identity type"); - goto error; - } - - uid = polkit_unix_user_get_uid (POLKIT_UNIX_USER (session->identity)); - - passwd = getpwuid (uid); - if (passwd == NULL) - { - g_warning ("No user with uid %d", uid); - goto error; - } - - helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-agent-helper-1"; - helper_argv[1] = passwd->pw_name; - helper_argv[2] = session->cookie; - helper_argv[3] = NULL; - - session->child_stdin = -1; - 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, - &session->child_stdin, - &session->child_stdout, - NULL, - &error)) - { - g_warning ("Cannot spawn helper: %s\n", error->message); - g_error_free (error); - goto error; - } - - session->child_watch_id = g_child_watch_add (session->child_pid, child_watch_func, session); - - channel = g_io_channel_unix_new (session->child_stdout); - session->io_watch_id = g_io_add_watch (channel, G_IO_IN, io_watch_have_data, session); - g_io_channel_unref (channel); - - /* so we can use getline... */ - session->child_stdout_f = fdopen (session->child_stdout, "r"); - - session->success = FALSE; - - session->helper_is_running = TRUE; - - ret = TRUE; - -error: - - return ret; -} - - -void -polkit_agent_authentication_session_cancel (PolkitAgentAuthenticationSession *session) -{ - GPid pid; - - g_return_if_fail (session->helper_is_running); - - pid = session->child_pid; - session->child_pid = 0; - if (pid > 0) - { - int status; - kill (pid, SIGTERM); - waitpid (pid, &status, 0); - session->helper_is_running = FALSE; - } - session->func_done (session, FALSE, FALSE, session->user_data); -} diff --git a/src/polkitagent/polkitagentauthenticationsession.h b/src/polkitagent/polkitagentauthenticationsession.h deleted file mode 100644 index b1239fe..0000000 --- a/src/polkitagent/polkitagentauthenticationsession.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: David Zeuthen - */ - -#ifndef __POLKIT_AGENT_AUTHENTICATION_SESSION_H -#define __POLKIT_AGENT_AUTHENTICATION_SESSION_H - -#include -#include - -G_BEGIN_DECLS - -#define POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION (polkit_agent_authentication_session_get_type()) -#define POLKIT_AGENT_AUTHENTICATION_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION, PolkitAgentAuthenticationSession)) -#define POLKIT_AGENT_AUTHENTICATION_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION, PolkitAgentAuthenticationSessionClass)) -#define POLKIT_AGENT_AUTHENTICATION_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION, PolkitAgentAuthenticationSessionClass)) -#define POLKIT_AGENT_IS_AUTHENTICATION_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION)) -#define POLKIT_AGENT_IS_AUTHENTICATION_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_AGENT_TYPE_AUTHENTICATION_SESSION)) - -/** - * PolkitAgentAuthenticationSessionConversationPromptEchoOff: - * @session: A #PolkitAgentAuthenticationSession. - * @prompt: prompt passed by the authentication layer; do not free this string - * @user_data: user data pointer as passed into polkit_agent_authorization_session_set_functions() - * - * Type for callback function that is invoked when the authentication - * layer needs to ask the user a secret and the UI should NOT echo what - * the user types on the screen. - * - * Returns: the answer obtained from the user; must be allocated with - * malloc(3) and will be freed by the #PolkitAgentAuthenticationSession class. - **/ -typedef char* (*PolkitAgentAuthenticationSessionConversationPromptEchoOff) (PolkitAgentAuthenticationSession *session, - const gchar *prompt, - gpointer user_data); - -/** - * PolkitAgentAuthenticationSessionConversationPromptEchoOn: - * @session: A #PolkitAgentAuthenticationSession. - * @prompt: prompt passed by the authentication layer; do not free this string - * @user_data: user data pointer as passed into polkit_agent_authorization_session_set_functions() - * - * Type for callback function that is invoked when the authentication - * layer needs to ask the user a secret and the UI should echo what - * the user types on the screen. - * - * Returns: the answer obtained from the user; must be allocated with - * malloc(3) and will be freed by the #PolkitAgentAuthenticationSession class. - **/ -typedef char* (*PolkitAgentAuthenticationSessionConversationPromptEchoOn) (PolkitAgentAuthenticationSession *session, - const gchar *prompt, - gpointer user_data); - -/** - * PolkitAgentAuthenticationSessionConversationErrorMessage: - * @session: A #PolkitAgentAuthenticationSession. - * @error_message: error message passed by the authentication layer; do not free this string - * @user_data: user data pointer as passed into polkit_agent_authorization_session_set_functions() - * - * Type for callback function that is invoked when the authentication - * layer produces an error message that should be displayed in the UI. - **/ -typedef void (*PolkitAgentAuthenticationSessionConversationErrorMessage) (PolkitAgentAuthenticationSession *session, - const gchar *error_message, - gpointer user_data); - -/** - * PolkitAgentAuthenticationSessionConversationTextInfo: - * @session: A #PolkitAgentAuthenticationSession. - * @text_info: information passed by the authentication layer; do not free this string - * @user_data: user data pointer as passed into polkit_agent_authorization_session_set_functions() - * - * Type for callback function that is invoked when the authentication - * layer produces an informational message that should be displayed in - * the UI. - **/ -typedef void (*PolkitAgentAuthenticationSessionConversationTextInfo) (PolkitAgentAuthenticationSession *session, - const gchar *text_info, - gpointer user_data); - -/** - * PolkitAgentAuthenticationSessionDone: - * @session: A #PolkitAgentAuthenticationSession. - * @gained_authorization: whether the authorization was obtained - * @invalid_data: whether the input data was bogus (not including bad passwords) - * @user_data: user data pointer as passed into polkit_agent_authorization_session_set_functions() - * - * This function is called when the granting process ends; either if - * successful or if it was canceled using e.g. polkit_agent_authorization_session_cancel_auth(). - **/ -typedef void (*PolkitAgentAuthenticationSessionDone) (PolkitAgentAuthenticationSession *session, - gboolean gained_authorization, - gboolean invalid_data, - gpointer user_data); - - -#if 0 -typedef struct _PolkitAgentAuthenticationSession PolkitAgentAuthenticationSession; -#endif -typedef struct _PolkitAgentAuthenticationSessionClass PolkitAgentAuthenticationSessionClass; - -GType polkit_agent_authentication_session_get_type (void) G_GNUC_CONST; -PolkitAgentAuthenticationSession *polkit_agent_authentication_session_new (PolkitIdentity *identity, - const gchar *cookie); - -/* TODO: would be much nicer to use signals here */ -void polkit_agent_authentication_session_set_functions - (PolkitAgentAuthenticationSession *session, - PolkitAgentAuthenticationSessionConversationPromptEchoOff func_prompt_echo_off, - PolkitAgentAuthenticationSessionConversationPromptEchoOn func_prompt_echo_on, - PolkitAgentAuthenticationSessionConversationErrorMessage func_error_message, - PolkitAgentAuthenticationSessionConversationTextInfo func_text_info, - PolkitAgentAuthenticationSessionDone func_done, - void *user_data); - -gboolean polkit_agent_authentication_session_initiate_auth (PolkitAgentAuthenticationSession *session); - -void polkit_agent_authentication_session_cancel (PolkitAgentAuthenticationSession *session); - -G_END_DECLS - -#endif /* __POLKIT_AGENT_AUTHENTICATION_SESSION_H */ diff --git a/src/polkitagent/polkitagenthelper.c b/src/polkitagent/polkitagenthelper.c index d5844e5..b5181e5 100644 --- a/src/polkitagent/polkitagenthelper.c +++ b/src/polkitagent/polkitagenthelper.c @@ -40,7 +40,7 @@ * sensitive information. */ #undef PAH_DEBUG -//#define PAH_DEBUG +#define PAH_DEBUG static gboolean send_dbus_message (const char *cookie, const char *user); diff --git a/src/polkitagent/polkitagentlistener.c b/src/polkitagent/polkitagentlistener.c new file mode 100644 index 0000000..05042aa --- /dev/null +++ b/src/polkitagent/polkitagentlistener.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include +#include "_polkitagentbindings.h" + +#include "polkitagentlistener.h" + +/** + * SECTION:polkitagentlistener + * @title: PolkitAgentListener + * @short_description: Authentication Agent Listener + * + * The #PolkitAgentListener is an abstract base class used for implementing authentication agents. + */ + +/* private class for exporting an interface D-Bus */ + +#define TYPE_SERVER (server_get_type ()) +#define SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_SERVER, Server)) +#define SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_AGENT_TYPE_LISTENER, ServerClass)) +#define SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_SERVER, ServerClass)) +#define IS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_SERVER)) +#define IS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TYPE_SERVER)) + +typedef struct _Server Server; +typedef struct _ServerClass ServerClass; + +struct _Server +{ + GObject parent_instance; + + EggDBusConnection *system_bus; + + EggDBusObjectProxy *authority_proxy; + + PolkitAuthority *authority; + + gboolean is_registered; + + PolkitAgentListener *listener; + + gchar *session_id; + gchar *object_path; + + GHashTable *cookie_to_pending_auth; + +}; + +struct _ServerClass +{ + GObjectClass parent_class; + +}; + +static GType server_get_type (void) G_GNUC_CONST; + +static void authentication_agent_iface_init (_PolkitAgentAuthenticationAgentIface *agent_iface); + +G_DEFINE_TYPE_WITH_CODE (Server, server, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (_POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, + authentication_agent_iface_init) + ); + +static gboolean +server_register (Server *server, + GError **error) +{ + GError *local_error; + gboolean ret; + + ret = FALSE; + + local_error = NULL; + /* TODO: also pass server->session_id */ + if (!polkit_authority_register_authentication_agent_sync (server->authority, + server->object_path, + NULL, + &local_error)) + { + g_warning ("Unable to register authentication agent: %s", local_error->message); + g_propagate_error (error, local_error); + } + else + { + server->is_registered = TRUE; + ret = TRUE; + } + + return ret; +} + +static void +name_owner_notify (EggDBusObjectProxy *object_proxy, + GParamSpec *pspec, + gpointer user_data) +{ + Server *server = SERVER (user_data); + gchar *owner; + + owner = egg_dbus_object_proxy_get_name_owner (server->authority_proxy); + + if (owner == NULL) + { + g_printerr ("PolicyKit daemon disconnected from the bus.\n"); + + if (server->is_registered) + g_printerr ("We are no longer a registered authentication agent.\n"); + + server->is_registered = FALSE; + } + else + { + /* only register if there is a name owner */ + if (!server->is_registered) + { + GError *error; + + g_printerr ("PolicyKit daemon reconnected to bus.\n"); + g_printerr ("Attempting to re-register as an authentication agent.\n"); + + error = NULL; + if (server_register (server, &error)) + { + g_printerr ("We are now a registered authentication agent.\n"); + } + else + { + g_printerr ("Failed to register as an authentication agent: %s\n", error->message); + g_error_free (error); + } + } + } + + g_free (owner); +} + +static void +server_init (Server *server) +{ + server->cookie_to_pending_auth = g_hash_table_new (g_str_hash, g_str_equal); + + server->system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM); + + server->authority = polkit_authority_get (); + + /* the only use of this proxy is to re-register with the polkit daemon + * if it jumps off the bus and comes back (which is useful for debugging) + */ + server->authority_proxy = egg_dbus_connection_get_object_proxy (server->system_bus, + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority"); + + g_signal_connect (server->authority_proxy, + "notify::name-owner", + G_CALLBACK (name_owner_notify), + server); +} + +static void +server_finalize (GObject *object) +{ + Server *server = SERVER (object); + + if (server->is_registered) + { + GError *error; + + error = NULL; + if (!polkit_authority_unregister_authentication_agent_sync (server->authority, + server->object_path, + NULL, + &error)) + { + g_warning ("Error unregistering authentication agent: %s", error->message); + g_error_free (error); + } + } + + g_free (server->session_id); + g_free (server->object_path); + + g_object_unref (server->authority); + + g_object_unref (server->authority_proxy); + + g_object_unref (server->system_bus); + + g_hash_table_unref (server->cookie_to_pending_auth); + + if (G_OBJECT_CLASS (server_parent_class)->finalize != NULL) + G_OBJECT_CLASS (server_parent_class)->finalize (object); +} + +static void +server_class_init (ServerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = server_finalize; +} + +static void +listener_died (gpointer user_data, + GObject *where_the_object_was) +{ + Server *server = SERVER (user_data); + + g_object_unref (server); +} + +void +polkit_agent_export_listener (PolkitAgentListener *listener, + const gchar *session_id, + const gchar *object_path) +{ + Server *server; + GError *error; + + server = SERVER (g_object_new (TYPE_SERVER, NULL)); + server->session_id = g_strdup (session_id); + server->object_path = g_strdup (object_path); + server->listener = listener; + + /* take a weak ref and kill server when listener dies */ + g_object_weak_ref (G_OBJECT (server->listener), listener_died, server); + + egg_dbus_connection_register_interface (server->system_bus, + server->object_path, + _POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, + G_OBJECT (server), + G_TYPE_INVALID); + + error = NULL; + if (!server_register (server, &error)) + { + g_printerr ("Failed to register as an authentication agent: %s\n", error->message); + g_printerr ("Will attempt to register when the PolicyKit daemon is back up\n"); + g_error_free (error); + } +} + +typedef struct +{ + Server *server; + gchar *cookie; + EggDBusMethodInvocation *method_invocation; + GCancellable *cancellable; +} AuthData; + +static AuthData * +auth_data_new (Server *server, + const gchar *cookie, + EggDBusMethodInvocation *method_invocation, + GCancellable *cancellable) +{ + AuthData *data; + + data = g_new0 (AuthData, 1); + data->server = g_object_ref (server); + data->cookie = g_strdup (cookie); + data->method_invocation = g_object_ref (method_invocation); + data->cancellable = g_object_ref (cancellable); + + return data; +} + +static void +auth_data_free (AuthData *data) +{ + g_object_unref (data->server); + g_free (data->cookie); + g_object_unref (data->method_invocation); + g_object_unref (data->cancellable); + g_free (data); +} + +static void +auth_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + AuthData *data = user_data; + GError *error; + + error = NULL; + if (!polkit_agent_listener_initiate_authentication_finish (POLKIT_AGENT_LISTENER (source_object), + res, + &error)) + { + egg_dbus_method_invocation_return_gerror (data->method_invocation, error); + g_error_free (error); + } + else + { + _polkit_agent_authentication_agent_handle_begin_authentication_finish (data->method_invocation); + } + + g_hash_table_remove (data->server->cookie_to_pending_auth, data->cookie); + + auth_data_free (data); +} + +static void +handle_begin_authentication (_PolkitAgentAuthenticationAgent *instance, + const gchar *action_id, + const gchar *cookie, + EggDBusArraySeq *identities, + EggDBusMethodInvocation *method_invocation) +{ + Server *server = SERVER (instance); + AuthData *data; + GList *list; + guint n; + GCancellable *cancellable; + + list = NULL; + for (n = 0; n < identities->size; n++) + { + _PolkitIdentity *real_identity = _POLKIT_IDENTITY (identities->data.v_ptr[n]); + + list = g_list_prepend (list, polkit_identity_new_for_real (real_identity)); + } + + list = g_list_reverse (list); + + cancellable = g_cancellable_new (); + data = auth_data_new (server, + cookie, + method_invocation, + cancellable); + g_object_unref (cancellable); + + g_hash_table_insert (server->cookie_to_pending_auth, (gpointer) cookie, data); + + polkit_agent_listener_initiate_authentication (server->listener, + action_id, + cookie, + list, + data->cancellable, + auth_cb, + data); + + g_list_free (list); +} + +static void +handle_cancel_authentication (_PolkitAgentAuthenticationAgent *instance, + const gchar *cookie, + EggDBusMethodInvocation *method_invocation) +{ + Server *server = SERVER (instance); + AuthData *data; + + data = g_hash_table_lookup (server->cookie_to_pending_auth, cookie); + if (data == NULL) + { + egg_dbus_method_invocation_return_error (method_invocation, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "No pending authentication request for cookie '%s'", + cookie); + } + else + { + g_cancellable_cancel (data->cancellable); + _polkit_agent_authentication_agent_handle_cancel_authentication_finish (method_invocation); + } +} + +static void +authentication_agent_iface_init (_PolkitAgentAuthenticationAgentIface *agent_iface) +{ + agent_iface->handle_begin_authentication = handle_begin_authentication; + agent_iface->handle_cancel_authentication = handle_cancel_authentication; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +G_DEFINE_ABSTRACT_TYPE (PolkitAgentListener, polkit_agent_listener, G_TYPE_OBJECT); + +static void +polkit_agent_listener_init (PolkitAgentListener *listener) +{ +} + +static void +polkit_agent_listener_class_init (PolkitAgentListenerClass *klass) +{ +} + +void +polkit_agent_listener_initiate_authentication (PolkitAgentListener *listener, + const gchar *action_id, + const gchar *cookie, + GList *identities, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + POLKIT_AGENT_LISTENER_GET_CLASS (listener)->initiate_authentication (listener, + action_id, + cookie, + identities, + cancellable, + callback, + user_data); +} + +gboolean +polkit_agent_listener_initiate_authentication_finish (PolkitAgentListener *listener, + GAsyncResult *res, + GError **error) +{ + return POLKIT_AGENT_LISTENER_GET_CLASS (listener)->initiate_authentication_finish (listener, + res, + error); +} + diff --git a/src/polkitagent/polkitagentlistener.h b/src/polkitagent/polkitagentlistener.h new file mode 100644 index 0000000..d71acf7 --- /dev/null +++ b/src/polkitagent/polkitagentlistener.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#ifndef __POLKIT_AGENT_LISTENER_H +#define __POLKIT_AGENT_LISTENER_H + +#include +#include + +G_BEGIN_DECLS + +#define POLKIT_AGENT_TYPE_LISTENER (polkit_agent_listener_get_type ()) +#define POLKIT_AGENT_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_AGENT_TYPE_LISTENER, PolkitAgentListener)) +#define POLKIT_AGENT_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_AGENT_TYPE_LISTENER, PolkitAgentListenerClass)) +#define POLKIT_AGENT_LISTENER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_AGENT_TYPE_LISTENER,PolkitAgentListenerClass)) +#define POLKIT_AGENT_IS_LISTENER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_AGENT_TYPE_LISTENER)) +#define POLKIT_AGENT_IS_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_AGENT_TYPE_LISTENER)) + +#if 0 +typedef struct _PolkitAgentListener PolkitAgentListener; +#endif +typedef struct _PolkitAgentListenerClass PolkitAgentListenerClass; + +struct _PolkitAgentListener +{ + GObject parent_instance; +}; + +struct _PolkitAgentListenerClass +{ + GObjectClass parent_class; + + /*< public >*/ + /* VFuncs */ + void (*initiate_authentication) (PolkitAgentListener *listener, + const gchar *action_id, + const gchar *cookie, + GList *identities, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + + gboolean (*initiate_authentication_finish) (PolkitAgentListener *listener, + GAsyncResult *res, + GError **error); + + /*< private >*/ + /* Padding for future expansion */ + void (*_polkit_reserved0) (void); + void (*_polkit_reserved1) (void); + void (*_polkit_reserved2) (void); + void (*_polkit_reserved3) (void); + void (*_polkit_reserved4) (void); + void (*_polkit_reserved5) (void); + void (*_polkit_reserved6) (void); + void (*_polkit_reserved7) (void); +}; + +GType polkit_agent_listener_get_type (void) G_GNUC_CONST; +void polkit_agent_listener_initiate_authentication (PolkitAgentListener *listener, + const gchar *action_id, + const gchar *cookie, + GList *identities, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean polkit_agent_listener_initiate_authentication_finish (PolkitAgentListener *listener, + GAsyncResult *res, + GError **error); + +void polkit_agent_export_listener (PolkitAgentListener *listener, + const gchar *session_id, + const gchar *object_path); + +G_END_DECLS + +#endif /* __POLKIT_AGENT_LISTENER_H */ diff --git a/src/polkitagent/polkitagentsession.c b/src/polkitagent/polkitagentsession.c new file mode 100644 index 0000000..0510227 --- /dev/null +++ b/src/polkitagent/polkitagentsession.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +/** + * SECTION:polkitagentsession + * @title: PolkitAgentSession + * @short_description: Authentcation Sessions + * + * The #PolkitAgentSession class is used for interacting with an authentication system. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "polkitagentsession.h" + +struct _PolkitAgentSession +{ + GObject parent_instance; + + gchar *cookie; + PolkitIdentity *identity; + + int child_stdin; + int child_stdout; + GPid child_pid; + + int child_watch_id; + int child_stdout_watch_id; + GIOChannel *child_stdout_channel; + + gboolean success; + gboolean helper_is_running; +}; + +struct _PolkitAgentSessionClass +{ + GObjectClass parent_class; + +}; + +enum +{ + REQUEST_ECHO_ON_SIGNAL, + REQUEST_ECHO_OFF_SIGNAL, + SHOW_INFO_SIGNAL, + SHOW_ERROR_SIGNAL, + COMPLETED_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = {0}; + +G_DEFINE_TYPE (PolkitAgentSession, polkit_agent_session, G_TYPE_OBJECT); + +static void +polkit_agent_session_init (PolkitAgentSession *session) +{ +} + +static void kill_helper (PolkitAgentSession *session); + +static void +polkit_agent_session_finalize (GObject *object) +{ + PolkitAgentSession *session; + + session = POLKIT_AGENT_SESSION (object); + + /* this releases resources related to the helper */ + kill_helper (session); + + g_free (session->cookie); + if (session->identity != NULL) + g_object_unref (session->identity); + + if (G_OBJECT_CLASS (polkit_agent_session_parent_class)->finalize != NULL) + G_OBJECT_CLASS (polkit_agent_session_parent_class)->finalize (object); +} + +static void +polkit_agent_session_class_init (PolkitAgentSessionClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = polkit_agent_session_finalize; + + /** + * PolkitAgentSession::request-echo-on: + * @session: A #PolkitAgentSession. + * @request: The request to show the user, e.g. "name: " + * + * Emitted when the user is requested to answer a question. User input + * should be echoed on the screen in the clear. + * + * When the response has been collected from the user, call + * polkit_agent_session_response(). + */ + signals[REQUEST_ECHO_ON_SIGNAL] = g_signal_new ("request-echo-on", + POLKIT_AGENT_TYPE_SESSION, + G_SIGNAL_RUN_LAST, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + /** + * PolkitAgentSession::request-echo-off: + * @session: A #PolkitAgentSession. + * @request: The request to show the user, e.g. "password: " + * + * Emitted when the user is requested to answer a question. User input + * MUST NOT be echoed on the screen in the clear. + * + * When the response has been collected from the user, call + * polkit_agent_session_response(). + */ + signals[REQUEST_ECHO_OFF_SIGNAL] = g_signal_new ("request-echo-off", + POLKIT_AGENT_TYPE_SESSION, + G_SIGNAL_RUN_LAST, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + + /** + * PolkitAgentSession::show-info: + * @session: A #PolkitAgentSession. + * @text: A string to display to the user. + * + * Emitted when there is information to be displayed to the user. + */ + signals[SHOW_INFO_SIGNAL] = g_signal_new ("show-info", + POLKIT_AGENT_TYPE_SESSION, + G_SIGNAL_RUN_LAST, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + /** + * PolkitAgentSession::show-error: + * @session: A #PolkitAgentSession. + * @text: An error string to display to the user. + * + * Emitted when there is information related to an error condition to be displayed to the user. + */ + signals[SHOW_ERROR_SIGNAL] = g_signal_new ("show-error", + POLKIT_AGENT_TYPE_SESSION, + G_SIGNAL_RUN_LAST, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + /** + * PolkitAgentSession::completed: + * @session: A #PolkitAgentSession. + * @authentication_result: %TRUE only if the user sucessfully authenticated. + * + * Emitted when the authentication session has been completed or + * cancelled. The user should unref @session. + */ + signals[COMPLETED_SIGNAL] = g_signal_new ("completed", + POLKIT_AGENT_TYPE_SESSION, + G_SIGNAL_RUN_LAST, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); +} + +PolkitAgentSession * +polkit_agent_session_new (PolkitIdentity *identity, + const gchar *cookie) +{ + PolkitAgentSession *session; + + session = POLKIT_AGENT_SESSION (g_object_new (POLKIT_AGENT_TYPE_SESSION, NULL)); + + session->identity = g_object_ref (identity); + session->cookie = g_strdup (cookie); + + return session; +} + +static void +kill_helper (PolkitAgentSession *session) +{ + if (!session->helper_is_running) + goto out; + + if (session->child_pid > 0) + { + gint status; + kill (session->child_pid, SIGTERM); + waitpid (session->child_pid, &status, 0); + session->child_pid = 0; + } + + if (session->child_watch_id > 0) + { + g_source_remove (session->child_watch_id); + session->child_watch_id = 0; + } + + if (session->child_stdout_watch_id > 0) + { + g_source_remove (session->child_stdout_watch_id); + session->child_stdout_watch_id = 0; + } + + if (session->child_stdout_channel != NULL) + { + g_io_channel_unref (session->child_stdout_channel); + session->child_stdout_channel = NULL; + } + + session->helper_is_running = FALSE; + + out: + ; +} + +static void +complete_session (PolkitAgentSession *session, + gboolean result) +{ + kill_helper (session); + g_signal_emit_by_name (session, "completed", result); +} + +static void +child_watch_func (GPid pid, + gint status, + gpointer user_data) +{ + PolkitAgentSession *session = POLKIT_AGENT_SESSION (user_data); + + /* kill all the watches we have set up, except for the child since it has exited already */ + session->child_pid = 0; + kill_helper (session); +} + +static gboolean +io_watch_have_data (GIOChannel *channel, + GIOCondition condition, + gpointer user_data) +{ + PolkitAgentSession *session = POLKIT_AGENT_SESSION (user_data); + gchar *line; + GError *error; + + error = NULL; + line = NULL; + + if (!session->helper_is_running) + { + g_warning ("in io_watch_have_data() but helper is not supposed to be running"); + + complete_session (session, FALSE); + goto out; + } + + g_io_channel_read_line (channel, + &line, + NULL, + NULL, + &error); + if (error != NULL) + { + g_warning ("Error reading line from helper: %s", error->message); + g_error_free (error); + + complete_session (session, FALSE); + goto out; + } + + /* remove terminator */ + if (strlen (line) > 0 && line[strlen (line) - 1] == '\n') + line[strlen (line) - 1] = '\0'; + + if (g_str_has_prefix (line, "PAM_PROMPT_ECHO_OFF ")) + { + g_signal_emit_by_name (session, "request-echo-off", line + sizeof "PAM_PROMPT_ECHO_OFF " - 1); + } + else if (g_str_has_prefix (line, "PAM_PROMPT_ECHO_ON ")) + { + g_signal_emit_by_name (session, "request-echo-on", line + sizeof "PAM_PROMPT_ECHO_ON " - 1); + } + else if (g_str_has_prefix (line, "PAM_ERROR_MSG ")) + { + g_signal_emit_by_name (session, "show-error", line + sizeof "PAM_ERROR_MSG " - 1); + } + else if (g_str_has_prefix (line, "PAM_TEXT_INFO ")) + { + g_signal_emit_by_name (session, "show-info", line + sizeof "PAM_TEXT_INFO " - 1); + } + else if (g_str_has_prefix (line, "PAM_TEXT_INFO ")) + { + g_signal_emit_by_name (session, "show-info", line + sizeof "PAM_TEXT_INFO " - 1); + } + else if (g_str_has_prefix (line, "SUCCESS")) + { + complete_session (session, TRUE); + } + else if (g_str_has_prefix (line, "FAILURE")) + { + complete_session (session, FALSE); + } + else + { + g_warning ("Unknown line '%s' from helper", line); + complete_session (session, FALSE); + goto out; + } + + out: + g_free (line); + + /* keep the IOChannel around */ + return TRUE; +} + +void +polkit_agent_session_response (PolkitAgentSession *session, + const gchar *response) +{ + gboolean add_newline; + size_t response_len; + const char newline[] = "\n"; + + g_return_if_fail (response != NULL); + + response_len = strlen (response); + + add_newline = (response[response_len] != '\n'); + + write (session->child_stdin, response, response_len); + if (add_newline) + write (session->child_stdin, newline, 1); +} + +void +polkit_agent_session_initiate (PolkitAgentSession *session) +{ + uid_t uid; + GError *error; + gchar *helper_argv[4]; + gboolean ret; + struct passwd *passwd; + + ret = FALSE; + + /* TODO: also support authorization for other kinds of identities */ + if (!POLKIT_IS_UNIX_USER (session->identity)) + { + g_warning ("Unsupported identity type"); + goto error; + } + + uid = polkit_unix_user_get_uid (POLKIT_UNIX_USER (session->identity)); + + passwd = getpwuid (uid); + if (passwd == NULL) + { + g_warning ("No user with uid %d", uid); + goto error; + } + + helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-agent-helper-1"; + helper_argv[1] = passwd->pw_name; + helper_argv[2] = session->cookie; + helper_argv[3] = NULL; + + session->child_stdin = -1; + 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, + &session->child_stdin, + &session->child_stdout, + NULL, + &error)) + { + g_warning ("Cannot spawn helper: %s\n", error->message); + g_error_free (error); + goto error; + } + + session->child_watch_id = g_child_watch_add (session->child_pid, child_watch_func, session); + session->child_stdout_channel = g_io_channel_unix_new (session->child_stdout); + session->child_stdout_watch_id = g_io_add_watch (session->child_stdout_channel, G_IO_IN, io_watch_have_data, session); + + session->success = FALSE; + + session->helper_is_running = TRUE; + + return; + +error: + complete_session (session, FALSE); +} + + +void +polkit_agent_session_cancel (PolkitAgentSession *session) +{ + complete_session (session, FALSE); +} diff --git a/src/polkitagent/polkitagentsession.h b/src/polkitagent/polkitagentsession.h new file mode 100644 index 0000000..a3863bf --- /dev/null +++ b/src/polkitagent/polkitagentsession.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#ifndef __POLKIT_AGENT_SESSION_H +#define __POLKIT_AGENT_SESSION_H + +#include +#include + +G_BEGIN_DECLS + +#define POLKIT_AGENT_TYPE_SESSION (polkit_agent_session_get_type()) +#define POLKIT_AGENT_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_AGENT_TYPE_SESSION, PolkitAgentSession)) +#define POLKIT_AGENT_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), POLKIT_AGENT_TYPE_SESSION, PolkitAgentSessionClass)) +#define POLKIT_AGENT_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_AGENT_TYPE_SESSION, PolkitAgentSessionClass)) +#define POLKIT_AGENT_IS_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_AGENT_TYPE_SESSION)) +#define POLKIT_AGENT_IS_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_AGENT_TYPE_SESSION)) + + +#if 0 +typedef struct _PolkitAgentSession PolkitAgentSession; +#endif +typedef struct _PolkitAgentSessionClass PolkitAgentSessionClass; + +GType polkit_agent_session_get_type (void) G_GNUC_CONST; +PolkitAgentSession *polkit_agent_session_new (PolkitIdentity *identity, + const gchar *cookie); +void polkit_agent_session_initiate (PolkitAgentSession *session); +void polkit_agent_session_response (PolkitAgentSession *session, + const gchar *response); +void polkit_agent_session_cancel (PolkitAgentSession *session); + +G_END_DECLS + +#endif /* __POLKIT_AGENT_SESSION_H */ diff --git a/src/polkitagent/polkitagenttypes.h b/src/polkitagent/polkitagenttypes.h index c82ed1a..2405ebc 100644 --- a/src/polkitagent/polkitagenttypes.h +++ b/src/polkitagent/polkitagenttypes.h @@ -26,12 +26,11 @@ G_BEGIN_DECLS -struct _PolkitAgentAuthenticationSession; -typedef struct _PolkitAgentAuthenticationSession PolkitAgentAuthenticationSession; - -struct _PolkitAgentAuthenticationAgent; -typedef struct _PolkitAgentAuthenticationAgent PolkitAgentAuthenticationAgent; +struct _PolkitAgentListener; +typedef struct _PolkitAgentListener PolkitAgentListener; +struct _PolkitAgentSession; +typedef struct _PolkitAgentSession PolkitAgentSession; G_END_DECLS diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c index 7c0c632..77b6315 100644 --- a/src/polkitbackend/polkitbackendlocalauthority.c +++ b/src/polkitbackend/polkitbackendlocalauthority.c @@ -1286,7 +1286,13 @@ authentication_agent_initiate_challenge (AuthenticationAgent *agent, cookie = authentication_agent_new_cookie (agent); /* TODO: add uid 0 OR users in wheel group depending on value of @implicit_authorization */ - identities = g_list_prepend (NULL, g_object_ref (user_of_subject)); + identities = NULL; + identities = g_list_prepend (identities, g_object_ref (user_of_subject)); + //#if 0 + identities = g_list_prepend (identities, polkit_unix_user_new (501)); + identities = g_list_prepend (identities, polkit_unix_user_new (502)); + identities = g_list_prepend (identities, polkit_unix_user_new (0)); + //#endif session = authentication_session_new (agent, cookie, -- 2.7.4