/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006-2007 William Jon McCann * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ck-tty-idle-monitor.h" #include "ck-session.h" #include "ck-session-glue.h" #include "ck-marshal.h" #include "ck-run-programs.h" #define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate)) #define CK_DBUS_PATH "/org/freedesktop/ConsoleKit" #define CK_DBUS_NAME "org.freedesktop.ConsoleKit" #define NONULL_STRING(x) ((x) != NULL ? (x) : "") #define IDLE_TIME_SECS 60 struct CkSessionPrivate { char *id; char *cookie; char *seat_id; char *session_type; char *login_session_id; char *display_device; char *x11_display_device; char *x11_display; char *remote_host_name; guint uid; gboolean active; gboolean is_local; GTimeVal creation_time; CkTtyIdleMonitor *idle_monitor; gboolean idle_hint; GTimeVal idle_since_hint; DBusGConnection *connection; DBusGProxy *bus_proxy; }; enum { ACTIVATE, LOCK, UNLOCK, ACTIVE_CHANGED, IDLE_HINT_CHANGED, LAST_SIGNAL }; enum { PROP_0, PROP_ID, PROP_COOKIE, PROP_USER, PROP_UNIX_USER, PROP_X11_DISPLAY, PROP_X11_DISPLAY_DEVICE, PROP_DISPLAY_DEVICE, PROP_SESSION_TYPE, PROP_REMOTE_HOST_NAME, PROP_LOGIN_SESSION_ID, PROP_IS_LOCAL, PROP_ACTIVE, PROP_IDLE_HINT, }; static guint signals [LAST_SIGNAL] = { 0, }; static void ck_session_class_init (CkSessionClass *klass); static void ck_session_init (CkSession *session); static void ck_session_finalize (GObject *object); G_DEFINE_TYPE (CkSession, ck_session, G_TYPE_OBJECT) GQuark ck_session_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("ck_session_error"); } return ret; } static gboolean register_session (CkSession *session) { GError *error = NULL; error = NULL; session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (session->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } return FALSE; } session->priv->bus_proxy = dbus_g_proxy_new_for_name (session->priv->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); dbus_g_connection_register_g_object (session->priv->connection, session->priv->id, G_OBJECT (session)); return TRUE; } /* lock and unlock are separate functions because: 1. we don't maintain state for locked 2. so security policy can be handled separately */ gboolean ck_session_lock (CkSession *session, DBusGMethodInvocation *context) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_debug ("Emitting lock for session %s", session->priv->id); g_signal_emit (session, signals [LOCK], 0); dbus_g_method_return (context); return TRUE; } gboolean ck_session_unlock (CkSession *session, DBusGMethodInvocation *context) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_debug ("Emitting unlock for session %s", session->priv->id); g_signal_emit (session, signals [UNLOCK], 0); dbus_g_method_return (context); return TRUE; } /* adapted from PolicyKit */ static gboolean get_caller_info (CkSession *session, const char *sender, uid_t *calling_uid, pid_t *calling_pid) { gboolean res; GError *error = NULL; res = FALSE; if (sender == NULL) { goto out; } if (! dbus_g_proxy_call (session->priv->bus_proxy, "GetConnectionUnixUser", &error, G_TYPE_STRING, sender, G_TYPE_INVALID, G_TYPE_UINT, calling_uid, G_TYPE_INVALID)) { g_warning ("GetConnectionUnixUser() failed: %s", error->message); g_error_free (error); goto out; } if (! dbus_g_proxy_call (session->priv->bus_proxy, "GetConnectionUnixProcessID", &error, G_TYPE_STRING, sender, G_TYPE_INVALID, G_TYPE_UINT, calling_pid, G_TYPE_INVALID)) { g_warning ("GetConnectionUnixProcessID() failed: %s", error->message); g_error_free (error); goto out; } res = TRUE; g_debug ("uid = %d", *calling_uid); g_debug ("pid = %d", *calling_pid); out: return res; } static gboolean session_set_idle_hint_internal (CkSession *session, gboolean idle_hint) { if (session->priv->idle_hint != idle_hint) { session->priv->idle_hint = idle_hint; g_object_notify (G_OBJECT (session), "idle-hint"); /* FIXME: can we get a time from the dbus message? */ g_get_current_time (&session->priv->idle_since_hint); g_debug ("Emitting idle-changed for session %s", session->priv->id); g_signal_emit (session, signals [IDLE_HINT_CHANGED], 0, idle_hint); } return TRUE; } /* Example: dbus-send --system --dest=org.freedesktop.ConsoleKit \ --type=method_call --print-reply --reply-timeout=2000 \ /org/freedesktop/ConsoleKit/Session1 \ org.freedesktop.ConsoleKit.Session.SetIdleHint boolean:TRUE */ gboolean ck_session_set_idle_hint (CkSession *session, gboolean idle_hint, DBusGMethodInvocation *context) { char *sender; uid_t calling_uid; pid_t calling_pid; gboolean res; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); sender = dbus_g_method_get_sender (context); res = get_caller_info (session, sender, &calling_uid, &calling_pid); g_free (sender); if (! res) { GError *error; error = g_error_new (CK_SESSION_ERROR, CK_SESSION_ERROR_GENERAL, _("Unable to lookup information about calling process '%d'"), calling_pid); g_warning ("stat on pid %d failed", calling_pid); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } /* only restrict this by UID for now */ if (session->priv->uid != calling_uid) { GError *error; error = g_error_new (CK_SESSION_ERROR, CK_SESSION_ERROR_GENERAL, _("Only session owner may set idle hint state")); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } session_set_idle_hint_internal (session, idle_hint); dbus_g_method_return (context); return TRUE; } gboolean ck_session_get_idle_hint (CkSession *session, gboolean *idle_hint, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (idle_hint != NULL) { *idle_hint = session->priv->idle_hint; } return TRUE; } #if GLIB_CHECK_VERSION(2,12,0) #define _g_time_val_to_iso8601(t) g_time_val_to_iso8601(t) #else /* copied from GLib */ static gchar * _g_time_val_to_iso8601 (GTimeVal *time_) { gchar *retval; g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL); #define ISO_8601_LEN 21 #define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ" retval = g_new0 (gchar, ISO_8601_LEN + 1); strftime (retval, ISO_8601_LEN, ISO_8601_FORMAT, gmtime (&(time_->tv_sec))); return retval; } #endif gboolean ck_session_get_idle_since_hint (CkSession *session, char **iso8601_datetime, GError **error) { char *date_str; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); date_str = NULL; if (session->priv->idle_hint) { date_str = _g_time_val_to_iso8601 (&session->priv->idle_since_hint); } if (iso8601_datetime != NULL) { *iso8601_datetime = g_strdup (date_str); } g_free (date_str); return TRUE; } gboolean ck_session_activate (CkSession *session, DBusGMethodInvocation *context) { gboolean res; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); res = FALSE; g_signal_emit (session, signals [ACTIVATE], 0, context, &res); if (! res) { GError *error; /* if the signal is not handled then either: a) aren't attached to seat b) seat doesn't support activation changes */ g_debug ("Activate signal not handled"); error = g_error_new (CK_SESSION_ERROR, CK_SESSION_ERROR_GENERAL, _("Unable to activate session")); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } return TRUE; } gboolean ck_session_set_active (CkSession *session, gboolean active, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (session->priv->active != active) { session->priv->active = active; g_signal_emit (session, signals [ACTIVE_CHANGED], 0, active); } return TRUE; } gboolean ck_session_set_is_local (CkSession *session, gboolean is_local, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (session->priv->is_local != is_local) { session->priv->is_local = is_local; } return TRUE; } gboolean ck_session_get_id (CkSession *session, char **id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (id != NULL) { *id = g_strdup (session->priv->id); } return TRUE; } gboolean ck_session_get_seat_id (CkSession *session, char **id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (id != NULL) { *id = g_strdup (session->priv->seat_id); } return TRUE; } gboolean ck_session_get_unix_user (CkSession *session, guint *uid, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (uid != NULL) { *uid = session->priv->uid; } return TRUE; } /* deprecated */ gboolean ck_session_get_user (CkSession *session, guint *uid, GError **error) { return ck_session_get_unix_user (session, uid, error); } gboolean ck_session_get_x11_display (CkSession *session, char **x11_display, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (x11_display != NULL) { *x11_display = g_strdup (session->priv->x11_display); } return TRUE; } gboolean ck_session_get_display_device (CkSession *session, char **display_device, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (display_device != NULL) { *display_device = g_strdup (session->priv->display_device); } return TRUE; } gboolean ck_session_get_login_session_id (CkSession *session, char **login_session_id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (login_session_id != NULL) { *login_session_id = g_strdup (session->priv->login_session_id); } return TRUE; } gboolean ck_session_get_x11_display_device (CkSession *session, char **x11_display_device, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (x11_display_device != NULL) { *x11_display_device = g_strdup (session->priv->x11_display_device); } return TRUE; } gboolean ck_session_get_remote_host_name (CkSession *session, char **remote_host_name, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (remote_host_name != NULL) { *remote_host_name = g_strdup (session->priv->remote_host_name); } return TRUE; } gboolean ck_session_get_creation_time (CkSession *session, char **iso8601_datetime, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (iso8601_datetime != NULL) { *iso8601_datetime = _g_time_val_to_iso8601 (&session->priv->creation_time); } return TRUE; } gboolean ck_session_get_session_type (CkSession *session, char **type, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (type != NULL) { *type = g_strdup (session->priv->session_type); } return TRUE; } gboolean ck_session_is_active (CkSession *session, gboolean *active, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (active != NULL) { *active = session->priv->active; } return TRUE; } gboolean ck_session_is_local (CkSession *session, gboolean *local, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); if (local != NULL) { *local = session->priv->is_local; } return TRUE; } gboolean ck_session_set_id (CkSession *session, const char *id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->id); session->priv->id = g_strdup (id); return TRUE; } gboolean ck_session_set_cookie (CkSession *session, const char *cookie, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->cookie); session->priv->cookie = g_strdup (cookie); return TRUE; } gboolean ck_session_set_seat_id (CkSession *session, const char *id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->seat_id); session->priv->seat_id = g_strdup (id); return TRUE; } gboolean ck_session_set_unix_user (CkSession *session, guint uid, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); session->priv->uid = uid; return TRUE; } gboolean ck_session_set_x11_display (CkSession *session, const char *x11_display, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->x11_display); session->priv->x11_display = g_strdup (x11_display); return TRUE; } gboolean ck_session_set_display_device (CkSession *session, const char *display_device, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->display_device); session->priv->display_device = g_strdup (display_device); return TRUE; } gboolean ck_session_set_x11_display_device (CkSession *session, const char *x11_display_device, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->x11_display_device); session->priv->x11_display_device = g_strdup (x11_display_device); return TRUE; } gboolean ck_session_set_login_session_id (CkSession *session, const char *login_session_id, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->login_session_id); session->priv->login_session_id = g_strdup (login_session_id); return TRUE; } gboolean ck_session_set_remote_host_name (CkSession *session, const char *remote_host_name, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->remote_host_name); session->priv->remote_host_name = g_strdup (remote_host_name); return TRUE; } gboolean ck_session_set_session_type (CkSession *session, const char *type, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->session_type); session->priv->session_type = g_strdup (type); return TRUE; } static void ck_session_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CkSession *self; self = CK_SESSION (object); switch (prop_id) { case PROP_ACTIVE: ck_session_set_active (self, g_value_get_boolean (value), NULL); break; case PROP_IS_LOCAL: ck_session_set_is_local (self, g_value_get_boolean (value), NULL); break; case PROP_ID: ck_session_set_id (self, g_value_get_string (value), NULL); break; case PROP_COOKIE: ck_session_set_cookie (self, g_value_get_string (value), NULL); break; case PROP_SESSION_TYPE: ck_session_set_session_type (self, g_value_get_string (value), NULL); break; case PROP_X11_DISPLAY: ck_session_set_x11_display (self, g_value_get_string (value), NULL); break; case PROP_X11_DISPLAY_DEVICE: ck_session_set_x11_display_device (self, g_value_get_string (value), NULL); break; case PROP_DISPLAY_DEVICE: ck_session_set_display_device (self, g_value_get_string (value), NULL); break; case PROP_LOGIN_SESSION_ID: ck_session_set_login_session_id (self, g_value_get_string (value), NULL); break; case PROP_UNIX_USER: ck_session_set_unix_user (self, g_value_get_uint (value), NULL); break; case PROP_USER: /* deprecated */ ck_session_set_unix_user (self, g_value_get_uint (value), NULL); break; case PROP_REMOTE_HOST_NAME: ck_session_set_remote_host_name (self, g_value_get_string (value), NULL); break; case PROP_IDLE_HINT: session_set_idle_hint_internal (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ck_session_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CkSession *self; self = CK_SESSION (object); switch (prop_id) { case PROP_ACTIVE: g_value_set_boolean (value, self->priv->active); break; case PROP_IS_LOCAL: g_value_set_boolean (value, self->priv->is_local); break; case PROP_ID: g_value_set_string (value, self->priv->id); break; case PROP_COOKIE: g_value_set_string (value, self->priv->cookie); break; case PROP_SESSION_TYPE: g_value_set_string (value, self->priv->session_type); break; case PROP_X11_DISPLAY: g_value_set_string (value, self->priv->x11_display); break; case PROP_X11_DISPLAY_DEVICE: g_value_set_string (value, self->priv->x11_display_device); break; case PROP_DISPLAY_DEVICE: g_value_set_string (value, self->priv->display_device); break; case PROP_LOGIN_SESSION_ID: g_value_set_string (value, self->priv->login_session_id); break; case PROP_UNIX_USER: g_value_set_uint (value, self->priv->uid); break; case PROP_USER: /* deprecated */ g_value_set_uint (value, self->priv->uid); break; case PROP_REMOTE_HOST_NAME: g_value_set_string (value, self->priv->remote_host_name); break; case PROP_IDLE_HINT: g_value_set_boolean (value, self->priv->idle_hint); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } #define IS_STR_SET(x) (x != NULL && x[0] != '\0') static gboolean session_is_text (CkSession *session) { gboolean ret; ret = FALSE; if (! IS_STR_SET (session->priv->x11_display_device) && ! IS_STR_SET (session->priv->x11_display) && IS_STR_SET (session->priv->display_device)) { ret = TRUE; } g_debug ("Identified session '%s' as %s", session->priv->id, ret ? "text" : "graphical"); return ret; } static void tty_idle_changed_cb (CkTtyIdleMonitor *monitor, gboolean idle_hint, CkSession *session) { session_set_idle_hint_internal (session, idle_hint); } static void session_add_activity_watch (CkSession *session) { if (session->priv->idle_monitor == NULL) { session->priv->idle_monitor = ck_tty_idle_monitor_new (session->priv->display_device); g_signal_connect (session->priv->idle_monitor, "idle-hint-changed", G_CALLBACK (tty_idle_changed_cb), session); } ck_tty_idle_monitor_start (session->priv->idle_monitor); } static void session_remove_activity_watch (CkSession *session) { if (session->priv->idle_monitor == NULL) { return; } ck_tty_idle_monitor_stop (session->priv->idle_monitor); g_object_unref (session->priv->idle_monitor); session->priv->idle_monitor = NULL; } static GObject * ck_session_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CkSession *session; CkSessionClass *klass; klass = CK_SESSION_CLASS (g_type_class_peek (CK_TYPE_SESSION)); session = CK_SESSION (G_OBJECT_CLASS (ck_session_parent_class)->constructor (type, n_construct_properties, construct_properties)); if (session_is_text (session)) { session_add_activity_watch (session); } return G_OBJECT (session); } static void ck_session_class_init (CkSessionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = ck_session_constructor; object_class->get_property = ck_session_get_property; object_class->set_property = ck_session_set_property; object_class->finalize = ck_session_finalize; signals [ACTIVE_CHANGED] = g_signal_new ("active-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, active_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); signals [ACTIVATE] = g_signal_new ("activate", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, activate), NULL, NULL, ck_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); signals [LOCK] = g_signal_new ("lock", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, lock), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [UNLOCK] = g_signal_new ("unlock", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, unlock), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [IDLE_HINT_CHANGED] = g_signal_new ("idle-hint-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, idle_hint_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_object_class_install_property (object_class, PROP_ACTIVE, g_param_spec_boolean ("active", NULL, NULL, FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_IS_LOCAL, g_param_spec_boolean ("is-local", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "id", "id", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_COOKIE, g_param_spec_string ("cookie", "cookie", "cookie", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_SESSION_TYPE, g_param_spec_string ("session-type", "session-type", "session type", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_LOGIN_SESSION_ID, g_param_spec_string ("login-session-id", "login-session-id", "login session id", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_X11_DISPLAY, g_param_spec_string ("x11-display", "x11-display", "X11 Display", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_X11_DISPLAY_DEVICE, g_param_spec_string ("x11-display-device", "x11-display-device", "X11 Display device", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_DISPLAY_DEVICE, g_param_spec_string ("display-device", "display-device", "Display device", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_REMOTE_HOST_NAME, g_param_spec_string ("remote-host-name", "remote-host-name", "Remote host name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_UNIX_USER, g_param_spec_uint ("unix-user", "POSIX User Id", "POSIX User Id", 0, G_MAXINT, 0, G_PARAM_READWRITE)); /* deprecated */ g_object_class_install_property (object_class, PROP_USER, g_param_spec_uint ("user", "User Id", "User Id", 0, G_MAXINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_IDLE_HINT, g_param_spec_boolean ("idle-hint", NULL, NULL, FALSE, G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (CkSessionPrivate)); dbus_g_object_type_install_info (CK_TYPE_SESSION, &dbus_glib_ck_session_object_info); } static void ck_session_init (CkSession *session) { session->priv = CK_SESSION_GET_PRIVATE (session); /* FIXME: should we have a property for this? */ g_get_current_time (&session->priv->creation_time); } static void ck_session_finalize (GObject *object) { CkSession *session; g_return_if_fail (object != NULL); g_return_if_fail (CK_IS_SESSION (object)); session = CK_SESSION (object); g_return_if_fail (session->priv != NULL); session_remove_activity_watch (session); g_object_unref (session->priv->bus_proxy); g_free (session->priv->id); g_free (session->priv->cookie); g_free (session->priv->seat_id); g_free (session->priv->session_type); g_free (session->priv->login_session_id); g_free (session->priv->display_device); g_free (session->priv->x11_display_device); g_free (session->priv->x11_display); g_free (session->priv->remote_host_name); G_OBJECT_CLASS (ck_session_parent_class)->finalize (object); } CkSession * ck_session_new (const char *ssid, const char *cookie) { GObject *object; gboolean res; object = g_object_new (CK_TYPE_SESSION, "id", ssid, "cookie", cookie, NULL); res = register_session (CK_SESSION (object)); if (! res) { g_object_unref (object); return NULL; } return CK_SESSION (object); } #define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \ G_TYPE_STRING, \ G_TYPE_VALUE, \ G_TYPE_INVALID)) CkSession * ck_session_new_with_parameters (const char *ssid, const char *cookie, const GPtrArray *parameters) { GObject *object; gboolean res; int i; GParameter *params; guint n_allocated_params; guint n_params; GObjectClass *class; GType object_type; object_type = CK_TYPE_SESSION; class = g_type_class_ref (object_type); n_allocated_params = 2; if (parameters != NULL) { n_allocated_params += parameters->len; } params = g_new0 (GParameter, n_allocated_params); n_params = 0; params[n_params].name = g_strdup ("id"); params[n_params].value.g_type = 0; g_value_init (¶ms[n_params].value, G_TYPE_STRING); g_value_set_string (¶ms[n_params].value, ssid); n_params++; params[n_params].name = g_strdup ("cookie"); params[n_params].value.g_type = 0; g_value_init (¶ms[n_params].value, G_TYPE_STRING); g_value_set_string (¶ms[n_params].value, cookie); n_params++; if (parameters != NULL) { for (i = 0; i < parameters->len; i++) { gboolean res; GValue val_struct = { 0, }; char *prop_name; GValue *prop_val; GParamSpec *pspec; g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT); g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i)); res = dbus_g_type_struct_get (&val_struct, 0, &prop_name, 1, &prop_val, G_MAXUINT); if (! res) { g_debug ("Unable to extract parameter input"); goto cont; } if (prop_name == NULL) { g_debug ("Skipping NULL parameter"); goto cont; } if (strcmp (prop_name, "id") == 0 || strcmp (prop_name, "cookie") == 0) { g_debug ("Skipping restricted parameter: %s", prop_name); goto cont; } pspec = g_object_class_find_property (class, prop_name); if (! pspec) { g_debug ("Skipping unknown parameter: %s", prop_name); goto cont; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_debug ("property '%s' is not writable", pspec->name); goto cont; } params[n_params].name = g_strdup (prop_name); params[n_params].value.g_type = 0; g_value_init (¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec)); res = g_value_transform (prop_val, ¶ms[n_params].value); if (! res) { g_debug ("unable to transform property value for '%s'", pspec->name); goto cont; } n_params++; cont: g_free (prop_name); if (prop_val != NULL) { g_value_unset (prop_val); g_free (prop_val); } } } object = g_object_newv (object_type, n_params, params); while (n_params--) { g_free ((char *)params[n_params].name); g_value_unset (¶ms[n_params].value); } g_free (params); g_type_class_unref (class); res = register_session (CK_SESSION (object)); if (! res) { g_object_unref (object); return NULL; } return CK_SESSION (object); } void ck_session_run_programs (CkSession *session, const char *action) { int n; char *extra_env[11]; /* be sure to adjust this as needed */ n = 0; extra_env[n++] = g_strdup_printf ("CK_SESSION_ID=%s", session->priv->id); if (session->priv->session_type != NULL) { extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", session->priv->session_type); } extra_env[n++] = g_strdup_printf ("CK_SESSION_SEAT_ID=%s", session->priv->seat_id); extra_env[n++] = g_strdup_printf ("CK_SESSION_USER_UID=%d", session->priv->uid); if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_DEVICE=%s", session->priv->display_device); } if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY_DEVICE=%s", session->priv->x11_display_device); } extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY=%s", session->priv->x11_display ? session->priv->x11_display : ""); if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_REMOTE_HOST_NAME=%s", session->priv->remote_host_name); } extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_ACTIVE=%s", session->priv->active ? "true" : "false"); extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_LOCAL=%s", session->priv->is_local ? "true" : "false"); extra_env[n++] = NULL; g_assert(n <= G_N_ELEMENTS(extra_env)); ck_run_programs (SYSCONFDIR "/ConsoleKit/run-session.d", action, extra_env); ck_run_programs (PREFIX "/lib/ConsoleKit/run-session.d", action, extra_env); for (n = 0; extra_env[n] != NULL; n++) { g_free (extra_env[n]); } } void ck_session_dump (CkSession *session, GKeyFile *key_file) { char *s; char *group_name; group_name = g_strdup_printf ("Session %s", session->priv->id); g_key_file_set_integer (key_file, group_name, "uid", session->priv->uid); g_key_file_set_string (key_file, group_name, "seat", NONULL_STRING (session->priv->seat_id)); if (session->priv->session_type != NULL) { g_key_file_set_string (key_file, group_name, "type", NONULL_STRING (session->priv->session_type)); } if (session->priv->login_session_id != NULL && strlen (session->priv->login_session_id) > 0) { g_key_file_set_string (key_file, group_name, "login_session_id", NONULL_STRING (session->priv->login_session_id)); } if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) { g_key_file_set_string (key_file, group_name, "display_device", NONULL_STRING (session->priv->display_device)); } if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) { g_key_file_set_string (key_file, group_name, "x11_display_device", NONULL_STRING (session->priv->x11_display_device)); } if (session->priv->x11_display != NULL && strlen (session->priv->x11_display) > 0) { g_key_file_set_string (key_file, group_name, "x11_display", NONULL_STRING (session->priv->x11_display)); } if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) { g_key_file_set_string (key_file, group_name, "remote_host_name", NONULL_STRING (session->priv->remote_host_name)); } g_key_file_set_string (key_file, group_name, "remote_host_name", NONULL_STRING (session->priv->remote_host_name)); g_key_file_set_boolean (key_file, group_name, "is_active", session->priv->active); g_key_file_set_boolean (key_file, group_name, "is_local", session->priv->is_local); s = g_time_val_to_iso8601 (&(session->priv->creation_time)); g_key_file_set_string (key_file, group_name, "creation_time", NONULL_STRING (s)); g_free (s); g_free (group_name); }