Commit 0de60b30 authored by Pavel Šimerda's avatar Pavel Šimerda

session: merge nm-session-monitor-* modules

Merged all session tracking modules into one source file and simplified
it substantially. Now systemd-logind and ConsoleKit support can be built
in at the same time and both are detected at runtime. This is useful on
source based as well as binary distributions.

Original patch written by Fabio Erculiani <lxnay@sabayon.org>, modified
by Pavel Šimerda <psimerda@redhat.com> and Thomas Haller <thaller@redhat.com>.

https://bugzilla.gnome.org/show_bug.cgi?id=686997Acked-By: Thomas Haller's avatarThomas Haller <thaller@redhat.com>
parent eb2eda44
......@@ -332,30 +332,38 @@ fi
PKG_CHECK_MODULES(SYSTEMD_200, [systemd >= 200], [have_systemd_200=yes],[have_systemd_200=no])
AM_CONDITIONAL(HAVE_SYSTEMD_200, test "${have_systemd_200}" = "yes")
# session tracking support
AC_MSG_CHECKING([Session tracking support])
# Session tracking support
AC_ARG_WITH(systemd-logind, AS_HELP_STRING([--with-systemd-logind=yes|no],
[Support systemd session tracking]))
AC_ARG_WITH(consolekit, AS_HELP_STRING([--with-consolekit=yes|no],
[Support consolekit session tracking]))
AC_ARG_WITH(session-tracking, AS_HELP_STRING([--with-session-tracking=systemd|consolekit|no],
[Select session tracking support (default: consolekit)]))
# default to consolekit
AS_IF([test -z "$with_session_tracking"], with_session_tracking=consolekit)
AS_IF([test "$with_session_tracking" = "ck"], with_session_tracking=consolekit)
AS_IF([test "$with_session_tracking" = "none"], with_session_tracking=no)
# check value
AS_IF([! (echo "$with_session_tracking" | grep -q -E "^(systemd|consolekit|no)$")],
AC_MSG_ERROR([--with-session-tracking must be systemd/consolekit/no, not $with_session_tracking]))
# add conditionals and subtitutions
AM_CONDITIONAL(SESSION_TRACKING_CK, test "$with_session_tracking" = "consolekit")
AM_CONDITIONAL(SESSION_TRACKING_SYSTEMD, test "$with_session_tracking" = "systemd")
if test "$with_session_tracking" = "systemd"; then
PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd],,
[PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login])])
[Compatibility option to choose one session tracking module]))
# defaults
AS_IF([test -z "$with_systemd_logind"], [with_systemd_logind="yes"])
AS_IF([test -z "$with_consolekit"], [with_consolekit="yes"])
# backwards compatibility
AS_IF([test "$with_session_tracking" = "ck"], [with_consolekit="yes" with_systemd_logind="no"])
AS_IF([test "$with_session_tracking" = "consolekit"], [with_consolekit="yes" with_systemd_logind="no"])
AS_IF([test "$with_session_tracking" = "systemd"], [with_consolekit="no" with_systemd_logind="yes"])
AS_IF([test "$with_session_tracking" = "no"], [with_consolekit="no" with_systemd_logind="no"])
AS_IF([test "$with_session_tracking" = "none"], [with_consolekit="no" with_systemd_logind="no"])
unset with_session_tracking
# output
session_tracking=
if test "$with_systemd_logind" = "yes"; then
PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login])
AC_SUBST(SYSTEMD_LOGIN_CFLAGS)
AC_SUBST(SYSTEMD_LOGIN_LIBS)
AC_DEFINE([SESSION_TRACKING_SYSTEMD], 1, [Define to 1 if libsystemd-login is available])
session_tracking="$session_tracking, systemd-logind"
fi
if test "$with_session_tracking" = "consolekit"; then
AC_SUBST(CKDB_PATH, /var/run/ConsoleKit/database)
if test "$with_consolekit" = "yes"; then
AC_DEFINE([SESSION_TRACKING_CONSOLEKIT], 1, [Define to 1 if ConsoleKit is available])
AC_DEFINE([CKDB_PATH], "/var/run/ConsoleKit/database", [Path to ConsoleKit database])
session_tracking="$session_tracking, consolekit"
fi
AC_MSG_RESULT($with_session_tracking)
session_tracking=${session_tracking:2}
AC_ARG_WITH(suspend-resume, AS_HELP_STRING([--with-suspend-resume=upower|systemd], [Build NetworkManager with specific suspend/resume support]))
if test "z$with_suspend_resume" = "z"; then
......@@ -1029,7 +1037,7 @@ echo " nmrundir: $nmrundir"
echo
echo "Platform:"
echo " session tracking: $with_session_tracking"
echo " session tracking: $session_tracking"
echo " suspend/resume: $with_suspend_resume"
if test "${enable_polkit}" = "yes"; then
if test "${enable_modify_system}" = "yes"; then
......
......@@ -333,15 +333,6 @@ nm_sources = \
NetworkManagerUtils.c \
NetworkManagerUtils.h
if SESSION_TRACKING_SYSTEMD
nm_sources += nm-session-monitor-systemd.c
else
if SESSION_TRACKING_CK
nm_sources += nm-session-monitor-ck.c
else
nm_sources += nm-session-monitor-null.c
endif
endif
if SUSPEND_RESUME_SYSTEMD
nm_sources += nm-sleep-monitor-systemd.c
......@@ -432,10 +423,6 @@ AM_CPPFLAGS += \
\
$(NULL)
if SESSION_TRACKING_CK
AM_CPPFLAGS += -DCKDB_PATH=\"${CKDB_PATH}\"
endif
libNetworkManager_la_SOURCES = \
$(nm_sources) \
$(glue_sources)
......
This diff is collapsed.
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 - 2010 Red Hat, Inc.
* Author: David Zeuthen <davidz@redhat.com>
* Author: Dan Williams <dcbw@redhat.com>
*/
#include "config.h"
#include <string.h>
#include "nm-logging.h"
#include "nm-session-monitor.h"
/* <internal>
* SECTION:nm-session-monitor
* @title: NMSessionMonitor
* @short_description: Monitor sessions
*
* The #NMSessionMonitor class is a utility class to track and monitor sessions.
*/
struct _NMSessionMonitor {
GObject parent_instance;
};
struct _NMSessionMonitorClass {
GObjectClass parent_class;
void (*changed) (NMSessionMonitor *monitor);
};
enum {
CHANGED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
/********************************************************************/
static void
nm_session_monitor_init (NMSessionMonitor *self)
{
}
static void
nm_session_monitor_class_init (NMSessionMonitorClass *klass)
{
/**
* NMSessionMonitor::changed:
* @monitor: A #NMSessionMonitor
*
* Emitted when something changes.
*/
signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED,
NM_TYPE_SESSION_MONITOR,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
NMSessionMonitor *
nm_session_monitor_get (void)
{
static NMSessionMonitor *singleton = NULL;
if (!singleton)
singleton = g_object_new (NM_TYPE_SESSION_MONITOR, NULL);
return singleton;
}
/* ---------------------------------------------------------------------------------------------------- */
/**
* nm_session_monitor_user_has_session:
* @monitor: A #NMSessionMonitor.
* @username: A username.
* @error: Return location for error.
*
* Checks whether the given @username is logged into a session or not.
*
* Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
* currently logged into a session.
*/
gboolean
nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
const char *username,
uid_t *out_uid,
GError **error)
{
return nm_session_user_to_uid (username, out_uid, error);
}
/**
* nm_session_monitor_uid_has_session:
* @monitor: A #NMSessionMonitor.
* @uid: A user ID.
* @error: Return location for error.
*
* Checks whether the given @uid is logged into a session or not.
*
* Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
* currently logged into a session.
*/
gboolean
nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
uid_t uid,
const char **out_user,
GError **error)
{
return nm_session_uid_to_user (uid, out_user, error);
}
/**
* nm_session_monitor_user_active:
* @monitor: A #NMSessionMonitor.
* @username: A username.
* @error: Return location for error.
*
* Checks whether the given @username is logged into a active session or not.
*
* Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
* logged into an active session.
*/
gboolean
nm_session_monitor_user_active (NMSessionMonitor *monitor,
const char *username,
GError **error)
{
return TRUE;
}
/**
* nm_session_monitor_uid_active:
* @monitor: A #NMSessionMonitor.
* @uid: A user ID.
* @error: Return location for error.
*
* Checks whether the given @uid is logged into a active session or not.
*
* Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
* logged into an active session.
*/
gboolean
nm_session_monitor_uid_active (NMSessionMonitor *monitor,
uid_t uid,
GError **error)
{
return TRUE;
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <glib/gstdio.h>
#include <systemd/sd-login.h>
#include <stdlib.h>
#include "nm-session-monitor.h"
#include "nm-logging.h"
/********************************************************************/
typedef struct {
GSource source;
GPollFD pollfd;
sd_login_monitor *monitor;
} SdSource;
static gboolean
sd_source_prepare (GSource *source, gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
sd_source_check (GSource *source)
{
SdSource *sd_source = (SdSource *) source;
return sd_source->pollfd.revents != 0;
}
static gboolean
sd_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
SdSource *sd_source = (SdSource *)source;
gboolean ret;
g_warn_if_fail (callback != NULL);
ret = (*callback) (user_data);
sd_login_monitor_flush (sd_source->monitor);
return ret;
}
static void
sd_source_finalize (GSource *source)
{
SdSource *sd_source = (SdSource*) source;
sd_login_monitor_unref (sd_source->monitor);
}
static GSourceFuncs sd_source_funcs = {
sd_source_prepare,
sd_source_check,
sd_source_dispatch,
sd_source_finalize
};
static GSource *
sd_source_new (void)
{
GSource *source;
SdSource *sd_source;
int ret;
source = g_source_new (&sd_source_funcs, sizeof (SdSource));
sd_source = (SdSource *)source;
ret = sd_login_monitor_new (NULL, &sd_source->monitor);
if (ret < 0)
g_printerr ("Error getting login monitor: %d", ret);
else {
sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor);
sd_source->pollfd.events = G_IO_IN;
g_source_add_poll (source, &sd_source->pollfd);
}
return source;
}
struct _NMSessionMonitor {
GObject parent_instance;
GSource *sd_source;
};
struct _NMSessionMonitorClass {
GObjectClass parent_class;
void (*changed) (NMSessionMonitor *monitor);
};
enum {
CHANGED_SIGNAL,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
sessions_changed (gpointer user_data)
{
NMSessionMonitor *monitor = NM_SESSION_MONITOR (user_data);
g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
return TRUE;
}
static void
nm_session_monitor_init (NMSessionMonitor *monitor)
{
monitor->sd_source = sd_source_new ();
g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL);
g_source_attach (monitor->sd_source, NULL);
}
static void
nm_session_monitor_finalize (GObject *object)
{
NMSessionMonitor *monitor = NM_SESSION_MONITOR (object);
if (monitor->sd_source != NULL) {
g_source_destroy (monitor->sd_source);
g_source_unref (monitor->sd_source);
}
if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL)
G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object);
}
static void
nm_session_monitor_class_init (NMSessionMonitorClass *klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = nm_session_monitor_finalize;
/**
* NMSessionMonitor::changed:
* @monitor: A #NMSessionMonitor
*
* Emitted when something changes.
*/
signals[CHANGED_SIGNAL] = g_signal_new ("changed",
NM_TYPE_SESSION_MONITOR,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMSessionMonitorClass, changed),
NULL, /* accumulator */
NULL, /* accumulator data */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
NMSessionMonitor *
nm_session_monitor_get (void)
{
static NMSessionMonitor *singleton = NULL;
if (!singleton)
singleton = g_object_new (NM_TYPE_SESSION_MONITOR, NULL);
return singleton;
}
gboolean
nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
const char *username,
uid_t *out_uid,
GError **error)
{
uid_t uid;
if (!nm_session_user_to_uid (username, &uid, error))
return FALSE;
if (out_uid)
*out_uid = uid;
return nm_session_monitor_uid_has_session (monitor, uid, NULL, error);
}
gboolean
nm_session_monitor_user_active (NMSessionMonitor *monitor,
const char *username,
GError **error)
{
uid_t uid;
if (!nm_session_user_to_uid (username, &uid, error))
return FALSE;
return nm_session_monitor_uid_active (monitor, uid, error);
}
gboolean
nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
uid_t uid,
const char **out_user,
GError **error)
{
int num_sessions;
if (!nm_session_uid_to_user (uid, out_user, error))
return FALSE;
/* Get all sessions (including inactive ones) for the user */
num_sessions = sd_uid_get_sessions (uid, 0, NULL);
if (num_sessions < 0) {
nm_log_warn (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d",
uid, num_sessions);
return FALSE;
}
return num_sessions > 0;
}
gboolean
nm_session_monitor_uid_active (NMSessionMonitor *monitor,
uid_t uid,
GError **error)
{
int num_sessions;
/* Get active sessions for the user */
num_sessions = sd_uid_get_sessions (uid, 1, NULL);
if (num_sessions < 0) {
nm_log_warn (LOGD_CORE, "Failed to get active systemd sessions for uid %d: %d",
uid, num_sessions);
return FALSE;
}
return num_sessions > 0;
}
......@@ -14,13 +14,279 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 - 2015 Red Hat, Inc.
* Author: David Zeuthen <davidz@redhat.com>
* Author: Dan Williams <dcbw@redhat.com>
* Author: Matthias Clasen
* Author: Pavel Šimerda <psimerda@redhat.com>
*/
#include "config.h"
#include <pwd.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <gio/gio.h>
#include "nm-session-monitor.h"
#include "nm-logging.h"
#ifdef SESSION_TRACKING_SYSTEMD
#include <systemd/sd-login.h>
#endif
/********************************************************************/
/* <internal>
* SECTION:nm-session-monitor
* @title: NMSessionMonitor
* @short_description: Monitor sessions
*
* The #NMSessionMonitor class is a utility class to track and monitor sessions.
*/
struct _NMSessionMonitor {
GObject parent_instance;
#ifdef SESSION_TRACKING_SYSTEMD
struct {
sd_login_monitor *monitor;
guint watch;
} sd;
#endif
#ifdef SESSION_TRACKING_CONSOLEKIT
struct {
GFileMonitor *monitor;
GHashTable *cache;
time_t timestamp;
} ck;
#endif
};
struct _NMSessionMonitorClass {
GObjectClass parent_class;
void (*changed) (NMSessionMonitor *monitor);
};
G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
enum {
CHANGED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
/********************************************************************/
#ifdef SESSION_TRACKING_SYSTEMD
static gboolean
sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active)
{
int status;
if (!monitor->sd.monitor)
return FALSE;
status = sd_uid_get_sessions (uid, active, NULL);
if (status < 0)
nm_log_err (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d",
uid, status);
return status > 0;
}
static gboolean
sd_changed (GIOChannel *stream, GIOCondition condition, gpointer user_data)
{
NMSessionMonitor *monitor = user_data;
g_signal_emit (monitor, signals[CHANGED], 0);
sd_login_monitor_flush (monitor->sd.monitor);
return TRUE;
}
static void
sd_init (NMSessionMonitor *monitor)
{
int status;
GIOChannel *stream;
if (!g_file_test ("/run/systemd/seats/", G_FILE_TEST_EXISTS))
return;
if ((status = sd_login_monitor_new (NULL, &monitor->sd.monitor)) < 0) {
nm_log_err (LOGD_CORE, "Failed to create systemd login monitor: %d", status);
return;
}
stream = g_io_channel_unix_new (sd_login_monitor_get_fd (monitor->sd.monitor));
monitor->sd.watch = g_io_add_watch (stream, G_IO_IN, sd_changed, monitor);
g_io_channel_unref (stream);
}
static void
sd_finalize (NMSessionMonitor *monitor)
{
g_clear_pointer (&monitor->sd.monitor, sd_login_monitor_unref);
g_source_remove (monitor->sd.watch);
}
#endif /* SESSION_TRACKING_SYSTEMD */
/********************************************************************/
#ifdef SESSION_TRACKING_CONSOLEKIT
typedef struct {
gboolean active;
} CkSession;
static gboolean
ck_load_cache (GHashTable *cache)
{
GKeyFile *keyfile = g_key_file_new ();
char **groups = NULL;
GError *error = NULL;
gsize i, len;
gboolean finished = FALSE;
if (!g_key_file_load_from_file (keyfile, CKDB_PATH, G_KEY_FILE_NONE, &error))
goto out;
if (!(groups = g_key_file_get_groups (keyfile, &len))) {
nm_log_err (LOGD_CORE, "Could not load groups from " CKDB_PATH);
goto out;
}
g_hash_table_remove_all (cache);
for (i = 0; i < len; i++) {
guint uid = G_MAXUINT;
CkSession session = { .active = FALSE };
if (!g_str_has_prefix (groups[i], "CkSession "))
continue;
uid = g_key_file_get_integer (keyfile, groups[i], "uid", &error);
if (error)
goto out;
session.active = g_key_file_get_boolean (keyfile, groups[i], "is_active", &error);
if (error)
goto out;
g_hash_table_insert (cache, GUINT_TO_POINTER (uid), g_memdup (&session, sizeof session));
}
finished = TRUE;
out:
if (error)
nm_log_err (LOGD_CORE, "ConsoleKit: Failed to load database: %s", error->message);
g_clear_error (&error);
g_clear_pointer (&groups, g_strfreev);
g_clear_pointer (&keyfile, g_key_file_free);
return finished;
}
static gboolean
ck_update_cache (NMSessionMonitor *monitor)
{
struct stat statbuf;
if (!monitor->ck.cache)
return FALSE;
/* Check the database file */
if (stat (CKDB_PATH, &statbuf) != 0) {
nm_log_err (LOGD_CORE, "Failed to check ConsoleKit timestamp: %s", strerror (errno));
return FALSE;
}
if (statbuf.st_mtime == monitor->ck.timestamp)
return TRUE;
/* Update the cache */
if (!ck_load_cache (monitor->ck.cache))
return FALSE;
monitor->ck.timestamp = statbuf.st_mtime;
return TRUE;
<