summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Koegel <eric.koegel@gmail.com>2015-07-28 20:13:45 +0300
committerEric Koegel <eric.koegel@gmail.com>2015-07-28 20:20:15 +0300
commitf864e026e5ebf3a097f82e2e0d4d7b5c956d3a1f (patch)
treecb49fa217fdcc8e67137b39789ece57a2ff0b558
parente5fb2178fb2ac866232e1db738d6357ec0041b35 (diff)
downloadConsoleKit2-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
-rw-r--r--README6
-rw-r--r--configure.ac20
-rw-r--r--src/Makefile.am4
-rw-r--r--src/ck-manager.c40
-rw-r--r--src/ck-process-group.c275
-rw-r--r--src/ck-process-group.h67
-rw-r--r--src/ck-session.h12
7 files changed, 404 insertions, 20 deletions
diff --git a/README b/README
index f9fd2f6..0f40cfc 100644
--- a/README
+++ b/README
@@ -2,7 +2,10 @@ What is ConsoleKit2?
===================
ConsoleKit2 is a framework for defining and tracking users, login
-sessions, and seats.
+sessions, and seats. It allows multiple users to be logged in at the
+same time and share hardware for their graphical session. ConsoleKit2
+will keep track of those resources and whichever session is active
+will have use of the hardware at that time.
What is a seat?
===============
@@ -36,6 +39,7 @@ Minimum Requirements
* inotify (optional)
* RBAC (optional)
* pm-utils (optional, but required for suspend/hibernate on Linux)
+* cgmanager (recommended on Linux, for process tracking)
Additionally, on Linux CONFIG_AUDITSYSCALL=y is required for
pam_ck_connector.so to work (PAM support).
diff --git a/configure.ac b/configure.ac
index d768f3f..37a3c63 100644
--- a/configure.ac
+++ b/configure.ac
@@ -274,6 +274,25 @@ AM_CONDITIONAL(ENABLE_PAM_MODULE, test "x$enable_pam_module" = "xyes")
AC_CHECK_LIB(pam_misc, misc_conv, have_linuxpam=yes)
AM_CONDITIONAL(HAVE_LINUXPAM, test "x$have_linuxpam" = "xyes")
+
+# cgroups - Using the kernel to track processes instead of the cookie
+have_cgmanager=no
+AC_ARG_ENABLE([cgroups],
+ AS_HELP_STRING([--enable-cgroups], [Enable cgroup support @<:@default=auto@:>@]),
+ [enable_cgroups=$enableval],
+ [enable_cgroups=auto])
+AS_IF([test "x$enable_cgroups" != "xno"], [
+ PKG_CHECK_MODULES([CGMANAGER], [libcgmanager libnih >= 1.0.2 libnih-dbus >= 1.0.0], [have_cgmanager=yes], [have_cgmanager=no])
+ if test "x$enable_cgroups" = "xyes" -a "x$have_cgmanager" = "xno"; then
+ AC_MSG_ERROR([cgroup support explicitly requested but dependencies not found])
+ fi
+])
+AS_IF([test "x$have_cgmanager" = "xyes"], [
+ AC_DEFINE([HAVE_CGMANAGER], [], [Define if we have cgmanager])
+])
+AM_CONDITIONAL([HAVE_CGMANAGER], [test "x$have_cgmanager" = "xyes"])
+AC_SUBST(HAVE_CGMANAGER)
+
dnl ------------------------------------------------------------------------------
dnl udev-acl - apply ACLs for users with local forground sessions
dnl ------------------------------------------------------------------------------
@@ -553,6 +572,7 @@ echo "
PAM module dir: ${PAM_MODULE_DIR}
Build PAM module: ${msg_pam_module}
Build udev-acl: ${enable_udev_acl}
+ cgroup support: ${have_cgmanager}
Build docs: ${enable_docbook_docs}
xinitrc dir: ${XINITRC_DIR}
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);