summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Koegel <eric.koegel@gmail.com>2015-08-24 09:56:17 +0300
committerEric Koegel <eric.koegel@gmail.com>2016-01-23 04:04:17 +0300
commit93d957b7dbe9841dd50bacb18cd36f5e737d81fb (patch)
tree824871ca835dde65b1f44388fd3c5b8bdb1e8e64
parente0362195ecb5e584ab35d15c63b9fdcb2a48ee9d (diff)
downloadConsoleKit2-93d957b7dbe9841dd50bacb18cd36f5e737d81fb.tar.gz
Implement XDG_RUNTIME_DIR
This adds support for implementing the runtime dir spec. ConsoleKit2 will create $RUNDIR/users on the first session creation and then $RUNDIR/users/$uid for each user logging in that keeps an active session. CK2 will clean up the $uid folder once all sessions of that user have been closed. CK2 will also attempt to mount the user's rundir as a tmpfs mount owned by the user. This way if CK2 crashes the directory will get cleaned up on next system restart. CK2 will not create a runtime dir for root. http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html https://github.com/ConsoleKit2/ConsoleKit2/issues/41
-rw-r--r--.gitignore1
-rw-r--r--configure.ac4
-rw-r--r--data/ConsoleKit.conf3
-rw-r--r--libck-connector/ck-connector.c188
-rw-r--r--libck-connector/ck-connector.h2
-rw-r--r--libck-connector/test-connector.c12
-rw-r--r--src/ck-manager.c65
-rw-r--r--src/ck-session-leader.c1
-rw-r--r--src/ck-session.c57
-rw-r--r--src/ck-session.h4
-rw-r--r--src/ck-sysdeps-freebsd.c57
-rw-r--r--src/ck-sysdeps-gnu.c12
-rw-r--r--src/ck-sysdeps-linux.c52
-rw-r--r--src/ck-sysdeps-openbsd.c56
-rw-r--r--src/ck-sysdeps-solaris.c12
-rw-r--r--src/ck-sysdeps-unix.c146
-rw-r--r--src/ck-sysdeps.h10
-rw-r--r--src/org.freedesktop.ConsoleKit.Session.xml13
-rw-r--r--tools/Makefile.am10
-rw-r--r--tools/ck-launch-session.c3
-rw-r--r--tools/ck-remove-directory.c169
21 files changed, 874 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 7477b49..b9a2b32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,4 +66,5 @@ src/test-manager
src/ck-collect-session-info
tools/pam-foreground-compat.ck
tools/70-udev-acl.rules
+tools/ck-remove-directory
doc/console-kit-daemon.1m
diff --git a/configure.ac b/configure.ac
index f8cd52f..0420f6b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,11 +61,11 @@ POLKIT_REQUIRED_VERSION=0.92
AC_CHECK_HEADERS([unistd.h paths.h sys/vt.h sys/consio.h fcntl.h limits.h \
sys/ioctl.h sys/param.h sys/socket.h syslog.h kvm.h \
sys/sysctl.h sys/user.h poll.h libintl.h locale.h \
- sys/wait.h sys/resource.h])
+ sys/wait.h sys/resource.h sys/mount.h sys/param.h ftw.h])
AC_CHECK_FUNCS([getpeerucred getpeereid memset setenv strchr strdup \
strerror strrchr strspn strstr strtol strtoul uname \
- setlocale])
+ setlocale mount umount unmount])
AC_CHECK_MEMBERS([struct stat.st_rdev])
diff --git a/data/ConsoleKit.conf b/data/ConsoleKit.conf
index 789da65..45b0917 100644
--- a/data/ConsoleKit.conf
+++ b/data/ConsoleKit.conf
@@ -145,6 +145,9 @@
send_member="GetUnixUser"/>
<allow send_destination="org.freedesktop.ConsoleKit"
send_interface="org.freedesktop.ConsoleKit.Session"
+ send_member="GetXDGRuntimeDir"/>
+ <allow send_destination="org.freedesktop.ConsoleKit"
+ send_interface="org.freedesktop.ConsoleKit.Session"
send_member="GetX11Display"/>
<allow send_destination="org.freedesktop.ConsoleKit"
send_interface="org.freedesktop.ConsoleKit.Session"
diff --git a/libck-connector/ck-connector.c b/libck-connector/ck-connector.c
index 7f6f87f..416b28f 100644
--- a/libck-connector/ck-connector.c
+++ b/libck-connector/ck-connector.c
@@ -65,6 +65,8 @@ struct _CkConnector
{
int refcount;
char *cookie;
+ char *ssid;
+ char *runtime_dir;
dbus_bool_t session_created;
DBusConnection *connection;
};
@@ -181,6 +183,14 @@ _ck_connector_free (CkConnector *connector)
free (connector->cookie);
}
+ if (connector->ssid != NULL) {
+ free (connector->ssid);
+ }
+
+ if (connector->runtime_dir != NULL) {
+ free (connector->runtime_dir);
+ }
+
free (connector);
}
@@ -242,6 +252,8 @@ ck_connector_new (void)
connector->connection = NULL;
connector->cookie = NULL;
connector->session_created = FALSE;
+ connector->ssid = NULL;
+ connector->runtime_dir = NULL;
oom:
return connector;
}
@@ -589,6 +601,182 @@ ck_connector_get_cookie (CkConnector *connector)
}
}
+static dbus_bool_t
+ck_connector_get_ssid (CkConnector *connector,
+ DBusError *error)
+{
+ DBusError local_error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ char *ssid;
+ dbus_bool_t ret;
+
+ _ck_return_val_if_fail (connector != NULL, FALSE);
+
+ reply = NULL;
+ message = NULL;
+ ssid = NULL;
+ ret = FALSE;
+
+ if (!connector->session_created || connector->cookie == NULL) {
+ return ret;
+ }
+
+ dbus_error_init (&local_error);
+ message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ "GetSessionForCookie");
+ if (message == NULL) {
+ goto out;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &(connector->cookie),
+ DBUS_TYPE_INVALID)) {
+ goto out;
+ }
+
+ dbus_error_init (&local_error);
+ reply = dbus_connection_send_with_reply_and_block (connector->connection,
+ message,
+ -1,
+ &local_error);
+ if (reply == NULL) {
+ if (dbus_error_is_set (&local_error)) {
+ dbus_set_error (error,
+ CK_CONNECTOR_ERROR,
+ "Unable to get session for cookie: %s, no reply from dbus",
+ local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+ }
+
+ if (!dbus_message_get_args (reply, error,
+ DBUS_TYPE_OBJECT_PATH, &ssid,
+ DBUS_TYPE_INVALID)) {
+ dbus_set_error (error,
+ CK_CONNECTOR_ERROR,
+ "Unable to get session for cookie: %s",
+ local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+
+ connector->ssid = strdup (ssid);
+ if (connector->ssid == NULL) {
+ goto out;
+ }
+
+ ret = TRUE;
+
+out:
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+
+ return ret;
+}
+
+/**
+ * Gets the XDG_RUNTIME_DIR for the current open session.
+ * Returns #NULL if no session is open.
+ *
+ * @returns a constant string with the XDG_RUNTIME_DIR.
+ */
+const char *
+ck_connector_get_runtime_dir (CkConnector *connector,
+ DBusError *error)
+{
+ DBusError local_error;
+ DBusMessage *message;
+ char *runtime_dir;
+ DBusMessage *reply;
+
+ _ck_return_val_if_fail (connector != NULL, NULL);
+
+ if (!connector->session_created || connector->cookie == NULL) {
+ return NULL;
+ }
+
+ /* If we already have the runtime dir, supply it again */
+ if (connector->runtime_dir != NULL) {
+ return connector->runtime_dir;
+ }
+
+ /* get the ssid if we don't already have it */
+ if (connector->ssid == NULL) {
+ if (ck_connector_get_ssid (connector, error) == FALSE) {
+ return NULL;
+ }
+ }
+
+ reply = NULL;
+ message = NULL;
+ runtime_dir = NULL;
+
+ if (!connector->session_created || connector->cookie == NULL) {
+ return NULL;
+ }
+
+ dbus_error_init (&local_error);
+ message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
+ connector->ssid,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetXDGRuntimeDir");
+ if (message == NULL) {
+ goto out;
+ }
+
+ dbus_error_init (&local_error);
+ reply = dbus_connection_send_with_reply_and_block (connector->connection,
+ message,
+ -1,
+ &local_error);
+ if (reply == NULL) {
+ if (dbus_error_is_set (&local_error)) {
+ dbus_set_error (error,
+ CK_CONNECTOR_ERROR,
+ "Unable to get runtime dir for session: %s",
+ local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+ }
+
+ if (!dbus_message_get_args (reply, error,
+ DBUS_TYPE_STRING, &runtime_dir,
+ DBUS_TYPE_INVALID)) {
+ dbus_set_error (error,
+ CK_CONNECTOR_ERROR,
+ "Unable to get runtime dir for session: %s",
+ local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+
+ connector->runtime_dir = strdup (runtime_dir);
+ if (connector->runtime_dir == NULL) {
+ goto out;
+ }
+
+out:
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+
+ return connector->runtime_dir;
+}
+
/**
* Issues the CloseSession method call on the ConsoleKit manager
* interface.
diff --git a/libck-connector/ck-connector.h b/libck-connector/ck-connector.h
index f692803..523b22b 100644
--- a/libck-connector/ck-connector.h
+++ b/libck-connector/ck-connector.h
@@ -56,6 +56,8 @@ dbus_bool_t ck_connector_open_session (CkConnector *ckc,
DBusError *error);
const char *ck_connector_get_cookie (CkConnector *ckc);
+const char *ck_connector_get_runtime_dir (CkConnector *ckc,
+ DBusError *error);
dbus_bool_t ck_connector_close_session (CkConnector *ckc,
DBusError *error);
diff --git a/libck-connector/test-connector.c b/libck-connector/test-connector.c
index 66ddc61..3eb65c6 100644
--- a/libck-connector/test-connector.c
+++ b/libck-connector/test-connector.c
@@ -76,6 +76,18 @@ main (int argc, char *argv[])
}
printf ("Session cookie is '%s'\n", ck_connector_get_cookie (connector));
+
+ if (ck_connector_get_runtime_dir (connector, &error) == NULL) {
+ if (dbus_error_is_set (&error)) {
+ printf ("Failed to get XDG_RUNTIME_DIR error is '%s'\n", error.message);
+ dbus_error_free (&error);
+ } else {
+ printf ("Cannot get XDG_RUNTIME_DIR, out of memory error\n");
+ }
+ } else {
+ printf ("XDG_RUNTIME_DIR is '%s'\n", ck_connector_get_runtime_dir (connector, &error));
+ }
+
sleep (20);
dbus_error_init (&error);
diff --git a/src/ck-manager.c b/src/ck-manager.c
index 4a6e511..a72d5a1 100644
--- a/src/ck-manager.c
+++ b/src/ck-manager.c
@@ -1165,6 +1165,40 @@ get_system_num_users (CkManager *manager)
return num_users;
}
+static gboolean
+session_has_user (const char *ssid,
+ CkSession *session,
+ guint *unix_user)
+{
+ guint session_user;
+
+ session_user = console_kit_session_get_unix_user (CONSOLE_KIT_SESSION (session));
+
+ if (session_user == *unix_user) {
+ g_debug ("Found session for user %d", *unix_user);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static const gchar *
+get_runtime_dir_for_user (CkManager *manager,
+ guint unix_user)
+{
+ gpointer session;
+
+ TRACE ();
+
+ session = g_hash_table_find (manager->priv->sessions, (GHRFunc)session_has_user, &unix_user);
+
+ if (session != NULL) {
+ return ck_session_get_runtime_dir (CK_SESSION (session));
+ }
+
+ return NULL;
+}
+
#ifdef ENABLE_RBAC_SHUTDOWN
static gboolean
check_rbac_permissions (CkManager *manager,
@@ -2584,6 +2618,8 @@ open_session_for_leader (CkManager *manager,
CkSeat *seat;
const char *ssid;
const char *cookie;
+ char *runtime_dir;
+ guint unix_user;
ssid = ck_session_leader_peek_session_id (leader);
cookie = ck_session_leader_peek_cookie (leader);
@@ -2598,6 +2634,20 @@ open_session_for_leader (CkManager *manager,
return;
}
+ unix_user = console_kit_session_get_unix_user (CONSOLE_KIT_SESSION (session));
+
+ /* If the user is already logged in, continue to use the same runtime dir.
+ * We need to do this before adding the session to the manager's table. */
+ runtime_dir = g_strdup (get_runtime_dir_for_user (manager, unix_user));
+
+ /* otherwise generate a new one */
+ if (runtime_dir == NULL) {
+ runtime_dir = ck_generate_runtime_dir_for_user (unix_user);
+ }
+
+ g_debug ("XDG_RUNTIME_DIR is %s", runtime_dir);
+ ck_session_set_runtime_dir (session, runtime_dir);
+
/* 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 ();
@@ -2631,6 +2681,7 @@ open_session_for_leader (CkManager *manager,
manager);
g_object_unref (session);
+ g_free (runtime_dir);
g_dbus_method_invocation_return_value (context , g_variant_new ("(s)", cookie));
}
@@ -3016,6 +3067,7 @@ remove_session_for_cookie (CkManager *manager,
char *orig_ssid;
CkSessionLeader *leader;
char *sid;
+ guint unix_user;
gboolean res;
gboolean ret;
@@ -3055,6 +3107,11 @@ remove_session_for_cookie (CkManager *manager,
* for seat removals doesn't work.
*/
+ /* Get the session's uid, we'll need this if we have to remove the
+ * runtime dir
+ */
+ unix_user = console_kit_session_get_unix_user (CONSOLE_KIT_SESSION (orig_session));
+
/* remove from seat */
sid = NULL;
ck_session_get_seat_id (orig_session, &sid, NULL);
@@ -3085,6 +3142,14 @@ remove_session_for_cookie (CkManager *manager,
manager_update_system_idle_hint (manager);
+ if (get_runtime_dir_for_user (manager, unix_user) == NULL) {
+ /* We removed the session and now there's no runtime dir
+ * associated with that user.
+ * Remove the runtime dir from the system.
+ */
+ ck_remove_runtime_dir_for_user (unix_user);
+ }
+
ret = TRUE;
out:
if (orig_session != NULL) {
diff --git a/src/ck-session-leader.c b/src/ck-session-leader.c
index 2b392b6..5fd4f96 100644
--- a/src/ck-session-leader.c
+++ b/src/ck-session-leader.c
@@ -62,6 +62,7 @@ struct CkSessionLeaderPrivate
char *service_name;
char *session_id;
char *cookie;
+ char *runtime_dir;
GList *pending_jobs;
gboolean cancelled;
GHashTable *override_parameters;
diff --git a/src/ck-session.c b/src/ck-session.c
index 1b58889..901422f 100644
--- a/src/ck-session.c
+++ b/src/ck-session.c
@@ -53,7 +53,7 @@ struct CkSessionPrivate
char *id;
char *cookie;
char *seat_id;
-
+ char *runtime_dir;
char *login_session_id;
GTimeVal creation_time;
@@ -832,6 +832,58 @@ ck_session_set_seat_id (CkSession *session,
return TRUE;
}
+/**
+ * ck_session_set_runtime_dir
+ * @session: CkSession object
+ * @runtime_dir: The XDG_RUNTIME_DIR for the user of this session. For details, see:
+ * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ * returns: TRUE if successfully set, FALSE on failure.
+ **/
+gboolean
+ck_session_set_runtime_dir (CkSession *session,
+ const char *runtime_dir)
+{
+ g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+ g_free (session->priv->runtime_dir);
+ session->priv->runtime_dir = g_strdup (runtime_dir);
+
+ return TRUE;
+}
+
+/**
+ * ck_session_get_runtime_dir
+ * @session: CkSession object
+ * returns: The XDG_RUNTIME_DIR. For details, see:
+ * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ **/
+const char *
+ck_session_get_runtime_dir (CkSession *session)
+{
+ g_return_val_if_fail (CK_IS_SESSION (session), NULL);
+ return session->priv->runtime_dir;
+}
+
+static gboolean
+dbus_get_runtime_dir (ConsoleKitSession *cksession,
+ GDBusMethodInvocation *context)
+{
+ CkSession *session = CK_SESSION(cksession);
+
+ TRACE ();
+
+ g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE);
+
+ /* if no login session id is set return an empty string */
+ if (session->priv->runtime_dir == NULL) {
+ throw_error (context, CK_SESSION_ERROR_FAILED, _("Failed to create the XDG_RUNTIME_DIR"));
+ return FALSE;
+ }
+
+ console_kit_session_complete_get_xdgruntime_dir (cksession, context, session->priv->runtime_dir);
+ return TRUE;
+}
+
static gboolean
dbus_get_login_session_id (ConsoleKitSession *cksession,
GDBusMethodInvocation *context)
@@ -1087,6 +1139,7 @@ ck_session_iface_init (ConsoleKitSessionIface *iface)
iface->handle_lock = dbus_lock;
iface->handle_unlock = dbus_unlock;
iface->handle_get_idle_hint = dbus_get_idle_hint;
+ iface->handle_get_xdgruntime_dir = dbus_get_runtime_dir;
}
static void
@@ -1108,6 +1161,7 @@ ck_session_finalize (GObject *object)
g_free (session->priv->id);
g_free (session->priv->cookie);
g_free (session->priv->login_session_id);
+ g_free (session->priv->runtime_dir);
G_OBJECT_CLASS (ck_session_parent_class)->finalize (object);
}
@@ -1341,6 +1395,7 @@ ck_session_dump (CkSession *session,
g_key_file_set_boolean (key_file, group_name, "is_active", console_kit_session_get_active (cksession));
g_key_file_set_boolean (key_file, group_name, "is_local", console_kit_session_get_is_local (cksession));
+ g_key_file_set_string (key_file, group_name, "XDG_RUNTIME_DIR", NONULL_STRING (session->priv->runtime_dir));
s = g_time_val_to_iso8601 (&(session->priv->creation_time));
g_key_file_set_string (key_file,
diff --git a/src/ck-session.h b/src/ck-session.h
index d9b35cd..8750e2f 100644
--- a/src/ck-session.h
+++ b/src/ck-session.h
@@ -125,8 +125,12 @@ gboolean ck_session_get_login_session_id (CkSession *se
gboolean ck_session_get_creation_time (CkSession *session,
char **iso8601_datetime,
GError **error);
+const char * ck_session_get_runtime_dir (CkSession *session);
+gboolean ck_session_set_runtime_dir (CkSession *session,
+ const char *runtime_dir);
+
gboolean ck_session_set_id (CkSession *session,
const char *ssid,
GError **error);
diff --git a/src/ck-sysdeps-freebsd.c b/src/ck-sysdeps-freebsd.c
index e7cbb04..b7a93c5 100644
--- a/src/ck-sysdeps-freebsd.c
+++ b/src/ck-sysdeps-freebsd.c
@@ -45,6 +45,15 @@
#endif
#include <sys/consio.h>
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+
#define DEV_ENCODE(M,m) ( \
( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
)
@@ -598,3 +607,51 @@ ck_system_can_hybrid_sleep (void)
/* TODO: not implemented */
return FALSE;
}
+
+gboolean
+ck_make_tmpfs (guint uid, guint gid, const gchar *dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ gchar *opts;
+ int result;
+
+ TRACE ();
+
+ opts = g_strdup_printf ("mode=0700,size=8M,uid=%d,guid=%d", uid, gid);
+
+ result = mount("tmpfs", dest, 0, opts);
+
+ g_free (opts);
+
+ if (result == 0) {
+ return TRUE;
+ } else {
+ g_info ("Failed to create tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+ return FALSE;
+ }
+#endif
+
+ return FALSE;
+}
+
+gboolean
+ck_remove_tmpfs (guint uid, const gchar *dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ int result;
+
+ TRACE ();
+
+ result = unmount(dest, 0);
+
+ if (result == 0) {
+ return TRUE;
+ }
+
+ g_info ("Failed to unmount tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+#endif
+
+ return FALSE;
+}
diff --git a/src/ck-sysdeps-gnu.c b/src/ck-sysdeps-gnu.c
index 9437559..2ff9b24 100644
--- a/src/ck-sysdeps-gnu.c
+++ b/src/ck-sysdeps-gnu.c
@@ -421,3 +421,15 @@ ck_system_can_hybrid_sleep (void)
/* TODO: not implemented */
return FALSE;
}
+
+gboolean
+ck_make_tmpfs (guint uid, guint gid, const gchar *dest)
+{
+ return FALSE;
+}
+
+gboolean
+ck_remove_tmpfs (guint uid, const gchar *dest)
+{
+ return FALSE;
+}
diff --git a/src/ck-sysdeps-linux.c b/src/ck-sysdeps-linux.c
index d3d1b5a..aea9ab1 100644
--- a/src/ck-sysdeps-linux.c
+++ b/src/ck-sysdeps-linux.c
@@ -39,6 +39,10 @@
#include <paths.h>
#endif /* HAVE_PATHS_H */
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
#include "ck-sysdeps.h"
#ifndef ERROR
@@ -900,6 +904,54 @@ ck_system_can_hybrid_sleep (void)
return linux_supports_sleep_state ("suspend-hybrid");
}
+gboolean
+ck_make_tmpfs (guint uid, guint gid, const gchar *dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ gchar *opts;
+ int result;
+
+ TRACE ();
+
+ opts = g_strdup_printf ("mode=0700,size=8M,uid=%d,guid=%d", uid, gid);
+
+ result = mount("none", dest, "tmpfs", 0, opts);
+
+ g_free (opts);
+
+ if (result == 0) {
+ return TRUE;
+ } else {
+ g_info ("Failed to create tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+ return FALSE;
+ }
+#endif
+
+ return FALSE;
+}
+
+gboolean
+ck_remove_tmpfs (guint uid, const char* dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ int result;
+
+ TRACE ();
+
+ result = umount2(dest, MNT_DETACH);
+
+ if (result == 0) {
+ return TRUE;
+ }
+
+ g_info ("Failed to unmount tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+#endif
+
+ return FALSE;
+}
+
#ifdef HAVE_SYS_VT_SIGNAL
/* For the moment this is Linux only.
* Returns the vt file descriptor or < 0 on failure.
diff --git a/src/ck-sysdeps-openbsd.c b/src/ck-sysdeps-openbsd.c
index c924864..af1ee3a 100644
--- a/src/ck-sysdeps-openbsd.c
+++ b/src/ck-sysdeps-openbsd.c
@@ -43,6 +43,14 @@
#include <sys/stdint.h>
#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
#include <dev/wscons/wsdisplay_usl_io.h>
#define DEV_ENCODE(M,m) ( \
@@ -484,3 +492,51 @@ ck_system_can_hybrid_sleep (void)
/* TODO: not implemented */
return FALSE;
}
+
+gboolean
+ck_make_tmpfs (guint uid, guint gid, const gchar *dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ gchar *opts;
+ int result;
+
+ TRACE ();
+
+ opts = g_strdup_printf ("mode=0700,size=8M,uid=%d,guid=%d", uid, gid);
+
+ result = mount("tmpfs", dest, 0, opts);
+
+ g_free (opts);
+
+ if (result == 0) {
+ return TRUE;
+ } else {
+ g_info ("Failed to create tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+ return FALSE;
+ }
+#endif
+
+ return FALSE;
+}
+
+gboolean
+ck_remove_tmpfs (guint uid, const gchar *dest)
+{
+#ifdef HAVE_SYS_MOUNT_H
+ int result;
+
+ TRACE ();
+
+ result = unmount(dest, 0);
+
+ if (result == 0) {
+ return TRUE;
+ }
+
+ g_info ("Failed to unmount tmpfs mount, reason was: %s", strerror(errno));
+ errno = 0;
+#endif
+
+ return FALSE;
+}
diff --git a/src/ck-sysdeps-solaris.c b/src/ck-sysdeps-solaris.c
index 9d26380..0387fca 100644
--- a/src/ck-sysdeps-solaris.c
+++ b/src/ck-sysdeps-solaris.c
@@ -550,3 +550,15 @@ ck_system_can_hybrid_sleep (void)
/* TODO: not implemented */
return FALSE;
}
+
+gboolean
+ck_make_tmpfs (guint uid, guint gid, const gchar *dest)
+{
+ return FALSE;
+}
+
+gboolean
+ck_remove_tmpfs (guint uid, const gchar *dest)
+{
+ return FALSE;
+}
diff --git a/src/ck-sysdeps-unix.c b/src/ck-sysdeps-unix.c
index c24a0e1..a618388 100644
--- a/src/ck-sysdeps-unix.c
+++ b/src/ck-sysdeps-unix.c
@@ -31,6 +31,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <pwd.h>
#ifdef __linux__
#include <linux/kd.h>
@@ -56,6 +57,10 @@
#include <ucred.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include "ck-sysdeps.h"
#ifndef ERROR
@@ -328,6 +333,147 @@ ck_is_root_user (void)
return FALSE;
}
+/* Call g_free on string when done using it. [transfer: full] */
+static gchar *
+get_rundir (guint uid)
+{
+ const gchar *base;
+
+ TRACE ();
+
+ base = RUNDIR "/user";
+
+ return g_strdup_printf ("%s/%d", base, uid);
+}
+
+static gboolean
+create_rundir_base (guint uid)
+{
+ const gchar *base;
+
+ TRACE ();
+
+ base = RUNDIR "/user";
+
+ /* Create the base directory that we will own. */
+ if (g_mkdir_with_parents (base, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
+ g_warning ("Failed to create %s, reason was: %s", base, strerror(errno));
+ errno = 0;
+ return FALSE;
+ }
+
+ /* ensure we have ownership */
+ if (chown (base, 0, 0) != 0) {
+ g_warning ("Failed to chown %s, reason was: %s", base, strerror(errno));
+ errno = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+remove_rundir (guint uid, const gchar *dest)
+{
+ gchar *command;
+ GError *error = NULL;
+ gboolean res;
+
+ TRACE ();
+
+ g_return_val_if_fail (dest, FALSE);
+
+ if (uid < 1) {
+ g_debug ("We didn't create a runtime dir for root, nothing to remove");
+ return FALSE;
+ }
+
+ command = g_strdup_printf (LIBEXECDIR "/ck-remove-directory --uid=%d --dest=%s", uid, dest);
+
+ res = g_spawn_command_line_sync (command, NULL, NULL, NULL, &error);
+
+ if (! res) {
+ g_warning ("Unable to remove user runtime dir '%s' error was: %s", dest, error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gchar *
+ck_generate_runtime_dir_for_user (guint uid)
+{
+ gchar *dest;
+ struct passwd *pwent;
+
+ TRACE ();
+
+ if (uid < 1) {
+ g_debug ("We do not create runtime dirs for root");
+ return NULL;
+ }
+
+ errno = 0;
+ pwent = getpwuid (uid);
+ if (pwent == NULL) {
+ g_warning ("Unable to lookup UID: %s", g_strerror (errno));
+ errno = 0;
+ return NULL;
+ }
+
+ /* ensure we have created the base directory */
+ if (create_rundir_base (uid) == FALSE) {
+ return NULL;
+ }
+
+ dest = get_rundir (uid);
+
+ /* Create the new directory */
+ if (g_mkdir_with_parents (dest, S_IRWXU) != 0) {
+ g_warning ("Failed to create XDG_RUNTIME_DIR, reason was: %s", strerror(errno));
+ errno = 0;
+ g_free (dest);
+ return NULL;
+ }
+
+ g_debug ("setting uid %d, gid %d", uid, pwent->pw_gid);
+
+ /* assign ownership to the user */
+ if (chown (dest, uid, pwent->pw_gid) != 0) {
+ g_warning ("Failed to chown XDG_RUNTIME_DIR, reason was: %s", strerror(errno));
+ errno = 0;
+ g_free (dest);
+ return NULL;
+ }
+
+ /* attempt to make it a small tmpfs location */
+ ck_make_tmpfs (uid, pwent->pw_gid, dest);
+
+ return dest;
+}
+
+gboolean
+ck_remove_runtime_dir_for_user (guint uid)
+{
+ gchar *dest;
+
+ TRACE ();
+
+ dest = get_rundir (uid);
+
+ /* attempt to remove the tmpfs */
+ ck_remove_tmpfs (uid, dest);
+
+ /* remove the user's runtime dir now that all user sessions
+ * are gone */
+ remove_rundir (uid, dest);
+
+ g_free (dest);
+
+ return TRUE;
+}
+
gboolean
ck_wait_for_active_console_num (int console_fd,
guint num)
diff --git a/src/ck-sysdeps.h b/src/ck-sysdeps.h
index bc32631..0390cb4 100644
--- a/src/ck-sysdeps.h
+++ b/src/ck-sysdeps.h
@@ -60,6 +60,16 @@ gboolean ck_fd_is_a_console (int fd);
gboolean ck_is_root_user (void);
+gchar * ck_generate_runtime_dir_for_user (guint uid);
+
+gboolean ck_remove_runtime_dir_for_user (guint uid);
+
+gboolean ck_make_tmpfs (guint uid,
+ guint gid,
+ const gchar *dest);
+gboolean ck_remove_tmpfs (guint uid,
+ const gchar *dest);
+
gboolean ck_get_max_num_consoles (guint *num);
gboolean ck_supports_activatable_consoles (void);
diff --git a/src/org.freedesktop.ConsoleKit.Session.xml b/src/org.freedesktop.ConsoleKit.Session.xml
index 4f5c268..2330de4 100644
--- a/src/org.freedesktop.ConsoleKit.Session.xml
+++ b/src/org.freedesktop.ConsoleKit.Session.xml
@@ -78,6 +78,19 @@
<doc:seealso><doc:ref type="property" to="Session:unix-user">unix-user</doc:ref></doc:seealso>
</doc:doc>
</method>
+ <method name="GetXDGRuntimeDir">
+ <arg name="xdg_runtime_dir" direction="out" type="s">
+ <doc:doc>
+ <doc:summary>XDG_RUNTIME_DIR</doc:summary>
+ </doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description><doc:para>Returns the XDG_RUNTIME_DIR location of the session.
+ The XDG_RUNTIME_DIR is the same for all sessions of the same user and will be automatically
+ removed once the last session of the user is closed.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
<method name="GetX11Display">
<arg name="display" direction="out" type="s">
<doc:doc>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 07d02e3..a181033 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -129,6 +129,7 @@ libexec_PROGRAMS = \
ck-collect-session-info \
ck-get-x11-server-pid \
ck-get-x11-display-device \
+ ck-remove-directory \
$(NULL)
ck_collect_session_info_SOURCES = \
@@ -159,6 +160,15 @@ ck_get_x11_display_device_LDADD = \
$(top_builddir)/src/libck.la \
$(NULL)
+ck_remove_directory_SOURCES = \
+ ck-remove-directory.c \
+ $(NULL)
+
+ck_remove_directory_LDADD = \
+ $(TOOLS_LIBS) \
+ $(top_builddir)/src/libck.la \
+ $(NULL)
+
if ENABLE_UDEV_ACL
udevrulesdir = $(UDEVDIR)/rules.d
diff --git a/tools/ck-launch-session.c b/tools/ck-launch-session.c
index 4200da8..427e07b 100644
--- a/tools/ck-launch-session.c
+++ b/tools/ck-launch-session.c
@@ -76,6 +76,9 @@ main (int argc, char **argv)
case 0:
setenv ("XDG_SESSION_COOKIE",
ck_connector_get_cookie (ckc), 1);
+
+ setenv ("XDG_RUNTIME_DIR",
+ ck_connector_get_runtime_dir (ckc, &error), 1);
break;
default:
waitpid (pid, &status, 0);
diff --git a/tools/ck-remove-directory.c b/tools/ck-remove-directory.c
new file mode 100644
index 0000000..cf44fd6
--- /dev/null
+++ b/tools/ck-remove-directory.c
@@ -0,0 +1,169 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <libintl.h>
+#include <locale.h>
+#include <ftw.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "ck-sysdeps.h"
+
+
+static void
+become_user (uid_t uid, const gchar* dest)
+{
+ int res;
+ struct passwd *pwent;
+
+ if (uid < 1) {
+ g_critical ("invalid UID");
+ exit (1);
+ }
+
+ if (dest == NULL) {
+ g_critical ("invalid dest");
+ exit (1);
+ }
+
+ errno = 0;
+ pwent = getpwuid (uid);
+ if (pwent == NULL) {
+ g_warning ("Unable to lookup UID: %s", g_strerror (errno));
+ exit (1);
+ }
+
+ /* set the group */
+ errno = 0;
+ res = setgid (pwent->pw_gid);
+ if (res == -1) {
+ g_warning ("Error performing setgid: %s", g_strerror (errno));
+ exit (1);
+ }
+
+ /* become the user */
+ errno = 0;
+ res = setuid (uid);
+ if (res == -1) {
+ g_warning ("Error performing setuid: %s", g_strerror (errno));
+ exit (1);
+ }
+}
+
+static int
+unlink_cb (const char *fpath,
+ const struct stat *sb,
+ int typeflag,
+ struct FTW *ftwbuf)
+{
+ int ret = remove (fpath);
+
+ if (ret) {
+ g_error ("Failed to remove %s, reason was: %s", fpath, strerror(errno));
+ errno = 0;
+ }
+
+ return ret;
+}
+
+static int
+remove_dest_dir (const gchar *dest)
+{
+ return nftw(dest, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GOptionContext *context;
+ gboolean ret;
+ GError *error;
+ static int user_id = -1;
+ static gchar *dest = NULL;
+ static GOptionEntry entries [] = {
+ { "uid", 0, 0, G_OPTION_ARG_INT, &user_id, N_("User ID"), NULL },
+ { "dest", 0, 0, G_OPTION_ARG_STRING, &dest, N_("Destination to remove"), NULL },
+ { NULL }
+ };
+
+ /* Setup for i18n */
+ setlocale(LC_ALL, "");
+
+#ifdef ENABLE_NLS
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+
+ /* For now at least restrict this to root */
+ if (getuid () != 0) {
+ g_warning (_("You must be root to run this program"));
+ exit (1);
+ }
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, NULL);
+ error = NULL;
+ ret = g_option_context_parse (context, &argc, &argv, &error);
+ g_option_context_free (context);
+
+ if (! ret) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ if (user_id < 1) {
+ g_warning ("Invalid UID");
+ exit (1);
+ }
+
+ /* Ensure we have a dest and that it starts with the correct prefix
+ * so we don't remove something important.
+ */
+ if (dest == NULL || !g_str_has_prefix (dest, RUNDIR "/user/")) {
+ g_warning ("Invalid Dest");
+ exit (1);
+ }
+
+ become_user (user_id, dest);
+
+ ret = remove_dest_dir (dest);
+
+ return ret != TRUE;
+}