diff options
author | Eric Koegel <eric.koegel@gmail.com> | 2015-07-28 20:13:45 +0300 |
---|---|---|
committer | Eric Koegel <eric.koegel@gmail.com> | 2015-07-28 20:20:15 +0300 |
commit | f864e026e5ebf3a097f82e2e0d4d7b5c956d3a1f (patch) | |
tree | cb49fa217fdcc8e67137b39789ece57a2ff0b558 /src | |
parent | e5fb2178fb2ac866232e1db738d6357ec0041b35 (diff) | |
download | ConsoleKit2-f864e026e5ebf3a097f82e2e0d4d7b5c956d3a1f.tar.gz |
Add process grouping/tracking
On Linux, this adds an optional dependency on cgmanager to use
cgroups to manage and track processes. This is more reliable and
secure than the XDG_SESSION_COOKIE however it will fall back to
that.
https://github.com/ConsoleKit2/ConsoleKit2/issues/7
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/ck-manager.c | 40 | ||||
-rw-r--r-- | src/ck-process-group.c | 275 | ||||
-rw-r--r-- | src/ck-process-group.h | 67 | ||||
-rw-r--r-- | src/ck-session.h | 12 |
5 files changed, 379 insertions, 19 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 091ef27..7a7dd24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,7 @@ AM_CFLAGS = \ -U_FORTIFY_SOURCE \ $(CONSOLE_KIT_CFLAGS) \ $(POLKIT_CFLAGS) \ + $(CGMANAGER_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) \ -DPREFIX=\""$(prefix)"\" \ -DBINDIR=\""$(bindir)"\" \ @@ -157,6 +158,8 @@ console_kit_daemon_SOURCES = \ ck-inhibit.h \ ck-inhibit-manager.c \ ck-inhibit-manager.h \ + ck-process-group.h \ + ck-process-group.c \ $(BUILT_SOURCES) \ $(NULL) @@ -177,6 +180,7 @@ console_kit_daemon_LDADD = \ $(CONSOLE_KIT_LIBS) \ $(POLKIT_LIBS) \ $(RBAC_LIBS) \ + $(CGMANAGER_LIBS) \ libck.la \ libck-event-log.la \ $(NULL) diff --git a/src/ck-manager.c b/src/ck-manager.c index f7e0b05..a23e414 100644 --- a/src/ck-manager.c +++ b/src/ck-manager.c @@ -54,6 +54,7 @@ #include "ck-inhibit-manager.h" #include "ck-inhibit.h" #include "ck-sysdeps.h" +#include "ck-process-group.h" #define CK_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_MANAGER, CkManagerPrivate)) @@ -789,11 +790,28 @@ static char * get_cookie_for_pid (CkManager *manager, guint pid) { - char *cookie; + char *cookie = NULL; + gchar *ssid = NULL; + CkProcessGroup *pgroup; + CkSession *session; + + pgroup = ck_process_group_get (); + + ssid = ck_process_group_get_ssid (pgroup, pid); + + if (ssid != NULL) { + g_debug ("looking for session for ssid %s", ssid); + session = g_hash_table_lookup (manager->priv->sessions, ssid); + if (session != NULL) { + g_object_get (session, "cookie", &cookie, NULL); + } - /* FIXME: need a better way to get the cookie */ + g_free (ssid); + } - cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE"); + if (cookie == NULL) { + cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE"); + } return cookie; } @@ -2559,10 +2577,11 @@ open_session_for_leader (CkManager *manager, gboolean is_local, GDBusMethodInvocation *context) { - CkSession *session; - CkSeat *seat; - const char *ssid; - const char *cookie; + CkProcessGroup *pgroup; + CkSession *session; + CkSeat *seat; + const char *ssid; + const char *cookie; ssid = ck_session_leader_peek_session_id (leader); cookie = ck_session_leader_peek_cookie (leader); @@ -2577,6 +2596,13 @@ open_session_for_leader (CkManager *manager, return; } + /* If supported, add the session leader to a process group so we + * can track it with something better than an environment variable */ + pgroup = ck_process_group_get (); + ck_process_group_create (pgroup, + ck_session_leader_get_pid (leader), + ssid); + g_hash_table_insert (manager->priv->sessions, g_strdup (ssid), g_object_ref (session)); diff --git a/src/ck-process-group.c b/src/ck-process-group.c new file mode 100644 index 0000000..b1e079f --- /dev/null +++ b/src/ck-process-group.c @@ -0,0 +1,275 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (c) 2015, Eric Koegel <eric.koegel@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <glib.h> +#include <glib-object.h> +#include <glib/gstdio.h> + +#ifdef HAVE_CGMANAGER +#include <cgmanager/cgmanager.h> +#include <cgmanager/cgmanager-client.h> +#include <nih/alloc.h> +#include <nih/error.h> +#include <nih/string.h> +#endif + +/* For TRACE */ +#include "ck-sysdeps.h" + +#include "ck-process-group.h" + +#define CK_PROCESS_GROUP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_PROCESS_GROUP, CkProcessGroupPrivate)) + +struct CkProcessGroupPrivate +{ + gint unused; +#ifdef HAVE_CGMANAGER + NihDBusProxy *cgmanager_proxy; +#endif +}; + +static void ck_process_group_class_init (CkProcessGroupClass *klass); +static void ck_process_group_init (CkProcessGroup *pgroup); +static void ck_process_group_finalize (GObject *object); + +G_DEFINE_TYPE (CkProcessGroup, ck_process_group, G_TYPE_OBJECT) + +static gboolean +ck_process_group_backend_init (CkProcessGroup *pgroup) +{ +#ifdef HAVE_CGMANAGER + DBusError dbus_error; + DBusConnection *connection = NULL; + + TRACE (); + + dbus_error_init (&dbus_error); + + /* cgmanager uses a dbus based socket rather than running on the + * system bus, nify. Let's connect to it. + */ + connection = dbus_connection_open_private (CGMANAGER_DBUS_PATH, &dbus_error); + if (!connection) { + g_warning (_("Failed to open connection to cgmanager. Is the cgmanager service running?")); + dbus_error_free (&dbus_error); + return FALSE; + } + + dbus_connection_set_exit_on_disconnect (connection, FALSE); + dbus_error_free (&dbus_error); + + pgroup->priv->cgmanager_proxy = nih_dbus_proxy_new (NULL, connection, NULL, "/org/linuxcontainers/cgmanager", NULL, NULL); + dbus_connection_unref (connection); + if (!pgroup->priv->cgmanager_proxy) { + NihError *nerr; + nerr = nih_error_get (); + g_warning ("cgmanager initialization error: %s", nerr->message); + nih_free (nerr); + return FALSE; + } +#endif + return TRUE; +} + +/** + * ck_process_group_get: + * + * Increases the reference count of the @CkProcessGroup object. + * + * Return value: Returns the CkProcessGroup object or + * NULL on failure. Do not unref when finished. [transfer: none] + **/ +CkProcessGroup* +ck_process_group_get (void) +{ + static GObject *manager = NULL; + + if (manager == NULL) { + manager = g_object_new (CK_TYPE_PROCESS_GROUP, NULL); + + g_object_add_weak_pointer (manager, + (gpointer *) &manager); + + ck_process_group_backend_init (CK_PROCESS_GROUP (manager)); + } + + return CK_PROCESS_GROUP (manager); +} + +static void +ck_process_group_class_init (CkProcessGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = ck_process_group_finalize; + + g_type_class_add_private (klass, sizeof (CkProcessGroupPrivate)); +} + +static void +ck_process_group_init (CkProcessGroup *pgroup) +{ + pgroup->priv = CK_PROCESS_GROUP_GET_PRIVATE (pgroup); +} + +static void +ck_process_group_finalize (GObject *object) +{ +#ifdef HAVE_CGMANAGER + CkProcessGroupPrivate *priv = CK_PROCESS_GROUP_GET_PRIVATE (object); + + if (priv->cgmanager_proxy) { + dbus_connection_flush(priv->cgmanager_proxy->connection); + dbus_connection_close(priv->cgmanager_proxy->connection); + nih_free(priv->cgmanager_proxy); + } + priv->cgmanager_proxy = NULL; +#endif + + G_OBJECT_CLASS (ck_process_group_parent_class)->finalize (object); +} + +/** + * ck_process_group_create: + * @CkProcessGroup: the pgroup object. + * @process: the process to add to the new group + * @ssid: the session id. + * + * Creates a new process group named @ssid and places @process inside it. + * + * Return value: TRUE on success, FALSE if process groups are unsupported + * on this platform. + **/ +gboolean +ck_process_group_create (CkProcessGroup *pgroup, + pid_t process, + const gchar *ssid) +{ +#ifdef HAVE_CGMANAGER + CkProcessGroupPrivate *priv = CK_PROCESS_GROUP_GET_PRIVATE (pgroup); + gint ret; + gint32 existed; + + TRACE (); + + if (priv->cgmanager_proxy == NULL) { + g_debug ("cgmanager_proxy == NULL"); + return FALSE; + } + + /* Create the cgroup, move the pid into it, and then tell cgmanager + * to clean up the cgroup after all the processes are gone which + * will happen when the user logs out. + */ + ret = cgmanager_create_sync (NULL, priv->cgmanager_proxy, "cpuacct", ssid, &existed); + if (ret != 0) { + NihError *nerr; + nerr = nih_error_get(); + g_debug ("failed to create cgroup: %s", nerr->message); + nih_free(nerr); + return FALSE; + } + + ret = cgmanager_move_pid_abs_sync (NULL, priv->cgmanager_proxy, "cpuacct", ssid, process); + if (ret != 0) { + NihError *nerr; + nerr = nih_error_get(); + g_debug ("failed to move pid to cgroup: %s", nerr->message); + nih_free(nerr); + return FALSE; + } + + ret = cgmanager_remove_on_empty_sync (NULL, priv->cgmanager_proxy, "cpuacct", ssid); + if (ret != 0) { + NihError *nerr; + nerr = nih_error_get(); + g_debug ("cgmanager_remove_on_empty_sync error: %s", nerr->message); + nih_free(nerr); + return FALSE; + } + + return TRUE; +#endif + return FALSE; +} + +/** + * ck_process_group_get_ssid: + * @CkProcessGroup: the pgroup object. + * @process: the process to add to the new group + * + * Return value: the ssid of the pid, otherwise NULL + **/ +gchar* +ck_process_group_get_ssid (CkProcessGroup *pgroup, + pid_t process) +{ +#ifdef HAVE_CGMANAGER + CkProcessGroupPrivate *priv = CK_PROCESS_GROUP_GET_PRIVATE (pgroup); + gint ret; + char *nih_ssid = NULL; + gchar *g_ssid = NULL; + + TRACE (); + + if (priv->cgmanager_proxy == NULL) { + g_debug ("cgmanager_proxy == NULL"); + return NULL; + } + + ret = cgmanager_get_pid_cgroup_abs_sync (NULL, priv->cgmanager_proxy, "cpuacct", process, &nih_ssid); + if (ret != 0) { + NihError *nerr; + nerr = nih_error_get(); + g_debug ("cgmanager_get_pid_cgroup_abs_sync error: %s", nerr->message); + nih_free(nerr); + return NULL; + } + + /* This is probably why you don't mix toolkits. So memory allocated + * with nih causes corruption issues with glib, so copy + free it */ + if (nih_ssid != NULL) { + g_ssid = g_strdup (nih_ssid); + + nih_free (nih_ssid); + } + + /* ignore the unknown/root cgroup */ + if (g_strcmp0 (g_ssid, "/") == 0) { + g_free (g_ssid); + g_ssid = NULL; + } + + return g_ssid; +#endif + return NULL; +} + diff --git a/src/ck-process-group.h b/src/ck-process-group.h new file mode 100644 index 0000000..36ed189 --- /dev/null +++ b/src/ck-process-group.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (c) 2015, Eric Koegel <eric.koegel@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CK_PROCESS_GROUP_H_ +#define __CK_PROCESS_GROUP_H_ + +#include <glib-object.h> + +#define CK_TYPE_PROCESS_GROUP (ck_process_group_get_type ()) +#define CK_PROCESS_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_PROCESS_GROUP, CkProcessGroup)) +#define CK_PROCESS_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_PROCESS_GROUP, CkProcessGroupClass)) +#define CK_IS_PROCESS_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_PROCESS_GROUP)) +#define CK_IS_PROCESS_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_PROCESS_GROUP)) +#define CK_PROCESS_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_PROCESS_GROUP, CkProcessGroupClass)) + +typedef struct CkProcessGroupPrivate CkProcessGroupPrivate; + +typedef struct +{ + GObject parent; + CkProcessGroupPrivate *priv; +} CkProcessGroup; + +typedef struct +{ + GObjectClass parent_class; +} CkProcessGroupClass; + + +GType ck_process_group_get_type (void); + +CkProcessGroup *ck_process_group_get (void); + +gboolean ck_process_group_create (CkProcessGroup *pgroup, + pid_t process, + const gchar *ssid); + +gchar *ck_process_group_get_ssid (CkProcessGroup *pgroup, + pid_t process); + +#endif /* __CK_PROCESS_GROUP_H_ */ diff --git a/src/ck-session.h b/src/ck-session.h index d34f88c..d9b35cd 100644 --- a/src/ck-session.h +++ b/src/ck-session.h @@ -87,15 +87,6 @@ gboolean ck_session_set_active (CkSession *se gboolean ck_session_set_is_local (CkSession *session, gboolean is_local, GError **error); -gboolean ck_session_set_id (CkSession *session, - const char *ssid, - GError **error); -gboolean ck_session_set_cookie (CkSession *session, - const char *cookie, - GError **error); -gboolean ck_session_set_seat_id (CkSession *session, - const char *sid, - GError **error); gboolean ck_session_set_unix_user (CkSession *session, guint uid, GError **error); @@ -108,9 +99,6 @@ gboolean ck_session_set_x11_display_device (CkSession *se gboolean ck_session_set_display_device (CkSession *session, const char *device, GError **error); -gboolean ck_session_set_login_session_id (CkSession *session, - const char *login_session_id, - GError **error); gboolean ck_session_set_remote_host_name (CkSession *session, const char *remote_host_name, GError **error); |