Commit 4a9e4f72 authored by David Zeuthen's avatar David Zeuthen

Make polkitd accept --replace and gracefully handle SIGINT

E.g. actually clean up everything before exiting. This makes it much
easier to chase memory leaks.
Signed-off-by: default avatarDavid Zeuthen <davidz@redhat.com>
parent 2d0ef52d
......@@ -293,7 +293,8 @@ polkit_backend_authority_add_lockdown_for_action_finish
polkit_backend_authority_remove_lockdown_for_action
polkit_backend_authority_remove_lockdown_for_action_finish
polkit_backend_authority_get
polkit_backend_register_authority
polkit_backend_authority_register
polkit_backend_authority_unregister
<SUBSECTION Standard>
POLKIT_BACKEND_AUTHORITY
POLKIT_BACKEND_IS_AUTHORITY
......
......@@ -109,7 +109,7 @@ polkit_authorization_result_new (gboolean is_authorized,
authorization_result = POLKIT_AUTHORIZATION_RESULT (g_object_new (POLKIT_TYPE_AUTHORIZATION_RESULT, NULL));
authorization_result->is_authorized = is_authorized;
authorization_result->is_challenge = is_challenge;
authorization_result->details = g_object_ref (details);
authorization_result->details = details != NULL ? g_object_ref (details) : NULL;
return authorization_result;
}
......
......@@ -657,11 +657,10 @@ typedef struct
PolkitBackendAuthority *authority;
GDBusConnection *system_bus;
GDBusConnection *connection;
gulong authority_changed_id;
gchar *well_known_name;
gchar *object_path;
GHashTable *cancellation_id_to_check_auth_data;
......@@ -670,21 +669,18 @@ typedef struct
static void
server_free (Server *server)
{
g_free (server->well_known_name);
g_free (server->object_path);
/* TODO: release well_known_name if not NULL */
//g_signal_handler_disconnect (server->bus, server->name_owner_changed_id);
if (server->authority_registration_id > 0)
g_dbus_connection_unregister_object (server->system_bus, server->authority_registration_id);
g_dbus_connection_unregister_object (server->connection, server->authority_registration_id);
if (server->name_owner_changed_signal_id > 0)
g_dbus_connection_signal_unsubscribe (server->system_bus, server->name_owner_changed_signal_id);
g_dbus_connection_signal_unsubscribe (server->connection, server->name_owner_changed_signal_id);
if (server->system_bus != NULL)
g_object_unref (server->system_bus);
if (server->connection != NULL)
g_object_unref (server->connection);
if (server->introspection_info != NULL)
g_dbus_node_info_unref (server->introspection_info);
......@@ -695,6 +691,8 @@ server_free (Server *server)
if (server->cancellation_id_to_check_auth_data != NULL)
g_hash_table_unref (server->cancellation_id_to_check_auth_data);
g_object_unref (server->authority);
g_free (server);
}
......@@ -706,7 +704,7 @@ on_authority_changed (PolkitBackendAuthority *authority,
GError *error;
error = NULL;
if (!g_dbus_connection_emit_signal (server->system_bus,
if (!g_dbus_connection_emit_signal (server->connection,
NULL, /* destination bus name */
server->object_path,
"org.freedesktop.PolicyKit1.Authority",
......@@ -719,14 +717,6 @@ on_authority_changed (PolkitBackendAuthority *authority,
}
}
static void
authority_died (gpointer user_data,
GObject *where_the_object_was)
{
Server *server = user_data;
server_free (server);
}
static const gchar *server_introspection_data =
"<node>"
" <interface name='org.freedesktop.PolicyKit1.Authority'>"
......@@ -1455,19 +1445,32 @@ static const GDBusInterfaceVTable server_vtable =
};
/**
* polkit_backend_register_authority:
* polkit_backend_authority_unregister:
* @registration_id: A #gpointer obtained from polkit_backend_authority_register().
*
* Unregisters a #PolkitBackendAuthority registered with polkit_backend_authority_register().
*/
void
polkit_backend_authority_unregister (gpointer registration_id)
{
Server *server = registration_id;
server_free (server);
}
/**
* polkit_backend_authority_register:
* @connection: The #GDBusConnection to register the authority on.
* @authority: A #PolkitBackendAuthority.
* @well_known_name: Well-known name to claim on the system bus or %NULL to not claim a well-known name.
* @object_path: Object path of the authority.
* @error: Return location for error.
*
* Registers @authority on the system message bus.
* Registers @authority on a #GDBusConnection.
*
* Returns: %TRUE if @authority was registered, %FALSE if @error is set.
**/
gboolean
polkit_backend_register_authority (PolkitBackendAuthority *authority,
const gchar *well_known_name,
* Returns: A #gpointer that can be used with polkit_backend_authority_unregister() or %NULL if @error is set.
*/
gpointer
polkit_backend_authority_register (PolkitBackendAuthority *authority,
GDBusConnection *connection,
const gchar *object_path,
GError **error)
{
......@@ -1477,18 +1480,14 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority,
server->cancellation_id_to_check_auth_data = g_hash_table_new (g_str_hash, g_str_equal);
server->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
if (server->system_bus == NULL)
goto error;
server->well_known_name = g_strdup (well_known_name);
server->connection = g_object_ref (connection);
server->object_path = g_strdup (object_path);
server->introspection_info = g_dbus_node_info_new_for_xml (server_introspection_data, error);
if (server->introspection_info == NULL)
goto error;
server->authority_registration_id = g_dbus_connection_register_object (server->system_bus,
server->authority_registration_id = g_dbus_connection_register_object (server->connection,
object_path,
g_dbus_node_info_lookup_interface (server->introspection_info, "org.freedesktop.PolicyKit1.Authority"),
&server_vtable,
......@@ -1500,46 +1499,8 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority,
goto error;
}
if (well_known_name != NULL)
{
GVariant *result;
guint32 request_name_result;
/* TODO: use g_bus_own_name() instead */
result = g_dbus_connection_call_sync (server->system_bus,
"org.freedesktop.DBus", /* name */
"/org/freedesktop/DBus", /* path */
"org.freedesktop.DBus", /* interface */
"RequestName",
g_variant_new ("(su)", well_known_name, 0),
G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, /* GCancellable */
error);
if (result == NULL)
{
g_prefix_error (error,
"Could not become primary name owner for `%s'. RequestName() failed with: ",
well_known_name);
goto error;
}
g_variant_get (result, "(u)", &request_name_result);
g_variant_unref (result);
if (request_name_result != 1)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Could not become primary name owner for `%s'. RequestName returned %d",
well_known_name,
request_name_result);
goto error;
}
}
server->name_owner_changed_signal_id =
g_dbus_connection_signal_subscribe (server->system_bus,
g_dbus_connection_signal_subscribe (server->connection,
"org.freedesktop.DBus", /* sender */
"org.freedesktop.DBus", /* interface */
"NameOwnerChanged", /* member */
......@@ -1550,21 +1511,18 @@ polkit_backend_register_authority (PolkitBackendAuthority *authority,
server,
NULL); /* GDestroyNotify */
server->authority = authority;
server->authority = g_object_ref (authority);
server->authority_changed_id = g_signal_connect (server->authority,
"changed",
G_CALLBACK (on_authority_changed),
server);
/* take a weak ref and kill server when listener dies */
g_object_weak_ref (G_OBJECT (server->authority), authority_died, server);
return TRUE;
return server;
error:
server_free (server);
return FALSE;
return NULL;
}
......
......@@ -329,11 +329,13 @@ gboolean polkit_backend_authority_remove_lockdown_for_action_finish (PolkitBacke
PolkitBackendAuthority *polkit_backend_authority_get (void);
gboolean polkit_backend_register_authority (PolkitBackendAuthority *authority,
const gchar *well_known_name,
gpointer polkit_backend_authority_register (PolkitBackendAuthority *authority,
GDBusConnection *connection,
const gchar *object_path,
GError **error);
void polkit_backend_authority_unregister (gpointer registration_id);
G_END_DECLS
#endif /* __POLKIT_BACKEND_AUTHORITY_H */
......@@ -17,7 +17,8 @@ INCLUDES = \
libexec_PROGRAMS = polkitd
polkitd_SOURCES = \
main.c \
main.c \
gposixsignal.h gposixsignal.c \
$(NULL)
polkitd_CFLAGS = \
......
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2010 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 <davidz@redhat.com>
*/
#include "config.h"
#include <unistd.h>
#include <sys/signalfd.h>
#include <signal.h>
#include "gposixsignal.h"
typedef struct
{
GSource source;
GPollFD pollfd;
gint signum;
} _GPosixSignalSource;
static gboolean
_g_posix_signal_source_prepare (GSource *_source,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
_g_posix_signal_source_check (GSource *_source)
{
_GPosixSignalSource *source = (_GPosixSignalSource *) _source;
return source->pollfd.revents != 0;
}
static gboolean
_g_posix_signal_source_dispatch (GSource *_source,
GSourceFunc callback,
gpointer user_data)
{
_GPosixSignalWatchFunc func = (_GPosixSignalWatchFunc) callback;
g_warn_if_fail (func != NULL);
return (*func) (user_data);
}
static void
_g_posix_signal_source_finalize (GSource *_source)
{
_GPosixSignalSource *source = (_GPosixSignalSource *) _source;
close (source->pollfd.fd);
}
static GSourceFuncs _g_posix_signal_source_funcs =
{
_g_posix_signal_source_prepare,
_g_posix_signal_source_check,
_g_posix_signal_source_dispatch,
_g_posix_signal_source_finalize
};
GSource *
_g_posix_signal_source_new (gint signum)
{
sigset_t sigset;
gint fd;
GSource *_source;
_GPosixSignalSource *source;
_source = NULL;
sigemptyset (&sigset);
sigaddset (&sigset, signum);
if (sigprocmask (SIG_BLOCK, &sigset, NULL) == -1)
g_assert_not_reached ();
fd = signalfd (-1, &sigset, SFD_NONBLOCK | SFD_CLOEXEC);
_source = g_source_new (&_g_posix_signal_source_funcs, sizeof (_GPosixSignalSource));
source = (_GPosixSignalSource *) _source;
source->pollfd.fd = fd;
source->pollfd.events = G_IO_IN;
g_source_add_poll (_source, &source->pollfd);
source->signum = signum;
return _source;
}
guint
_g_posix_signal_watch_add (gint signum,
gint priority,
_GPosixSignalWatchFunc function,
gpointer user_data,
GDestroyNotify notify)
{
GSource *source;
guint id;
g_return_val_if_fail (function != NULL, 0);
source = _g_posix_signal_source_new (signum);
if (priority != G_PRIORITY_DEFAULT_IDLE)
g_source_set_priority (source, priority);
g_source_set_callback (source, (GSourceFunc) function, user_data, notify);
id = g_source_attach (source, NULL);
g_source_unref (source);
return id;
}
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2010 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 <davidz@redhat.com>
*/
#ifndef ___G_POSIX_SIGNAL_H__
#define ___G_POSIX_SIGNAL_H__
#include <glib.h>
G_BEGIN_DECLS
typedef gboolean (*_GPosixSignalWatchFunc) (gpointer user_data);
GSource *_g_posix_signal_source_new (gint signum);
guint _g_posix_signal_watch_add (gint signum,
gint priority,
_GPosixSignalWatchFunc function,
gpointer user_data,
GDestroyNotify notify);
G_END_DECLS
#endif /* ___G_POSIX_SIGNAL_H__ */
/*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2008-2010 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
......@@ -19,49 +19,144 @@
* Author: David Zeuthen <davidz@redhat.com>
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "config.h"
#include <signal.h>
#include <polkit/polkit.h>
#include <polkitbackend/polkitbackend.h>
int
main (int argc, char **argv)
#include "gposixsignal.h"
/* ---------------------------------------------------------------------------------------------------- */
static PolkitBackendAuthority *authority = NULL;
static gpointer registration_id = NULL;
static GMainLoop *loop = NULL;
static gboolean opt_replace = FALSE;
static GOptionEntry opt_entries[] = {
{"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
{NULL }
};
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
int ret;
GError *error;
GMainLoop *loop;
PolkitBackendAuthority *authority;
ret = 1;
error = NULL;
authority = NULL;
g_type_init ();
g_print ("Connected to the system bus\n");
loop = g_main_loop_new (NULL, FALSE);
g_assert (authority == NULL);
g_assert (registration_id == NULL);
authority = polkit_backend_authority_get ();
g_print ("Using authority class %s\n", g_type_name (G_TYPE_FROM_INSTANCE (authority)));
if (!polkit_backend_register_authority (authority,
"org.freedesktop.PolicyKit1",
"/org/freedesktop/PolicyKit1/Authority",
&error))
error = NULL;
registration_id = polkit_backend_authority_register (authority,
connection,
"/org/freedesktop/PolicyKit1/Authority",
&error);
if (registration_id == NULL)
{
g_printerr ("Error registering authority: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop); /* exit */
}
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_print ("Lost the name org.freedesktop.PolicyKit1 - exiting\n");
g_main_loop_quit (loop);
}
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_print ("Acquired the name org.freedesktop.PolicyKit1\n");
}
static gboolean
on_sigint (gpointer user_data)
{
g_print ("Handling SIGINT\n");
g_main_loop_quit (loop);
return FALSE;
}
int
main (int argc,
char **argv)
{
GError *error;
GOptionContext *opt_context;
gint ret;
guint name_owner_id;
guint sigint_id;
ret = 1;
loop = NULL;
opt_context = NULL;
name_owner_id = 0;
sigint_id = 0;
registration_id = NULL;
g_type_init ();
opt_context = g_option_context_new ("polkit authority");
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
error = NULL;
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
{
g_printerr ("Error parsing options: %s", error->message);
g_error_free (error);
goto out;
}
loop = g_main_loop_new (NULL, FALSE);
sigint_id = _g_posix_signal_watch_add (SIGINT,
G_PRIORITY_DEFAULT,
on_sigint,
NULL,
NULL);
name_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
"org.freedesktop.PolicyKit1",
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
(opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
g_print ("Entering main event loop\n");
g_main_loop_run (loop);
ret = 0;
g_print ("Shutting down\n");
out:
if (sigint_id > 0)
g_source_remove (sigint_id);
if (name_owner_id != 0)
g_bus_unown_name (name_owner_id);
if (registration_id != NULL)
polkit_backend_authority_unregister (registration_id);
if (authority != NULL)
g_object_unref (authority);
if (loop != NULL)
g_main_loop_unref (loop);
if (opt_context != NULL)
g_option_context_free (opt_context);
g_print ("Exiting with code %d\n", ret);
return ret;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment