From 5660e2c036463e899fb0da69297e88cf1bb6bbd8 Mon Sep 17 00:00:00 2001 From: Eric Koegel Date: Mon, 20 Oct 2014 14:26:27 +0300 Subject: [PATCH] Add HybridSleep support and change CanSleep Emulate the logind API to make it more easier for porting to ConsoleKit2 for the CanSuspend/CanHibernate/CanHybridSleep methods. They now return: yes - system can and user explicitly authorized by polkit, rbac, or neither is running no - system can and user explicitly unauthorized by polkit or rbac challenge - system can and user requires elevation via polkit na - system does not support it (hardware or backend support missing). The auth methods have been removed. Currently HybridSleep only works on Linux. --- data/ConsoleKit.conf | 8 +- data/org.freedesktop.consolekit.policy | 20 ++- src/ck-manager.c | 274 +++++++++++++++++++++++++---- src/ck-manager.h | 21 ++- src/ck-sysdeps-freebsd.c | 7 + src/ck-sysdeps-gnu.c | 7 + src/ck-sysdeps-linux.c | 6 + src/ck-sysdeps-openbsd.c | 7 + src/ck-sysdeps-solaris.c | 7 + src/ck-sysdeps.h | 1 + src/org.freedesktop.ConsoleKit.Manager.xml | 43 +++-- tools/freebsd/Makefile.am | 1 + tools/freebsd/ck-system-hybridsleep | 4 + tools/linux/Makefile.am | 1 + tools/linux/ck-system-hybridsleep | 12 ++ tools/openbsd/Makefile.am | 1 + tools/openbsd/ck-system-hybridsleep | 5 + tools/solaris/Makefile.am | 1 + tools/solaris/ck-system-hybridsleep | 4 + 19 files changed, 372 insertions(+), 58 deletions(-) create mode 100644 tools/freebsd/ck-system-hybridsleep create mode 100644 tools/linux/ck-system-hybridsleep create mode 100644 tools/openbsd/ck-system-hybridsleep create mode 100644 tools/solaris/ck-system-hybridsleep diff --git a/data/ConsoleKit.conf b/data/ConsoleKit.conf index 35c79a8..2b05219 100644 --- a/data/ConsoleKit.conf +++ b/data/ConsoleKit.conf @@ -42,9 +42,6 @@ - @@ -53,7 +50,10 @@ send_member="CanHibernate"/> + send_member="HybridSleep"/> + diff --git a/data/org.freedesktop.consolekit.policy b/data/org.freedesktop.consolekit.policy index 76a6cc8..3898d9a 100644 --- a/data/org.freedesktop.consolekit.policy +++ b/data/org.freedesktop.consolekit.policy @@ -63,7 +63,7 @@ Policy definitions for ConsoleKit - + Hibernate the system System policy prevents hibernating the system @@ -80,4 +80,22 @@ Policy definitions for ConsoleKit auth_admin_keep + + + Hybrid sleep the system (sleep + hibernate) + System policy prevents hybrid sleeping the system + + no + yes + + + + + Hybrid sleep the system (sleep + hibernate) when multiple users are logged in + System policy prevents hybrid sleeping the system when other users are logged in + + no + auth_admin_keep + + diff --git a/src/ck-manager.c b/src/ck-manager.c index 3ff8ec7..78b8092 100644 --- a/src/ck-manager.c +++ b/src/ck-manager.c @@ -856,6 +856,59 @@ ready_cb (PolkitAuthority *authority, g_object_unref (ret); } +static void +sleep_ready_cb (PolkitAuthority *authority, + GAsyncResult *res, + DBusGMethodInvocation *context) +{ + PolkitAuthorizationResult *ret; + GError *error; + + error = NULL; + ret = polkit_authority_check_authorization_finish (authority, res, &error); + if (error != NULL) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } + else if (polkit_authorization_result_get_is_authorized (ret)) { + dbus_g_method_return (context, "yes"); + } + else if (polkit_authorization_result_get_is_challenge (ret)) { + dbus_g_method_return (context, "challenge"); + } + else { + dbus_g_method_return (context, "no"); + } + + g_object_unref (ret); +} + +/* We use this and sleep_ready_cb to avoid breaking API compability with + * ConsoleKit for Stop and Restart */ +static void +get_polkit_sleep_permissions (CkManager *manager, + const char *action, + DBusGMethodInvocation *context) +{ + const char *sender; + PolkitSubject *subject; + + g_debug ("get permissions for action %s", action); + + sender = dbus_g_method_get_sender (context); + subject = polkit_system_bus_name_new (sender); + + polkit_authority_check_authorization (manager->priv->pol_ctx, + subject, + action, + NULL, + 0, + NULL, + (GAsyncReadyCallback) sleep_ready_cb, + context); + g_object_unref (subject); +} + static void get_polkit_permissions (CkManager *manager, const char *action, @@ -1314,38 +1367,55 @@ ck_manager_suspend (CkManager *manager, return TRUE; } +/** + * ck_manager_can_suspend: + * @manager: the @CkManager object + * @context: We return a string here, either: + * yes - system can and user explicitly authorized by polkit, rbac, or neither is running + * no - system can and user explicitly unauthorized by polkit or rbac + * challenge - system can and user requires elevation via polkit + * na - system does not support it (hardware or backend support missing). + * + * Determines if the system can suspend. + * Example: + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.CanSuspend + * + * Returnes TRUE. + **/ gboolean -ck_manager_auth_suspend (CkManager *manager, - DBusGMethodInvocation *context) +ck_manager_can_suspend (CkManager *manager, + DBusGMethodInvocation *context) { const char *action; - action = "org.freedesktop.consolekit.system.suspend"; + if (get_system_num_users (manager) > 1) { + action = "org.freedesktop.consolekit.system.suspend-multiple-users"; + } else { + action = "org.freedesktop.consolekit.system.suspend"; + } + if (ck_system_can_suspend ()) { #if defined HAVE_POLKIT - get_polkit_permissions (manager, action, context); + /* polkit_sleep will return the yes, no, and challenge */ + get_polkit_sleep_permissions (manager, action, context); #elif defined ENABLE_RBAC_SHUTDOWN - if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, - NULL, NULL)) { - dbus_g_method_return (context, TRUE); + /* rbac determines either yes or no. There is no challenge with rbac */ + if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, NULL, NULL)) { + dbus_g_method_return (context, "yes"); } else { - dbus_g_method_return (context, FALSE); + dbus_g_method_return (context, "no"); } +#else + /* neither polkit or rbac. assumed single user system */ + dbus_g_method_return (context, "yes"); #endif - - return TRUE; -} - -gboolean -ck_manager_can_suspend (CkManager *manager, - DBusGMethodInvocation *context) - -{ - if (ck_system_can_suspend ()) { - dbus_g_method_return (context, TRUE); } else { - dbus_g_method_return (context, FALSE); + /* not supported by system (or consolekit backend) */ + dbus_g_method_return (context, "na"); } return TRUE; @@ -1422,38 +1492,181 @@ ck_manager_hibernate (CkManager *manager, return TRUE; } +/** + * ck_manager_can_hibernate: + * @manager: the @CkManager object + * @context: We return a string here, either: + * yes - system can and user explicitly authorized by polkit, rbac, or neither is running + * no - system can and user explicitly unauthorized by polkit or rbac + * challenge - system can and user requires elevation via polkit + * na - system does not support it (hardware or backend support missing). + * + * Determines if the system can hibernate. + * Example: + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.CanHibernate + * + * Returnes TRUE. + **/ gboolean -ck_manager_auth_hibernate (CkManager *manager, - DBusGMethodInvocation *context) +ck_manager_can_hibernate (CkManager *manager, + DBusGMethodInvocation *context) { const char *action; - action = "org.freedesktop.consolekit.system.hibernate"; + if (get_system_num_users (manager) > 1) { + action = "org.freedesktop.consolekit.system.hibernate-multiple-users"; + } else { + action = "org.freedesktop.consolekit.system.hibernate"; + } + if (ck_system_can_hibernate ()) { #if defined HAVE_POLKIT - get_polkit_permissions (manager, action, context); + /* polkit_sleep will return the yes, no, and challenge */ + get_polkit_sleep_permissions (manager, action, context); #elif defined ENABLE_RBAC_SHUTDOWN - if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, - NULL, NULL)) { - dbus_g_method_return (context, TRUE); + /* rbac determines either yes or no. There is no challenge with rbac */ + if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, NULL, NULL)) { + dbus_g_method_return (context, "yes"); } else { + dbus_g_method_return (context, "no"); + } +#else + /* neither polkit or rbac. assumed single user system */ + dbus_g_method_return (context, "yes"); +#endif + } else { + /* not supported by system (or consolekit backend) */ + dbus_g_method_return (context, "na"); + } + + return TRUE; +} + +static void +do_hybrid_sleep (CkManager *manager, + DBusGMethodInvocation *context, + void *arg) +{ + GError *error; + gboolean res; + + g_debug ("ConsoleKit preforming Hybrid Sleep"); + + log_system_action_event (manager, CK_LOG_EVENT_SYSTEM_HIBERNATE); + + error = NULL; + res = g_spawn_command_line_async (PREFIX "/lib/ConsoleKit/scripts/ck-system-hybridsleep", + &error); + if (! res) { + GError *new_error; + + g_warning ("Unable to hybrid sleep system: %s", error->message); + + new_error = g_error_new (CK_MANAGER_ERROR, + CK_MANAGER_ERROR_GENERAL, + "Unable to hybrid sleep system: %s", error->message); + dbus_g_method_return_error (context, new_error); + g_error_free (new_error); + + g_error_free (error); + } else { + dbus_g_method_return (context); + } +} + +/* + Example: + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.Hibernate +*/ +gboolean +ck_manager_hybrid_sleep (CkManager *manager, + DBusGMethodInvocation *context) +{ + const char *action; + + /* Check if something in inhibiting that action */ + /* if (ck_inhibit_manager_is_suspend_inhibited (manager->priv->inhibit_manager)) { + g_debug ("hybrid sleep inhibited"); dbus_g_method_return (context, FALSE); + return TRUE; + } */ + + if (get_system_num_users (manager) > 1) { + action = "org.freedesktop.consolekit.system.hybridsleep-multiple-users"; + } else { + action = "org.freedesktop.consolekit.system.hybridsleep"; } + + g_debug ("ConsoleKit Hibernate: %s", action); + +#if defined HAVE_POLKIT + check_polkit_permissions (manager, context, action, do_hybrid_sleep); +#elif defined ENABLE_RBAC_SHUTDOWN + check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, do_hybrid_sleep, NULL); +#else + g_warning ("Compiled without PolicyKit or RBAC support!"); + do_hybrid_sleep(manager, context, NULL); #endif return TRUE; } +/** + * ck_manager_can_hybrid_sleep: + * @manager: the @CkManager object + * @context: We return a string here, either: + * yes - system can and user explicitly authorized by polkit, rbac, or neither is running + * no - system can and user explicitly unauthorized by polkit or rbac + * challenge - system can and user requires elevation via polkit + * na - system does not support it (hardware or backend support missing). + * + * Determines if the system can hybrid sleep (suspend + hibernate). + * Example: + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.CanHibernate + * + * Returnes TRUE. + **/ gboolean -ck_manager_can_hibernate (CkManager *manager, - DBusGMethodInvocation *context) +ck_manager_can_hybrid_sleep (CkManager *manager, + DBusGMethodInvocation *context) { + const char *action; + + if (get_system_num_users (manager) > 1) { + action = "org.freedesktop.consolekit.system.hybridsleep-multiple-users"; + } else { + action = "org.freedesktop.consolekit.system.hybridsleep"; + } + if (ck_system_can_hibernate ()) { - dbus_g_method_return (context, TRUE); +#if defined HAVE_POLKIT + /* polkit_sleep will return the yes, no, and challenge */ + get_polkit_sleep_permissions (manager, action, context); +#elif defined ENABLE_RBAC_SHUTDOWN + /* rbac determines either yes or no. There is no challenge with rbac */ + if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, NULL, NULL)) { + dbus_g_method_return (context, "yes"); } else { - dbus_g_method_return (context, FALSE); + dbus_g_method_return (context, "no"); + } +#else + /* neither polkit or rbac. assumed single user system */ + dbus_g_method_return (context, "yes"); +#endif + } else { + /* not supported by system (or consolekit backend) */ + dbus_g_method_return (context, "na"); } return TRUE; diff --git a/src/ck-manager.h b/src/ck-manager.h index d464056..7a58223 100644 --- a/src/ck-manager.h +++ b/src/ck-manager.h @@ -90,14 +90,12 @@ gboolean ck_manager_hibernate (CkManager *manager, DBusGMethodInvocation *context); -gboolean ck_manager_can_stop (CkManager *manager, - DBusGMethodInvocation *context); -gboolean ck_manager_can_restart (CkManager *manager, +gboolean ck_manager_hybrid_sleep (CkManager *manager, DBusGMethodInvocation *context); -gboolean ck_manager_can_suspend (CkManager *manager, - DBusGMethodInvocation *context); -gboolean ck_manager_can_hibernate (CkManager *manager, +gboolean ck_manager_can_stop (CkManager *manager, + DBusGMethodInvocation *context); +gboolean ck_manager_can_restart (CkManager *manager, DBusGMethodInvocation *context); gboolean ck_manager_get_available_operating_systems (CkManager *manager, @@ -105,10 +103,14 @@ gboolean ck_manager_restart_with_parameters (CkManager *manager, const gchar *parameters, DBusGMethodInvocation *context); -gboolean ck_manager_auth_suspend (CkManager *manager, + +gboolean ck_manager_can_suspend (CkManager *manager, DBusGMethodInvocation *context); -gboolean ck_manager_auth_hibernate (CkManager *manager, +gboolean ck_manager_can_hibernate (CkManager *manager, + DBusGMethodInvocation *context); +gboolean ck_manager_can_hybrid_sleep (CkManager *manager, DBusGMethodInvocation *context); + gboolean ck_manager_inhibit (CkManager *manager, gchar *what, gchar *who, diff --git a/src/ck-sysdeps-solaris.c b/src/ck-sysdeps-solaris.c index 63cb6e0..9d26380 100644 --- a/src/ck-sysdeps-solaris.c +++ b/src/ck-sysdeps-solaris.c @@ -543,3 +543,10 @@ ck_system_can_hibernate (void) /* TODO: not implemented */ return FALSE; } + +gboolean +ck_system_can_hybrid_sleep (void) +{ + /* TODO: not implemented */ + return FALSE; +} diff --git a/src/ck-sysdeps.h b/src/ck-sysdeps.h index 73c2608..cf677bc 100644 --- a/src/ck-sysdeps.h +++ b/src/ck-sysdeps.h @@ -75,6 +75,7 @@ gboolean ck_wait_for_active_console_num (int console_fd, gboolean ck_system_can_suspend (void); gboolean ck_system_can_hibernate (void); +gboolean ck_system_can_hybrid_sleep (void); #ifdef HAVE_SYS_VT_SIGNAL gint ck_get_vt_signal_fd (void); diff --git a/src/org.freedesktop.ConsoleKit.Manager.xml b/src/org.freedesktop.ConsoleKit.Manager.xml index 18957c2..1732e0a 100644 --- a/src/org.freedesktop.ConsoleKit.Manager.xml +++ b/src/org.freedesktop.ConsoleKit.Manager.xml @@ -53,49 +53,66 @@ - + - This method returns whether the computer system is capable of suspending. + This method emulates the logind implementation. + Returns whether the system supports suspending and whether the calling user is eligible to hibernate the system. + Returns one of "na", "yes", "no" or "challenge". + If "na" is returned suspending is not available because of hardware support. + If "yes" is returned suspending is supported and the user may suspend without further authentication. + If "no" is returned suspending is available but the user is not allowed to suspend. + If "challenge" is returned suspending is available, but only after authorization. - + - - This method returns whether the user is authorized to suspend the computer system. + This method initiates a request to hibernate the computer system. - + + - This method initiates a request to hibernate the computer system. + This method emulates the logind implementation. + Returns whether the system supports hibernation and whether the calling user is eligible to hibernate the system. + Returns one of "na", "yes", "no" or "challenge". + If "na" is returned hibernation is not available because of hardware support. + If "yes" is returned hibernation is supported and the user may hibernate without further authentication. + If "no" is returned hibernation is available but the user is not allowed to hibernate. + If "challenge" is returned hibernation is available, but only after authorization. - + - - This method returns whether the computer system is capable of hibernating. + This method initiates a request to hybrid sleep (suspend + hibernate) the computer system. - + - + - This method returns whether the user is authorized to hibernate the computer system. + This method emulates the logind implementation. + Returns whether the system supports hybrid sleep (suspend + hibernate) and whether the calling user is eligible to hybrid sleep the system. + Returns one of "na", "yes", "no" or "challenge". + If "na" is returned hybrid sleeping is not available because of hardware support. + If "yes" is returned hybrid sleeping is supported and the user may hybrid sleep without further authentication. + If "no" is returned hybrid sleeping is available but the user is not allowed to hybrid sleep. + If "challenge" is returned hybrid sleeping is available, but only after authorization. diff --git a/tools/solaris/Makefile.am b/tools/solaris/Makefile.am index 50b9b27..85a7166 100644 --- a/tools/solaris/Makefile.am +++ b/tools/solaris/Makefile.am @@ -12,6 +12,7 @@ script_SCRIPTS = \ ck-system-restart \ ck-system-suspend \ ck-system-hibernate \ + ck-system-hybridsleep \ $(NULL) EXTRA_DIST = \ diff --git a/tools/solaris/ck-system-hybridsleep b/tools/solaris/ck-system-hybridsleep new file mode 100644 index 0000000..5f31342 --- /dev/null +++ b/tools/solaris/ck-system-hybridsleep @@ -0,0 +1,4 @@ +#!/bin/sh + +# FIXME: Implement this +exit 1