/* -*- 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 #ifdef HAVE_SYS_VT_H #include #endif #ifdef HAVE_SYS_KD_H #include #endif #ifdef HAVE_SYS_CONSIO_H #include #endif #ifdef HAVE_SYS_KBIO_H #include #endif #include #include #include #include #include #include #include "ck-tty-idle-monitor.h" #include "ck-session.h" #include "ck-seat.h" #include "ck-marshal.h" #include "ck-run-programs.h" #include "ck-sysdeps.h" #include "ck-device.h" #define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate)) #define CK_SESSION_DBUS_NAME "org.freedesktop.ConsoleKit.Session" #define NONULL_STRING(x) ((x) != NULL ? (x) : "") #define IDLE_TIME_SECS 60 #ifndef KDSKBMUTE #define KDSKBMUTE 0x4B51 #endif #ifdef K_OFF #define KBD_OFF_MODE K_OFF #else #define KBD_OFF_MODE K_RAW #endif struct CkSessionPrivate { char *id; char *cookie; char *seat_id; char *runtime_dir; char *login_session_id; gchar *session_controller; guint session_controller_watchid; GList *devices; guint pause_devices_timer; gint tty_fd; gint old_kbd_mode; guint sig_watch_s1; guint sig_watch_s2; GTimeVal creation_time; CkTtyIdleMonitor *idle_monitor; GTimeVal idle_since_hint; GDBusConnection *connection; GDBusProxy *bus_proxy; }; enum { ACTIVATE, LAST_SIGNAL }; /* Private properties not exported over D-BUS */ enum { PROP_0, PROP_ID, PROP_COOKIE, PROP_LOGIN_SESSION_ID, PROP_SESSION_CONTROLLER, }; 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_iface_init (ConsoleKitSessionIface *iface); static void ck_session_finalize (GObject *object); static void ck_session_remove_all_devices (CkSession *session); G_DEFINE_TYPE_WITH_CODE (CkSession, ck_session, CONSOLE_KIT_TYPE_SESSION_SKELETON, G_IMPLEMENT_INTERFACE (CONSOLE_KIT_TYPE_SESSION, ck_session_iface_init)); static const GDBusErrorEntry ck_session_error_entries[] = { { CK_SESSION_ERROR_FAILED, CK_SESSION_DBUS_NAME ".Error.Failed" }, { CK_SESSION_ERROR_GENERAL, CK_SESSION_DBUS_NAME ".Error.General" }, { CK_SESSION_ERROR_INSUFFICIENT_PERMISSION, CK_SESSION_DBUS_NAME ".Error.InsufficientPermission" }, { CK_SESSION_ERROR_NOT_SUPPORTED, CK_SESSION_DBUS_NAME ".Error.NotSupported" }, { CK_SESSION_ERROR_ALREADY_ACTIVE, CK_SESSION_DBUS_NAME ".Error.AlreadyActive" } }; GQuark ck_session_error_quark (void) { static volatile gsize quark_volatile = 0; g_dbus_error_register_error_domain ("ck_session_error", &quark_volatile, ck_session_error_entries, G_N_ELEMENTS (ck_session_error_entries)); return (GQuark) quark_volatile; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType ck_session_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CK_SESSION_ERROR_FAILED, "Failed"), ENUM_ENTRY (CK_SESSION_ERROR_GENERAL, "General"), ENUM_ENTRY (CK_SESSION_ERROR_INSUFFICIENT_PERMISSION, "InsufficientPermission"), ENUM_ENTRY (CK_SESSION_ERROR_NOT_SUPPORTED, "NotSupported"), ENUM_ENTRY (CK_SESSION_ERROR_ALREADY_ACTIVE, "AlreadyActive"), { 0, 0, 0 } }; g_assert (CK_SESSION_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("Error", values); } return etype; } static void throw_error (GDBusMethodInvocation *context, gint error_code, const gchar *format, ...) { va_list args; gchar *message; va_start (args, format); message = g_strdup_vprintf (format, args); va_end (args); g_debug ("session: throwing error: %s", message); g_dbus_method_invocation_return_error (context, CK_SESSION_ERROR, error_code, "%s", message); g_free (message); } static gboolean register_session (CkSession *session, GDBusConnection *connection) { GError *error = NULL; g_debug ("register session"); error = NULL; if (connection == NULL) { g_critical ("CkSession-register_session:connection == NULL"); } else { session->priv->connection = connection; } if (session->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } return FALSE; } g_debug ("exporting path %s", session->priv->id); if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (CONSOLE_KIT_SESSION (session)), session->priv->connection, session->priv->id, &error)) { if (error != NULL) { g_critical ("error exporting interface: %s", error->message); g_error_free (error); return FALSE; } } g_debug ("exported on %s", g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (CONSOLE_KIT_SESSION (session)))); /* connect to DBus for get_caller_info */ session->priv->bus_proxy = g_dbus_proxy_new_sync (session->priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, "org.freedesktop.DBus", "/org/freedesktop/DBus/Bus", "org.freedesktop.DBus", NULL, &error); if (session->priv->bus_proxy == NULL) { g_warning ("cannot connect to DBus: %s", error->message); g_error_free (error); } /* default to unspecified for the session type on startup */ console_kit_session_set_session_type (CONSOLE_KIT_SESSION (session), "unspecified"); return TRUE; } /* lock and unlock are separate functions because we may want security policy to be handled separately */ void ck_session_lock (CkSession *session) { ConsoleKitSession *cksession; TRACE (); g_return_if_fail (CK_IS_SESSION (session)); cksession = CONSOLE_KIT_SESSION (session); g_debug ("Emitting lock for session %s", session->priv->id); console_kit_session_set_locked_hint (cksession, TRUE); console_kit_session_emit_lock (cksession); } void ck_session_unlock (CkSession *session) { ConsoleKitSession *cksession; TRACE (); g_return_if_fail (CK_IS_SESSION (session)); cksession = CONSOLE_KIT_SESSION (session); g_debug ("Emitting unlock for session %s", session->priv->id); console_kit_session_set_locked_hint (cksession, FALSE); console_kit_session_emit_unlock (cksession); } static gboolean dbus_lock (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); ck_session_lock (CK_SESSION (cksession)); console_kit_session_complete_lock (cksession, context); return TRUE; } static gboolean dbus_unlock (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); ck_session_unlock (CK_SESSION (cksession)); console_kit_session_complete_unlock (cksession, 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 = FALSE; GVariant *value = NULL; GError *error = NULL; if (sender == NULL) { goto out; } value = g_dbus_proxy_call_sync (session->priv->bus_proxy, "GetConnectionUnixUser", g_variant_new ("(s)", sender), G_DBUS_CALL_FLAGS_NONE, 2000, NULL, &error); if (value == NULL) { g_warning ("GetConnectionUnixUser() failed: %s", error->message); g_error_free (error); goto out; } g_variant_get (value, "(u)", calling_uid); g_variant_unref (value); value = g_dbus_proxy_call_sync (session->priv->bus_proxy, "GetConnectionUnixProcessID", g_variant_new ("(s)", sender), G_DBUS_CALL_FLAGS_NONE, 2000, NULL, &error); if (value == NULL) { g_warning ("GetConnectionUnixProcessID() failed: %s", error->message); g_error_free (error); goto out; } g_variant_get (value, "(u)", calling_pid); g_variant_unref (value); 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) { ConsoleKitSession *cksession = CONSOLE_KIT_SESSION (session); if (console_kit_session_get_idle_hint (cksession) != idle_hint) { console_kit_session_set_idle_hint (cksession, 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); console_kit_session_emit_idle_hint_changed (cksession, idle_hint); } return TRUE; } static gboolean dbus_get_idle_since_hint (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { CkSession *session = CK_SESSION(cksession); char *date_str; TRACE (); g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE); if (console_kit_session_get_idle_hint (cksession) == FALSE) { throw_error (context, CK_SESSION_ERROR_GENERAL, "idle since hint not set"); return TRUE; } date_str = g_time_val_to_iso8601 (&session->priv->idle_since_hint); console_kit_session_complete_get_idle_since_hint (cksession, context, date_str); g_free (date_str); return TRUE; } static gboolean dbus_get_idle_hint (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_get_idle_hint (cksession, context, console_kit_session_get_idle_hint (cksession)); 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 */ static gboolean dbus_set_idle_hint (ConsoleKitSession *cksession, GDBusMethodInvocation *context, gboolean idle_hint) { const char *sender; uid_t calling_uid = 0; pid_t calling_pid = 0; gboolean res; CkSession *session; TRACE (); g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE); session = CK_SESSION(cksession); sender = g_dbus_method_invocation_get_sender (context); res = get_caller_info (session, sender, &calling_uid, &calling_pid); if (! res) { g_warning ("stat on pid %d failed", calling_pid); throw_error (context, CK_SESSION_ERROR_FAILED, _("Unable to lookup information about calling process '%d'"), calling_pid); return TRUE; } /* only restrict this by UID for now */ if (console_kit_session_get_unix_user (cksession) != calling_uid) { throw_error (context, CK_SESSION_ERROR_INSUFFICIENT_PERMISSION, _("Only session owner may set idle hint state")); return TRUE; } session_set_idle_hint_internal (session, idle_hint); console_kit_session_complete_set_idle_hint (cksession, context); 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.SetLockedHint boolean:TRUE */ static gboolean dbus_set_locked_hint (ConsoleKitSession *cksession, GDBusMethodInvocation *context, gboolean arg_locked_hint) { const char *sender; uid_t calling_uid = 0; pid_t calling_pid = 0; gboolean res; CkSession *session; TRACE (); g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE); session = CK_SESSION(cksession); sender = g_dbus_method_invocation_get_sender (context); res = get_caller_info (session, sender, &calling_uid, &calling_pid); if (! res) { g_warning ("stat on pid %d failed", calling_pid); throw_error (context, CK_SESSION_ERROR_FAILED, _("Unable to lookup information about calling process '%d'"), calling_pid); return TRUE; } /* only restrict this by UID for now */ if (console_kit_session_get_unix_user (cksession) != calling_uid) { throw_error (context, CK_SESSION_ERROR_INSUFFICIENT_PERMISSION, _("Only session owner may set locked hint state")); return TRUE; } console_kit_session_set_locked_hint (cksession, arg_locked_hint); console_kit_session_complete_set_idle_hint (cksession, context); return TRUE; } static gboolean dbus_get_session_type (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { const gchar *session_type = console_kit_session_get_session_type (cksession); TRACE (); if (session_type == NULL) { /* default to unspecified */ session_type = "unspecified"; } console_kit_session_complete_get_session_type (cksession, context, session_type); return TRUE; } static void ck_session_print_list_size (CkSession *session) { #if defined(CONSOLEKIT_DEBUGGING) g_debug ("session %s list size is %d", session->priv->id, g_list_length (session->priv->devices)); #endif } static void ck_session_check_paused_devices (CkSession *session) { ConsoleKitSession *cksession = CONSOLE_KIT_SESSION (session); GList *itr; TRACE (); ck_session_print_list_size (session); /* See if we've paused all the devices in the session */ for (itr = session->priv->devices; itr != NULL; itr = g_list_next (itr)) { CkDevice *device = CK_DEVICE (itr->data); if (ck_device_get_active (device)) { return; } } /* If we didn't force the state change, do it now */ if (console_kit_session_get_active (cksession) != FALSE) { g_debug ("marking session %s inactive", session->priv->id); console_kit_session_set_active (cksession, FALSE); console_kit_session_emit_active_changed (cksession, FALSE); } if (session->priv->pause_devices_timer != 0) { g_source_remove (session->priv->pause_devices_timer); session->priv->pause_devices_timer = 0; } } static gboolean force_pause_devices (CkSession *session) { GList *itr; TRACE (); ck_session_print_list_size (session); for (itr = session->priv->devices; itr != NULL; itr = g_list_next (itr)) { ck_device_set_active (CK_DEVICE (itr->data), FALSE); } session->priv->pause_devices_timer = 0; ck_session_check_paused_devices (session); return FALSE; } static void ck_session_pause_all_devices (CkSession *session, gboolean force) { ConsoleKitSession *cksession = CONSOLE_KIT_SESSION (session); GList *itr; TRACE (); ck_session_print_list_size (session); for (itr = session->priv->devices; itr != NULL; itr = g_list_next (itr)) { CkDevice *device = CK_DEVICE (itr->data); if (ck_device_get_active (device) == FALSE) { g_debug ("device already paused"); continue; } /* Let the session controller know about the change */ g_debug ("emit pause device for %d, %d, type %s", ck_device_get_major (device), ck_device_get_minor (device), force ? "force" : "pause"); console_kit_session_emit_pause_device (CONSOLE_KIT_SESSION (session), ck_device_get_major (device), ck_device_get_minor (device), force ? "force" : "pause"); if (force) { ck_device_set_active (device, FALSE); } } if (force || session->priv->devices == NULL) { g_debug ("marking session %s inactive", session->priv->id); console_kit_session_set_active (cksession, FALSE); console_kit_session_emit_active_changed (cksession, FALSE); } else { session->priv->pause_devices_timer = g_timeout_add_seconds (3, (GSourceFunc)force_pause_devices, session); } } static void ck_session_debug_print_dbus_message (CkSession *session, GDBusMessage *message) { #if defined(CONSOLEKIT_DEBUGGING) gchar *string = g_dbus_message_print (message, 4); gchar **split_string = g_strsplit (string, "\n", 0); gint i; for (i = 0; split_string != NULL && split_string[i] != NULL; i++) { g_debug ("%s", split_string[i]); } g_strfreev (split_string); g_free (string); #endif } static void ck_session_resume_all_devices (CkSession *session) { ConsoleKitSession *cksession = CONSOLE_KIT_SESSION (session); GList *itr; gint vtnr; TRACE (); vtnr = console_kit_session_get_vtnr (cksession); /* Give ownership of the active console device to the user */ if (vtnr > 0) { struct passwd *pwent; gint fd; gint uid; uid = console_kit_session_get_unix_user (cksession); fd = ck_open_a_console (ck_get_console_device_for_num (vtnr)); if (fd >= 0) { errno = 0; pwent = getpwuid (uid); if (pwent == NULL) { g_warning ("Unable to lookup UID: %s", g_strerror (errno)); errno = 0; } else { if (fchown (fd, uid, pwent->pw_gid) != 0) { g_warning ("Failed to chown console device, reason was: %s", strerror(errno)); errno = 0; } } g_close (fd, NULL); } } /* without a controller, we just mark ourselved active */ if (session->priv->session_controller == NULL) { g_debug ("no session controller: marking session active"); console_kit_session_set_active (cksession, TRUE); console_kit_session_emit_active_changed (cksession, TRUE); return; } ck_session_print_list_size (session); for (itr = session->priv->devices; itr != NULL; itr = g_list_next (itr)) { CkDevice *device = CK_DEVICE (itr->data); GVariant *body; GDBusMessage *message; GUnixFDList *out_fd_list = NULL; gint fd = -1; gint fd2 = -1; ck_device_set_active (device, TRUE); fd = ck_device_get_fd (device); if (fd < 0) { g_debug ("Unable to signal ResumeDevice, failed to get device"); continue; } message = g_dbus_message_new_signal (session->priv->id, CK_SESSION_DBUS_NAME, "ResumeDevice"); /* We always send to the session controller */ g_dbus_message_set_destination (message, session->priv->session_controller); body = g_variant_new ("(uu@h)", ck_device_get_major (device), ck_device_get_minor (device), g_variant_new_handle (0)); g_dbus_message_set_body (message, body); /* we need to copy this, because gdbus closes the fd on us */ fd2 = dup (fd); out_fd_list = g_unix_fd_list_new_from_array (&fd2, 1); g_dbus_message_set_unix_fd_list (message, out_fd_list); g_debug ("sending ResumeDevice signal to session controller"); ck_session_debug_print_dbus_message (session, message); /* Let only the session controller know about the change and * give them the new fd. */ g_dbus_connection_send_message (session->priv->connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL); g_clear_object (&out_fd_list); g_clear_object (&message); } g_debug ("marking session active"); console_kit_session_set_active (cksession, TRUE); console_kit_session_emit_active_changed (cksession, TRUE); } gboolean ck_session_set_active (CkSession *session, gboolean active, gboolean force) { ConsoleKitSession *cksession; TRACE (); g_return_val_if_fail (CK_IS_SESSION (session), FALSE); cksession = CONSOLE_KIT_SESSION (session); if (console_kit_session_get_active (cksession) == active) { /* redundant call, we shouldn't need to do anything */ return TRUE; } if (session->priv->pause_devices_timer != 0) { g_source_remove (session->priv->pause_devices_timer); session->priv->pause_devices_timer = 0; } g_debug ("ck_session_set_active: session %s changing to %s, forced? %s", session->priv->id, active ? "active" : "not active", force ? "yes" : "no"); /* We handle device events then change the active state */ if (active == FALSE) { ck_session_pause_all_devices (session, force); } else { ck_session_resume_all_devices (session); } return TRUE; } static gboolean dbus_is_active (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_is_active (cksession, context, console_kit_session_get_active (cksession)); return TRUE; } static gboolean dbus_activate (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { GError *error = NULL; GError *initial_error; CkSession *session = CK_SESSION (cksession); TRACE (); g_return_val_if_fail (session, FALSE); /* Set an initial error message in the event the signal isn't handeled */ g_set_error (&error, CK_SESSION_ERROR, CK_SESSION_ERROR_NOT_SUPPORTED, _("Activate signal not handeled. Session not attached to seat, or the seat doesn't support activation changes")); /* keep track of the starting error because the call to g_signal_emit * may change it and we still need to free it */ initial_error = error; g_signal_emit (session, signals [ACTIVATE], 0, context, &error); if (error != NULL) { /* if the signal is not handled then either: a) aren't attached to seat b) seat doesn't support activation changes */ g_debug ("Got error message: %s", error->message); /* translate and throw the error */ switch (error->code) { case CK_SEAT_ERROR_ALREADY_ACTIVE: /* Don't care */ break; case CK_SEAT_ERROR_NOT_SUPPORTED: throw_error (context, CK_SESSION_ERROR_NOT_SUPPORTED, error->message); break; default: throw_error (context, CK_SESSION_ERROR_GENERAL, error->message); } g_clear_error (&error); g_clear_error (&initial_error); return TRUE; } g_clear_error (&initial_error); console_kit_session_complete_activate (cksession, context); return TRUE; } static gboolean dbus_get_id (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { CkSession *session = CK_SESSION (cksession); gchar *id; TRACE (); g_return_val_if_fail (CK_IS_SESSION (session), FALSE); id = session->priv->id; if (id == NULL) { id = ""; } console_kit_session_complete_get_id (cksession, context, session->priv->id); 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; } static gboolean dbus_get_seat_id (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { CkSession *session = CK_SESSION (cksession); const gchar *seat_id; TRACE (); g_return_val_if_fail (CK_IS_SESSION (session), FALSE); seat_id = session->priv->seat_id; if (seat_id == NULL) { throw_error (context, CK_SESSION_ERROR_FAILED, "session not attached to a seat"); return TRUE; } console_kit_session_complete_get_seat_id (cksession, context, session->priv->seat_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; } static gboolean dbus_get_user (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_get_unix_user (cksession, context, console_kit_session_get_unix_user (cksession)); return TRUE; } static gboolean dbus_get_unix_user (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_get_unix_user (cksession, context, console_kit_session_get_unix_user (cksession)); return TRUE; } gboolean ck_session_set_unix_user (CkSession *session, guint uid, GError **error) { g_return_val_if_fail (CK_IS_SESSION (session), FALSE); console_kit_session_set_unix_user (CONSOLE_KIT_SESSION (session), uid); return TRUE; } static gboolean dbus_get_x11_display (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { const gchar *x11_display; TRACE (); x11_display = console_kit_session_get_x11_display (cksession); if (x11_display == NULL) { x11_display = ""; } console_kit_session_complete_get_x11_display (cksession, context, x11_display); 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); console_kit_session_set_x11_display (CONSOLE_KIT_SESSION (session), x11_display); return TRUE; } static gboolean dbus_get_display_device (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { const gchar *display_device; TRACE (); display_device = console_kit_session_get_display_device (cksession); if (display_device == NULL) { display_device = ""; } console_kit_session_complete_get_x11_display_device (cksession, context, display_device); return TRUE; } gboolean ck_session_set_display_device (CkSession *session, const char *display_device, GError **error) { ConsoleKitSession *cksession; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); cksession = CONSOLE_KIT_SESSION (session); console_kit_session_set_display_device (cksession, display_device); return TRUE; } static gboolean dbus_get_x11_display_device (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { const gchar *x11_display_device; TRACE (); x11_display_device = console_kit_session_get_x11_display_device (cksession); if (x11_display_device == NULL) { x11_display_device = ""; } console_kit_session_complete_get_x11_display_device (cksession, context, x11_display_device); return TRUE; } gboolean ck_session_set_x11_display_device (CkSession *session, const char *x11_display_device, GError **error) { ConsoleKitSession *cksession; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); cksession = CONSOLE_KIT_SESSION (session); console_kit_session_set_x11_display_device (cksession, x11_display_device); return TRUE; } static gboolean dbus_get_remote_host_name (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { const gchar *remote_host_name = console_kit_session_get_remote_host_name (cksession); TRACE (); if (remote_host_name == NULL) { remote_host_name = ""; } console_kit_session_complete_get_remote_host_name (cksession, context, remote_host_name); return TRUE; } gboolean ck_session_set_remote_host_name (CkSession *session, const char *remote_host_name, GError **error) { ConsoleKitSession *cksession; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); cksession = CONSOLE_KIT_SESSION (session); console_kit_session_set_remote_host_name (cksession, remote_host_name); return TRUE; } static gboolean dbus_get_creation_time (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { CkSession *session = CK_SESSION(cksession); TRACE (); g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE); console_kit_session_complete_get_creation_time (cksession, context, g_time_val_to_iso8601 (&session->priv->creation_time)); 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; } static gboolean dbus_is_local (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_is_local (cksession, context, console_kit_session_get_is_local (cksession)); 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); console_kit_session_set_is_local (CONSOLE_KIT_SESSION (session), is_local); 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 = console_kit_session_get_is_local (CONSOLE_KIT_SESSION (session)); } 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) { GVariant *seat = NULL; g_return_val_if_fail (CK_IS_SESSION (session), FALSE); g_free (session->priv->seat_id); session->priv->seat_id = g_strdup (id); if (id != NULL) { seat = g_variant_new ("(so)", id, id); } console_kit_session_set_seat (CONSOLE_KIT_SESSION (session), seat); 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 TRUE; } 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) { CkSession *session = CK_SESSION(cksession); const gchar *login_session_id; TRACE (); g_return_val_if_fail (CK_IS_SESSION (cksession), FALSE); login_session_id = session->priv->login_session_id; /* if no login session id is set return an empty string */ if (login_session_id == NULL) { login_session_id = ""; } console_kit_session_complete_get_login_session_id (cksession, context, login_session_id); return TRUE; } static gboolean dbus_get_vtnr (ConsoleKitSession *cksession, GDBusMethodInvocation *context) { TRACE (); console_kit_session_complete_get_vtnr (cksession, context, console_kit_session_get_vtnr (cksession)); 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_session_type (CkSession *session, const char *type, GError **error) { ConsoleKitSession *cksession = CONSOLE_KIT_SESSION (session); g_return_val_if_fail (CK_IS_SESSION (session), FALSE); console_kit_session_set_session_type (cksession, type); return TRUE; } static gboolean vt_leave_handler (gpointer data) { CkSession *session = CK_SESSION (data); TRACE (); /* g_unix_signal_add_full returns this callback in the GMainContext * so we don't have the limitations of POSIX signal handlers */ /* Forcably disable all devices, we have to do this * now or we'll crash Xorg if it's running as root on * the new VT */ ck_session_pause_all_devices (session, TRUE); /* release control */ ioctl (session->priv->tty_fd, VT_RELDISP, 1); return TRUE; } static gboolean vt_acquire_handler (gpointer data) { CkSession *session = CK_SESSION (data); TRACE (); /* g_unix_signal_add_full returns this callback in the GMainContext * so we don't have the limitations of POSIX signal handlers */ /* ack that we are getting control, but let the normal * process handle granting access */ ioctl (session->priv->tty_fd, VT_RELDISP, VT_ACKACQ); return TRUE; } static void ck_session_setup_vt_signal (CkSession *session, guint vtnr) { struct vt_mode mode = { 0 }; int graphical_mode; session->priv->tty_fd = ck_open_a_console (ck_get_console_device_for_num (vtnr)); if (session->priv->tty_fd < 0) { return; } ioctl(session->priv->tty_fd, KDGKBMODE, &session->priv->old_kbd_mode); /* So during setup here, we need to ensure we're in graphical mode, * otherwise it will try to draw stuff in the background */ if (ioctl (session->priv->tty_fd, KDGETMODE, &graphical_mode) != 0) { g_warning ("failed to get current VT mode"); return; } if (graphical_mode == KD_TEXT) { if (ioctl (session->priv->tty_fd, KDSETMODE, KD_GRAPHICS) != 0) { g_warning ("failed to change VT to graphical mode"); return; } } else { g_debug ("already running in graphical mode? not messing with the tty or VT"); return; } #if defined(__linux__) if (ioctl (session->priv->tty_fd, KDSKBMUTE, 1) != 0) { g_warning ("failed to mute FD with KDSKBMUTE"); } #endif if (ioctl (session->priv->tty_fd, KDSKBMODE, KBD_OFF_MODE) != 0) { g_warning ("failed to turn off keyboard"); } mode.mode = VT_PROCESS; mode.relsig = SIGUSR1; mode.acqsig = SIGUSR2; mode.frsig = SIGIO; /* not used, but has to be set anyway */ if (ioctl (session->priv->tty_fd, VT_SETMODE, &mode) < 0) { g_warning ("failed to take control of vt handling"); return; } session->priv->sig_watch_s1 = g_unix_signal_add_full (G_PRIORITY_HIGH, SIGUSR1, (GSourceFunc)vt_leave_handler, session, NULL); session->priv->sig_watch_s2 = g_unix_signal_add_full (G_PRIORITY_HIGH, SIGUSR2, (GSourceFunc)vt_acquire_handler, session, NULL); } static void session_controller_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { CkSession *session = CK_SESSION (user_data); TRACE (); session->priv->session_controller_watchid = 0; ck_session_set_session_controller (session, NULL); } static void ck_session_controller_cleanup (CkSession *session) { TRACE (); if (session->priv->session_controller_watchid != 0) { g_bus_unwatch_name (session->priv->session_controller_watchid); session->priv->session_controller_watchid = 0; } if (session->priv->pause_devices_timer != 0) { g_source_remove (session->priv->pause_devices_timer); session->priv->pause_devices_timer = 0; } if (session->priv->session_controller) { g_free (session->priv->session_controller); session->priv->session_controller = NULL; } ck_session_remove_all_devices (session); /* Remove the old signal call backs, restore VT switching to auto * and text mode (put it back the way we found it) */ if (session->priv->sig_watch_s1 != 0) { struct vt_mode mode = { 0 }; mode.mode = VT_AUTO; #if defined(__linux__) if (ioctl (session->priv->tty_fd, KDSKBMUTE, 0) != 0) { g_warning ("failed to unmute FD with KDSKBMUTE"); } #endif if (ioctl(session->priv->tty_fd, KDSKBMODE, session->priv->old_kbd_mode) != 0) { g_warning ("failed to restore old keyboard mode"); } if (ioctl (session->priv->tty_fd, VT_SETMODE, &mode) < 0) { g_warning ("failed to return control of vt handling"); } if (ioctl (session->priv->tty_fd, KDSETMODE, KD_TEXT) < 0) { g_warning ("failed to return to text mode for the VT"); } g_source_remove (session->priv->sig_watch_s1); session->priv->sig_watch_s1 = 0; g_source_remove (session->priv->sig_watch_s2); session->priv->sig_watch_s2 = 0; } /* Close the old tty fd */ if (session->priv->tty_fd != -1) { g_close (session->priv->tty_fd, NULL); session->priv->tty_fd = -1; } } void ck_session_set_session_controller (CkSession *session, const gchar *bus_name) { guint vtnr; TRACE (); /* clean up after the old controller */ ck_session_controller_cleanup (session); /* There's no reason to go further if we're removing the session * controller */ if (bus_name == NULL) { return; } session->priv->session_controller = g_strdup (bus_name); /* if the session controller crashes or exits, we need to drop access * to all the devices it requested and let someone else become the * session controller. */ session->priv->session_controller_watchid = g_bus_watch_name_on_connection (session->priv->connection, bus_name, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, session_controller_vanished, session, NULL); vtnr = console_kit_session_get_vtnr (CONSOLE_KIT_SESSION (session)); if (vtnr > 0) { ck_session_setup_vt_signal (session, vtnr); } } static gboolean dbus_take_control (ConsoleKitSession *object, GDBusMethodInvocation *invocation, gboolean arg_force) { CkSession *session = CK_SESSION (object); uid_t uid = 0; pid_t pid = 0; const gchar *sender = g_dbus_method_invocation_get_sender (invocation); TRACE (); if (!ck_device_is_server_managed ()) { throw_error (invocation, CK_SESSION_ERROR_NOT_SUPPORTED, _("Server managed devices not supported")); return TRUE; } if (!get_caller_info (session, sender, &uid, &pid)) { throw_error (invocation, CK_SESSION_ERROR_GENERAL, _("Failed to get uid of dbus caller")); return TRUE; } if (g_strcmp0 (session->priv->session_controller, sender) == 0) { /* The current session controller is trying to take control * again? Odd, but we'll just do nothing here. */ } else if (session->priv->session_controller == NULL || (arg_force == TRUE && uid == 0)) { ck_session_set_session_controller (CK_SESSION (session), sender); } else { if (arg_force == TRUE) { throw_error (invocation, CK_SESSION_ERROR_INSUFFICIENT_PERMISSION, _("Failed to replace the current session controller")); } else { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Session controller already present")); } return TRUE; } console_kit_session_complete_take_control (object, invocation); return TRUE; } static gboolean dbus_release_control (ConsoleKitSession *object, GDBusMethodInvocation *invocation) { CkSession *session = CK_SESSION (object); const gchar *sender = g_dbus_method_invocation_get_sender (invocation); TRACE (); /* only the session controller can release it */ if (g_strcmp0 (session->priv->session_controller, sender) == 0) { ck_session_set_session_controller (CK_SESSION (object), NULL); } else { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Only the session controller may use this function")); return TRUE; } console_kit_session_complete_release_control (object, invocation); return TRUE; } static CkDevice* ck_session_get_device (CkSession *session, guint major, guint minor) { GList *iter; TRACE (); ck_session_print_list_size (session); for (iter = session->priv->devices; iter != NULL; iter = g_list_next (iter)) { if (ck_device_compare (iter->data, major, minor)) { g_debug ("found device"); return iter->data; } } g_debug ("failed to find deivce"); return NULL; } static CkDevice* ck_session_create_device (CkSession *session, guint major, guint minor) { CkDevice *device = ck_session_get_device (session, major, minor); /* If the device already exists for this session don't * create it again */ if (device == NULL) { g_debug ("creating new device"); device = ck_device_new (major, minor, console_kit_session_get_active (CONSOLE_KIT_SESSION (session))); if (device != NULL && CK_IS_DEVICE (device)) { g_debug ("adding device to the list"); session->priv->devices = g_list_prepend (session->priv->devices, device); ck_session_print_list_size (session); } } return device; } static void ck_session_remove_device (CkSession *session, CkDevice *device) { TRACE (); ck_session_print_list_size (session); session->priv->devices = g_list_remove (session->priv->devices, device); ck_session_print_list_size (session); } static void ck_session_remove_all_devices (CkSession *session) { TRACE (); ck_session_print_list_size (session); g_list_free_full (session->priv->devices, g_object_unref); session->priv->devices = NULL; g_debug ("list size is now 0"); } static gboolean dbus_take_device (ConsoleKitSession *object, GDBusMethodInvocation *invocation, GUnixFDList *fd_list, guint arg_major, guint arg_minor) { CkSession *session = CK_SESSION (object); CkDevice *device; const gchar *sender = g_dbus_method_invocation_get_sender (invocation); gint fd = -1; GUnixFDList *out_fd_list = NULL; TRACE (); /* only the session controller can call us */ if (g_strcmp0 (session->priv->session_controller, sender) != 0) { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Only the session controller may call this function")); return TRUE; } /* you can't request the device again, that's confusing */ if (ck_session_get_device (session, arg_major, arg_minor)) { throw_error (invocation, CK_SESSION_ERROR_GENERAL, _("Device has already been requested")); return TRUE; } device = ck_session_create_device (session, arg_major, arg_minor); if (device == NULL) { throw_error (invocation, CK_SESSION_ERROR_NOT_SUPPORTED, _("Failed to create device")); return TRUE; } fd = ck_device_get_fd (device); if (fd == -1) { throw_error (invocation, CK_SESSION_ERROR_NOT_SUPPORTED, _("Failed to get file descriptor for device")); return TRUE; } out_fd_list = g_unix_fd_list_new_from_array (&fd, 1); console_kit_session_complete_take_device (object, invocation, out_fd_list, g_variant_new_handle (0), console_kit_session_get_active (object)); return TRUE; } static gboolean dbus_release_device (ConsoleKitSession *object, GDBusMethodInvocation *invocation, guint arg_major, guint arg_minor) { CkSession *session = CK_SESSION (object); CkDevice *device; const gchar *sender = g_dbus_method_invocation_get_sender (invocation); TRACE (); /* only the session controller can call us */ if (g_strcmp0 (session->priv->session_controller, sender) != 0) { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Only the session controller may call this function")); return TRUE; } device = ck_session_get_device (session, arg_major, arg_minor); if (device == NULL) { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Device doesn't exist")); return TRUE; } ck_session_remove_device (session, device); g_object_unref (device); console_kit_session_complete_release_device (object, invocation); return TRUE; } static gboolean dbus_pause_device_complete (ConsoleKitSession *object, GDBusMethodInvocation *invocation, guint arg_major, guint arg_minor) { CkSession *session = CK_SESSION (object); CkDevice *device; const gchar *sender = g_dbus_method_invocation_get_sender (invocation); TRACE (); /* only the session controller can call us */ if (g_strcmp0 (session->priv->session_controller, sender) != 0) { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Only the session controller may call this function")); return TRUE; } device = ck_session_get_device (session, arg_major, arg_minor); if (device == NULL) { throw_error (invocation, CK_SESSION_ERROR_FAILED, _("Device doesn't exist")); return TRUE; } ck_device_set_active (device, FALSE); ck_session_check_paused_devices (session); console_kit_session_complete_pause_device_complete (object, invocation); 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_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_LOGIN_SESSION_ID: ck_session_set_login_session_id (self, g_value_get_string (value), NULL); break; case PROP_SESSION_CONTROLLER: ck_session_set_session_controller (self, g_value_get_string (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_ID: g_value_set_string (value, self->priv->id); break; case PROP_COOKIE: g_value_set_string (value, self->priv->cookie); break; case PROP_LOGIN_SESSION_ID: g_value_set_string (value, self->priv->login_session_id); break; case PROP_SESSION_CONTROLLER: g_value_set_string (value, self->priv->session_controller); 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) { ConsoleKitSession *cksession; gboolean ret; ret = FALSE; cksession = CONSOLE_KIT_SESSION (session); if (! IS_STR_SET (console_kit_session_get_x11_display_device (cksession)) && ! IS_STR_SET (console_kit_session_get_x11_display (cksession)) && IS_STR_SET (console_kit_session_get_display_device (cksession))) { 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 (console_kit_session_get_display_device (CONSOLE_KIT_SESSION (session))); 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) { TRACE (); 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; 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 [ACTIVATE] = g_signal_new ("activate", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CkSessionClass, activate), NULL, NULL, ck_marshal_POINTER__POINTER, G_TYPE_POINTER, 1, G_TYPE_POINTER); /* Install private properties we're not exporting over D-BUS */ 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_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_SESSION_CONTROLLER, g_param_spec_string ("session-controller", "session-controller", "session-controller", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (CkSessionPrivate)); } 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); session->priv->tty_fd = -1; } static void ck_session_iface_init (ConsoleKitSessionIface *iface) { iface->handle_activate = dbus_activate; iface->handle_set_idle_hint = dbus_set_idle_hint; iface->handle_set_locked_hint = dbus_set_locked_hint; iface->handle_get_unix_user = dbus_get_unix_user; iface->handle_get_seat_id = dbus_get_seat_id; iface->handle_get_login_session_id = dbus_get_login_session_id; iface->handle_get_vtnr = dbus_get_vtnr; iface->handle_get_session_type = dbus_get_session_type; iface->handle_get_x11_display_device = dbus_get_x11_display_device; iface->handle_get_display_device = dbus_get_display_device; iface->handle_get_x11_display = dbus_get_x11_display; iface->handle_is_active = dbus_is_active; iface->handle_get_creation_time = dbus_get_creation_time; iface->handle_get_remote_host_name = dbus_get_remote_host_name; iface->handle_get_idle_since_hint = dbus_get_idle_since_hint; iface->handle_is_local = dbus_is_local; iface->handle_get_id = dbus_get_id; iface->handle_get_user = dbus_get_user; 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; iface->handle_take_control = dbus_take_control; iface->handle_release_control = dbus_release_control; iface->handle_take_device = dbus_take_device; iface->handle_release_device = dbus_release_device; iface->handle_pause_device_complete = dbus_pause_device_complete; } static void ck_session_finalize (GObject *object) { CkSession *session; g_debug ("ck_session_finalize"); 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); ck_session_set_session_controller (session, NULL); ck_session_remove_all_devices (session); g_free (session->priv->id); g_free (session->priv->cookie); g_free (session->priv->login_session_id); g_free (session->priv->runtime_dir); g_free (session->priv->seat_id); g_free (session->priv->session_controller); if (session->priv->bus_proxy) { g_object_unref(session->priv->bus_proxy); } if (session->priv->session_controller_watchid != 0) { g_bus_unwatch_name (session->priv->session_controller_watchid); } if (session->priv->pause_devices_timer != 0) { g_source_remove (session->priv->pause_devices_timer); session->priv->pause_devices_timer = 0; } G_OBJECT_CLASS (ck_session_parent_class)->finalize (object); } CkSession * ck_session_new (const char *ssid, const char *cookie, GDBusConnection *connection) { GObject *object; gboolean res; object = g_object_new (CK_TYPE_SESSION, "id", ssid, "cookie", cookie, NULL); res = register_session (CK_SESSION (object), connection); if (! res) { g_object_unref (object); return NULL; } return CK_SESSION (object); } CkSession * ck_session_new_with_parameters (const char *ssid, const char *cookie, const GVariant *parameters, GDBusConnection *connection) { GObject *object; gboolean res; GParameter *params; guint n_allocated_params; guint n_params; GObjectClass *class; GType object_type; GVariantIter *iter; gchar *prop_name; GVariant *value; object_type = CK_TYPE_SESSION; class = g_type_class_ref (object_type); g_variant_get ((GVariant *)parameters, "a{sv}", &iter); n_allocated_params = 2; if (parameters != NULL) { n_allocated_params += g_variant_iter_n_children (iter); } 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) { while (g_variant_iter_next (iter, "{sv}", &prop_name, &value)) { gboolean res; GValue val_struct = { 0, }; GParamSpec *pspec; if (prop_name == NULL) { g_debug ("Skipping NULL parameter"); goto cleanup; } g_debug ("prop_name = '%s'", prop_name); if (strcmp (prop_name, "id") == 0 || strcmp (prop_name, "cookie") == 0) { g_debug ("Skipping restricted parameter: %s", prop_name); goto cleanup; } pspec = g_object_class_find_property (class, prop_name); if (! pspec) { g_debug ("Skipping unknown parameter: %s", prop_name); goto cleanup; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_debug ("property '%s' is not writable", pspec->name); goto cleanup; } 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)); g_dbus_gvariant_to_gvalue (value, &val_struct); res = g_value_transform (&val_struct, ¶ms[n_params].value); if (! res) { g_debug ("unable to transform property value for '%s'", pspec->name); goto cleanup; } n_params++; cleanup: g_free(prop_name); if (value) { g_variant_unref(value); } } g_variant_iter_free (iter); } 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), connection); if (! res) { g_object_unref (object); return NULL; } return CK_SESSION (object); } void ck_session_run_programs (CkSession *session, const char *action) { ConsoleKitSession *cksession; int n; char *extra_env[11]; /* be sure to adjust this as needed */ TRACE (); n = 0; cksession = CONSOLE_KIT_SESSION (session); extra_env[n++] = g_strdup_printf ("CK_SESSION_ID=%s", session->priv->id); if (console_kit_session_get_session_type (cksession) != NULL) { extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", console_kit_session_get_session_type (cksession)); } 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", console_kit_session_get_unix_user (cksession)); if (console_kit_session_get_display_device (cksession) != NULL && strlen (console_kit_session_get_display_device (cksession)) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_DEVICE=%s", console_kit_session_get_display_device (cksession)); } if (console_kit_session_get_x11_display_device (cksession) != NULL && strlen (console_kit_session_get_x11_display_device (cksession) ) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY_DEVICE=%s", console_kit_session_get_x11_display_device (cksession) ); } extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY=%s", console_kit_session_get_x11_display (cksession) ? console_kit_session_get_x11_display (cksession) : ""); if (console_kit_session_get_remote_host_name (cksession) != NULL && strlen (console_kit_session_get_remote_host_name (cksession)) > 0) { extra_env[n++] = g_strdup_printf ("CK_SESSION_REMOTE_HOST_NAME=%s", console_kit_session_get_remote_host_name (cksession)); } extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_ACTIVE=%s", console_kit_session_get_active (cksession) ? "true" : "false"); extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_LOCAL=%s", console_kit_session_get_is_local (cksession) ? "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 (LIBDIR "/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; ConsoleKitSession *cksession; TRACE (); cksession = CONSOLE_KIT_SESSION (session); group_name = g_strdup_printf ("Session %s", session->priv->id); g_key_file_set_integer (key_file, group_name, "uid", console_kit_session_get_unix_user (cksession)); g_key_file_set_string (key_file, group_name, "seat", NONULL_STRING (session->priv->seat_id)); if (console_kit_session_get_session_type (cksession) != NULL) { g_key_file_set_string (key_file, group_name, "type", NONULL_STRING (console_kit_session_get_session_type (cksession))); } 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 (console_kit_session_get_display_device (cksession) != NULL && strlen (console_kit_session_get_display_device (cksession)) > 0) { g_key_file_set_string (key_file, group_name, "display_device", NONULL_STRING (console_kit_session_get_display_device (cksession))); } if (console_kit_session_get_x11_display_device (cksession) != NULL && strlen (console_kit_session_get_x11_display_device (cksession)) > 0) { g_key_file_set_string (key_file, group_name, "x11_display_device", NONULL_STRING (console_kit_session_get_x11_display_device (cksession))); } if (console_kit_session_get_x11_display (cksession) != NULL && strlen (console_kit_session_get_x11_display (cksession)) > 0) { g_key_file_set_string (key_file, group_name, "x11_display", NONULL_STRING (console_kit_session_get_x11_display (cksession))); } if (console_kit_session_get_remote_host_name (cksession) != NULL && strlen (console_kit_session_get_remote_host_name (cksession)) > 0) { g_key_file_set_string (key_file, group_name, "remote_host_name", NONULL_STRING (console_kit_session_get_remote_host_name (cksession))); } g_key_file_set_string (key_file, group_name, "remote_host_name", NONULL_STRING (console_kit_session_get_remote_host_name (cksession))); 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, group_name, "creation_time", NONULL_STRING (s)); g_free (s); g_free (group_name); }