summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Jon McCann <mccann@jhu.edu>2008-01-22 17:03:46 -0500
committerWilliam Jon McCann <mccann@jhu.edu>2008-01-22 17:43:22 -0500
commit5ce97e6f22fd25279793fbc75211d2e86413ae73 (patch)
tree5de0565516b1d90ed382dc5f0ed969c8e512706c
parent2fba24e67597bf59ae00db2867df7a348c81b094 (diff)
initial stop/restart support
Add Stop and Restart methods to the Manager object. We'll rename the Manager object to System in the near future. Use libpolkit to determine authorization.
-rw-r--r--configure.ac2
-rw-r--r--data/ConsoleKit.policy48
-rw-r--r--data/Makefile.am4
-rw-r--r--doc/spec/ck-manager.xml18
-rw-r--r--doc/xml/ref-ck-manager.xml10
-rw-r--r--src/ck-manager.c667
-rw-r--r--src/ck-manager.h10
-rw-r--r--src/ck-manager.xml6
-rw-r--r--tools/Makefile.am10
-rw-r--r--tools/freebsd/Makefile.am38
-rwxr-xr-xtools/freebsd/ck-system-restart12
-rwxr-xr-xtools/freebsd/ck-system-stop18
-rw-r--r--tools/linux/Makefile.am38
-rwxr-xr-xtools/linux/ck-system-restart12
-rwxr-xr-xtools/linux/ck-system-stop12
-rw-r--r--tools/solaris/Makefile.am38
-rwxr-xr-xtools/solaris/ck-system-restart12
-rwxr-xr-xtools/solaris/ck-system-stop12
18 files changed, 890 insertions, 77 deletions
diff --git a/configure.ac b/configure.ac
index c701912..c5be9ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,7 @@ AM_GLIB_GNU_GETTEXT
DBUS_REQUIRED_VERSION=0.30
GLIB_REQUIRED_VERSION=2.7.0
X11_REQUIRED_VERSION=1.0.0
+POLKIT_REQUIRED_VERSION=0.7
AC_CHECK_HEADERS(unistd.h)
AC_CHECK_HEADERS(paths.h)
@@ -52,6 +53,7 @@ PKG_CHECK_MODULES(CONSOLE_KIT,
dbus-glib-1 >= $DBUS_REQUIRED_VERSION
gobject-2.0 >= $GLIB_REQUIRED_VERSION
gthread-2.0 >= $GLIB_REQUIRED_VERSION
+ polkit >= $POLKIT_REQUIRED_VERSION
)
PKG_CHECK_MODULES(LIBDBUS,
dbus-1 >= $DBUS_REQUIRED_VERSION
diff --git a/data/ConsoleKit.policy b/data/ConsoleKit.policy
new file mode 100644
index 0000000..fea8737
--- /dev/null
+++ b/data/ConsoleKit.policy
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+
+<!--
+Policy definitions for ConsoleKit
+-->
+
+<policyconfig>
+
+ <action id="org.freedesktop.consolekit.system.stop">
+ <description>Stop the system</description>
+ <message>System policy prevents stopping the system</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.consolekit.system.stop-multiple-sessions">
+ <description>Stop the system when multiple users are logged in</description>
+ <message>System policy prevents stopping the when other users are logged in</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.consolekit.system.restart">
+ <description>Restart the system</description>
+ <message>System policy prevents restarting the system</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.consolekit.system.restart-multiple-sessions">
+ <description>Restart the system when multiple users are logged in</description>
+ <message>System policy prevents restarting the system when other users are logged in</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+
+</policyconfig>
diff --git a/data/Makefile.am b/data/Makefile.am
index e2a237b..dc1bf1a 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -6,6 +6,10 @@ dbusconf_DATA = ConsoleKit.conf
seatdir = $(sysconfdir)/ConsoleKit/seats.d
seat_DATA = 00-primary.seat
+polkit_policydir = $(datadir)/PolicyKit/policy
+dist_polkit_policy_DATA = \
+ ConsoleKit.policy \
+ $(NULL)
servicedir = $(datadir)/dbus-1/system-services
service_in_files = org.freedesktop.ConsoleKit.service.in
diff --git a/doc/spec/ck-manager.xml b/doc/spec/ck-manager.xml
index 077782f..acc065b 100644
--- a/doc/spec/ck-manager.xml
+++ b/doc/spec/ck-manager.xml
@@ -4,6 +4,24 @@
>
<interface name="org.freedesktop.ConsoleKit.Manager">
+ <method name="Restart">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <doc:doc>
+ <doc:description>
+ <doc:para>This method initiates a request to restart (ie. reboot) the computer system.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+
+ <method name="Stop">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <doc:doc>
+ <doc:description>
+ <doc:para>This method initiates a request to stop (ie. shutdown) the computer system.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+
<method name="OpenSession">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="cookie" direction="out" type="s">
diff --git a/doc/xml/ref-ck-manager.xml b/doc/xml/ref-ck-manager.xml
index 2aceef8..f964295 100644
--- a/doc/xml/ref-ck-manager.xml
+++ b/doc/xml/ref-ck-manager.xml
@@ -8,7 +8,9 @@
</refnamediv>
<refsynopsisdiv role="synopsis">
<title role="synopsis.title">Methods</title>
- <synopsis><link linkend="Manager.OpenSession">OpenSession</link> (out 's' cookie)
+ <synopsis><link linkend="Manager.Restart">Restart</link> ()
+<link linkend="Manager.Stop">Stop</link> ()
+<link linkend="Manager.OpenSession">OpenSession</link> (out 's' cookie)
<link linkend="Manager.OpenSessionWithParameters">OpenSessionWithParameters</link> (in 'a(sv)' parameters,
out 's' cookie)
<link linkend="Manager.CloseSession">CloseSession</link> (in 's' cookie,
@@ -49,7 +51,11 @@
<title role="desc.title">Description</title>
<para/>
</refsect1>
- <refsect1 role="details"><title role="details.title">Details</title><refsect2><title><anchor role="function" id="Manager.OpenSession"/>OpenSession ()</title><indexterm><primary>OpenSession</primary><secondary>Manager</secondary></indexterm><programlisting>OpenSession (out 's' cookie)</programlisting></refsect2>
+ <refsect1 role="details"><title role="details.title">Details</title><refsect2><title><anchor role="function" id="Manager.Restart"/>Restart ()</title><indexterm><primary>Restart</primary><secondary>Manager</secondary></indexterm><programlisting>Restart ()</programlisting></refsect2>
+ <para>This method initiates a request to restart (ie. reboot) the computer system.</para>
+ <variablelist role="params"/><refsect2><title><anchor role="function" id="Manager.Stop"/>Stop ()</title><indexterm><primary>Stop</primary><secondary>Manager</secondary></indexterm><programlisting>Stop ()</programlisting></refsect2>
+ <para>This method initiates a request to stop (ie. shutdown) the computer system.</para>
+ <variablelist role="params"/><refsect2><title><anchor role="function" id="Manager.OpenSession"/>OpenSession ()</title><indexterm><primary>OpenSession</primary><secondary>Manager</secondary></indexterm><programlisting>OpenSession (out 's' cookie)</programlisting></refsect2>
<para>This method requests that a new <link linkend="Session">Session</link>
be created for the calling process. The properties of this new Session are set automatically
from information collected about the calling process.
diff --git a/src/ck-manager.c b/src/ck-manager.c
index 5c77547..b6bcb2b 100644
--- a/src/ck-manager.c
+++ b/src/ck-manager.c
@@ -38,6 +38,8 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#include <polkit/polkit.h>
+
#include "ck-manager.h"
#include "ck-manager-glue.h"
#include "ck-seat.h"
@@ -58,6 +60,8 @@
struct CkManagerPrivate
{
+ PolKitContext *pol_ctx;
+
GHashTable *seats;
GHashTable *sessions;
GHashTable *leaders;
@@ -634,6 +638,561 @@ log_seat_device_removed_event (CkManager *manager,
g_free (device_id);
}
+static char *
+get_cookie_for_pid (CkManager *manager,
+ guint pid)
+{
+ char *cookie;
+
+ /* FIXME: need a better way to get the cookie */
+
+ cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE");
+
+ return cookie;
+}
+
+static CkSession *
+get_session_for_unix_process (CkManager *manager,
+ guint pid)
+{
+ CkSessionLeader *leader;
+ CkSession *session;
+ char *cookie;
+
+ session = NULL;
+ leader = NULL;
+
+ cookie = get_cookie_for_pid (manager, pid);
+ if (cookie == NULL) {
+ goto out;
+ }
+
+ leader = g_hash_table_lookup (manager->priv->leaders, cookie);
+ if (leader == NULL) {
+ goto out;
+ }
+
+ session = g_hash_table_lookup (manager->priv->sessions, ck_session_leader_peek_session_id (leader));
+
+ out:
+ g_free (cookie);
+
+ return session;
+}
+
+static PolKitSession *
+new_polkit_session_from_session (CkManager *manager,
+ CkSession *ck_session)
+{
+ PolKitSession *pk_session;
+ PolKitSeat *pk_seat;
+ uid_t uid;
+ gboolean is_active;
+ gboolean is_local;
+ char *sid;
+ char *ssid;
+ char *remote_host;
+
+ sid = NULL;
+ ssid = NULL;
+ remote_host = NULL;
+
+ ck_session_get_seat_id (ck_session, &sid, NULL);
+
+ g_object_get (ck_session,
+ "active", &is_active,
+ "is-local", &is_local,
+ "id", &ssid,
+ "unix-user", &uid,
+ "remote-host-name", &remote_host,
+ NULL);
+
+ pk_session = polkit_session_new ();
+ if (pk_session == NULL) {
+ goto out;
+ }
+ if (!polkit_session_set_uid (pk_session, uid)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_objref (pk_session, ssid)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_is_active (pk_session, is_active)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_is_local (pk_session, is_local)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!is_local) {
+ if (!polkit_session_set_ck_remote_host (pk_session, remote_host)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+ }
+
+
+ pk_seat = polkit_seat_new ();
+ if (pk_seat == NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_seat_set_ck_objref (pk_seat, sid)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_seat_validate (pk_seat)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+ if (!polkit_session_set_seat (pk_session, pk_seat)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ polkit_seat_unref (pk_seat); /* session object now owns this object */
+ pk_seat = NULL;
+
+ if (!polkit_session_validate (pk_session)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+out:
+ g_free (ssid);
+ g_free (sid);
+ g_free (remote_host);
+
+ return pk_session;
+}
+
+static PolKitCaller *
+new_polkit_caller_from_dbus_name (CkManager *manager,
+ const char *dbus_name)
+{
+ PolKitCaller *caller;
+ pid_t pid;
+ uid_t uid;
+ char *selinux_context;
+ PolKitSession *pk_session;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter sub_iter;
+ char *str;
+ int num_elems;
+ DBusConnection *con;
+ DBusError error;
+ CkSession *ck_session;
+
+ dbus_error_init (&error);
+
+ con = dbus_g_connection_get_connection (manager->priv->connection);
+
+ g_return_val_if_fail (con != NULL, NULL);
+ g_return_val_if_fail (dbus_name != NULL, NULL);
+
+ selinux_context = NULL;
+
+ caller = NULL;
+ ck_session = NULL;
+ pk_session = NULL;
+
+ uid = dbus_bus_get_unix_user (con, dbus_name, &error);
+ if (dbus_error_is_set (&error)) {
+ g_warning ("Could not get uid for connection: %s %s",
+ error.name,
+ error.message);
+ dbus_error_free (&error);
+ goto out;
+ }
+
+ message = dbus_message_new_method_call ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus/Bus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
+ reply = dbus_connection_send_with_reply_and_block (con, message, -1, &error);
+
+ if (reply == NULL || dbus_error_is_set (&error)) {
+ g_warning ("Error doing GetConnectionUnixProcessID on Bus: %s: %s",
+ error.name,
+ error.message);
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_error_free (&error);
+ goto out;
+ }
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &pid);
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+
+ message = dbus_message_new_method_call ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus/Bus",
+ "org.freedesktop.DBus",
+ "GetConnectionSELinuxSecurityContext");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
+ reply = dbus_connection_send_with_reply_and_block (con, message, -1, &error);
+ /* SELinux might not be enabled */
+ if (dbus_error_is_set (&error) &&
+ strcmp (error.name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown") == 0) {
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_error_init (&error);
+ } else if (reply == NULL || dbus_error_is_set (&error)) {
+ g_warning ("Error doing GetConnectionSELinuxSecurityContext on Bus: %s: %s", error.name, error.message);
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ goto out;
+ } else {
+ /* TODO: verify signature */
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &sub_iter);
+ dbus_message_iter_get_fixed_array (&sub_iter, (void *) &str, &num_elems);
+ if (str != NULL && num_elems > 0) {
+ selinux_context = g_strndup (str, num_elems);
+ }
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ }
+
+ ck_session = get_session_for_unix_process (manager, pid);
+ if (ck_session == NULL) {
+ /* OK, this is not a catastrophe; just means the caller is not a
+ * member of any session or that ConsoleKit is not available..
+ */
+ goto not_in_session;
+ }
+
+ pk_session = new_polkit_session_from_session (manager, ck_session);
+ if (pk_session == NULL) {
+ g_warning ("Got a session but couldn't construct polkit session object!");
+ goto out;
+ }
+ if (!polkit_session_validate (pk_session)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+not_in_session:
+
+ caller = polkit_caller_new ();
+ if (caller == NULL) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ goto out;
+ }
+
+ if (!polkit_caller_set_dbus_name (caller, dbus_name)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (!polkit_caller_set_uid (caller, uid)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (!polkit_caller_set_pid (caller, pid)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (selinux_context != NULL) {
+ if (!polkit_caller_set_selinux_context (caller, selinux_context)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ }
+ if (pk_session != NULL) {
+ if (!polkit_caller_set_ck_session (caller, pk_session)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ polkit_session_unref (pk_session); /* caller object now own this object */
+ pk_session = NULL;
+ }
+
+ if (!polkit_caller_validate (caller)) {
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+
+out:
+ g_free (selinux_context);
+
+ return caller;
+}
+
+static gboolean
+_check_polkit_for_action (CkManager *manager,
+ DBusGMethodInvocation *context,
+ const char *action)
+{
+ const char *sender;
+ GError *error;
+ DBusError dbus_error;
+ PolKitCaller *pk_caller;
+ PolKitAction *pk_action;
+ PolKitResult pk_result;
+
+ error = NULL;
+
+ g_debug ("constructing polkit data");
+
+ /* Check that caller is privileged */
+ sender = dbus_g_method_get_sender (context);
+ dbus_error_init (&dbus_error);
+
+ pk_caller = new_polkit_caller_from_dbus_name (manager, sender);
+ if (pk_caller == NULL) {
+ error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Error getting information about caller: %s: %s",
+ dbus_error.name,
+ dbus_error.message);
+ dbus_error_free (&dbus_error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ pk_action = polkit_action_new ();
+ polkit_action_set_action_id (pk_action, action);
+
+ g_debug ("checking if caller %s is authorized", sender);
+
+ /* this version crashes if error is used */
+ pk_result = polkit_context_is_caller_authorized (manager->priv->pol_ctx,
+ pk_action,
+ pk_caller,
+ TRUE,
+ NULL);
+ g_debug ("answer is: %s", (pk_result == POLKIT_RESULT_YES) ? "yes" : "no");
+
+ polkit_caller_unref (pk_caller);
+ polkit_action_unref (pk_action);
+
+ if (pk_result != POLKIT_RESULT_YES) {
+ error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_NOT_PRIVILEGED,
+ "Not privileged for action: %s",
+ action);
+ dbus_error_free (&dbus_error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* adapted from PolicyKit */
+static gboolean
+get_caller_info (CkManager *manager,
+ 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 (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_uid,
+ G_TYPE_INVALID)) {
+ g_debug ("GetConnectionUnixUser() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_pid,
+ G_TYPE_INVALID)) {
+ g_debug ("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;
+}
+
+/*
+ Example:
+ dbus-send --system --dest=org.freedesktop.ConsoleKit \
+ --type=method_call --print-reply --reply-timeout=2000 \
+ /org/freedesktop/ConsoleKit/Manager \
+ org.freedesktop.ConsoleKit.Manager.Restart
+*/
+gboolean
+ck_manager_restart (CkManager *manager,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+ gboolean res;
+ const char *action;
+ GError *error;
+
+ ret = FALSE;
+
+ if (g_hash_table_size (manager->priv->sessions) > 1) {
+ action = "org.freedesktop.consolekit.system.restart-multiple-users";
+ } else {
+ action = "org.freedesktop.consolekit.system.restart";
+ }
+
+ g_debug ("ConsoleKit Restart: %s", action);
+
+ res = _check_polkit_for_action (manager, context, action);
+
+ if (! res) {
+ goto out;
+ }
+
+ g_debug ("ConsoleKit preforming Restart: %s", action);
+
+ error = NULL;
+ res = g_spawn_command_line_async (LIBDIR "/ConsoleKit/scripts/ck-system-restart",
+ &error);
+ if (! res) {
+ GError *new_error;
+
+ g_warning ("Unable to restart system: %s", error->message);
+
+ new_error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Unable to restart system: %s", error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+
+ g_error_free (error);
+ } else {
+ ret = TRUE;
+ dbus_g_method_return (context);
+ }
+
+ out:
+
+ return ret;
+}
+
+gboolean
+ck_manager_stop (CkManager *manager,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+ gboolean res;
+ const char *action;
+ GError *error;
+
+ ret = TRUE;
+
+ if (g_hash_table_size (manager->priv->sessions) > 1) {
+ action = "org.freedesktop.consolekit.system.stop-multiple-users";
+ } else {
+ action = "org.freedesktop.consolekit.system.stop";
+ }
+
+ res = _check_polkit_for_action (manager, context, action);
+ if (! res) {
+ goto out;
+ }
+
+ g_debug ("Stopping system");
+ error = NULL;
+ res = g_spawn_command_line_async (LIBDIR "/ConsoleKit/scripts/ck-system-stop",
+ &error);
+ if (! res) {
+ GError *new_error;
+
+ g_warning ("Unable to stop system: %s", error->message);
+
+ new_error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Unable to stop system: %s", error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+
+ g_error_free (error);
+ } else {
+ ret = TRUE;
+ dbus_g_method_return (context);
+ }
+
+ out:
+ return ret;
+}
+
static void
on_seat_active_session_changed (CkSeat *seat,
const char *ssid,
@@ -844,51 +1403,6 @@ find_seat_for_session (CkManager *manager,
return seat;
}
-/* adapted from PolicyKit */
-static gboolean
-get_caller_info (CkManager *manager,
- 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 (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
- G_TYPE_STRING, sender,
- G_TYPE_INVALID,
- G_TYPE_UINT, calling_uid,
- G_TYPE_INVALID)) {
- g_debug ("GetConnectionUnixUser() failed: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
- G_TYPE_STRING, sender,
- G_TYPE_INVALID,
- G_TYPE_UINT, calling_pid,
- G_TYPE_INVALID)) {
- g_debug ("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
manager_set_system_idle_hint (CkManager *manager,
gboolean idle_hint)
@@ -1278,19 +1792,6 @@ ck_manager_get_session_for_cookie (CkManager *manager,
return TRUE;
}
-static char *
-get_cookie_for_pid (CkManager *manager,
- guint pid)
-{
- char *cookie;
-
- /* FIXME: need a better way to get the cookie */
-
- cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE");
-
- return cookie;
-}
-
/*
Example:
dbus-send --system --dest=org.freedesktop.ConsoleKit \
@@ -1682,10 +2183,60 @@ bus_name_owner_changed (DBusGProxy *bus_proxy,
}
static gboolean
+pk_io_watch_have_data (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ int fd;
+ PolKitContext *pk_context = user_data;
+
+ fd = g_io_channel_unix_get_fd (channel);
+ polkit_context_io_func (pk_context, fd);
+ return TRUE;
+}
+
+static int
+pk_io_add_watch (PolKitContext *pk_context,
+ int fd)
+{
+ guint id = 0;
+ GIOChannel *channel;
+
+ channel = g_io_channel_unix_new (fd);
+ if (channel == NULL) {
+ goto out;
+ }
+
+ id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
+ if (id == 0) {
+ g_io_channel_unref (channel);
+ goto out;
+ }
+ g_io_channel_unref (channel);
+
+out:
+ return id;
+}
+
+static void
+pk_io_remove_watch (PolKitContext *pk_context,
+ int watch_id)
+{
+ g_source_remove (watch_id);
+}
+
+static gboolean
register_manager (CkManager *manager)
{
GError *error = NULL;
+ manager->priv->pol_ctx = polkit_context_new ();
+ polkit_context_set_io_watch_functions (manager->priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch);
+ if (! polkit_context_init (manager->priv->pol_ctx, NULL)) {
+ g_critical ("cannot initialize libpolkit");
+ return FALSE;
+ }
+
error = NULL;
manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (manager->priv->connection == NULL) {
diff --git a/src/ck-manager.h b/src/ck-manager.h
index a6fd670..652435e 100644
--- a/src/ck-manager.h
+++ b/src/ck-manager.h
@@ -58,7 +58,8 @@ typedef struct
typedef enum
{
- CK_MANAGER_ERROR_GENERAL
+ CK_MANAGER_ERROR_GENERAL,
+ CK_MANAGER_ERROR_NOT_PRIVILEGED
} CkManagerError;
#define CK_MANAGER_ERROR ck_manager_error_quark ()
@@ -70,6 +71,13 @@ CkManager * ck_manager_new (void);
/* unprivileged methods */
+
+/* System actions */
+gboolean ck_manager_stop (CkManager *manager,
+ DBusGMethodInvocation *context);
+gboolean ck_manager_restart (CkManager *manager,
+ DBusGMethodInvocation *context);
+
/* Authoritative properties */
gboolean ck_manager_open_session (CkManager *manager,
DBusGMethodInvocation *context);
diff --git a/src/ck-manager.xml b/src/ck-manager.xml
index f40d6d5..031d8a1 100644
--- a/src/ck-manager.xml
+++ b/src/ck-manager.xml
@@ -1,6 +1,12 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/freedesktop/ConsoleKit/Manager">
<interface name="org.freedesktop.ConsoleKit.Manager">
+ <method name="Restart">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+ <method name="Stop">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
<method name="OpenSession">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="cookie" direction="out" type="s"/>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 61d60cc..dd3fbd7 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -10,8 +10,18 @@ if CK_COMPILE_LINUX
SUBDIRS += linux
endif
+if CK_COMPILE_FREEBSD
+SUBDIRS += freebsd
+endif
+
+if CK_COMPILE_SOLARIS
+SUBDIRS += solaris
+endif
+
DIST_SUBDIRS = \
linux \
+ freebsd \
+ solaris \
$(NULL)
INCLUDES = \
diff --git a/tools/freebsd/Makefile.am b/tools/freebsd/Makefile.am
new file mode 100644
index 0000000..d25930e
--- /dev/null
+++ b/tools/freebsd/Makefile.am
@@ -0,0 +1,38 @@
+## We require new-style dependency handling.
+AUTOMAKE_OPTIONS = 1.7
+
+NULL =
+
+SUBDIRS = \
+ $(NULL)
+
+scriptdir = $(libdir)/ConsoleKit/scripts
+script_SCRIPTS = \
+ ck-system-stop \
+ ck-system-restart \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(script_SCRIPTS) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
+
+
+check:
+ for f in $(script_SCRIPTS); do \
+ echo -n "Validate bash syntax in $$f : "; \
+ bash -n $(srcdir)/$$f 2> bash.error;\
+ if test -s bash.error; then \
+ echo failed; \
+ cat bash.error; \
+ rm -f bash.error; \
+ exit 1; \
+ else \
+ echo ok; \
+ rm -f bash.error; \
+ fi; \
+ done;
+
diff --git a/tools/freebsd/ck-system-restart b/tools/freebsd/ck-system-restart
new file mode 100755
index 0000000..8e0664e
--- /dev/null
+++ b/tools/freebsd/ck-system-restart
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -r now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -r now
+ exit $?
+else
+ exit 1
+fi
diff --git a/tools/freebsd/ck-system-stop b/tools/freebsd/ck-system-stop
new file mode 100755
index 0000000..c947bea
--- /dev/null
+++ b/tools/freebsd/ck-system-stop
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+unsupported() {
+ echo "org.freedesktop.Hal.Device.SystemPowerManagement.NotSupported" >&2
+ echo "No shutdown command found" >&2
+ exit 1
+}
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -p now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -p now
+ exit $?
+else
+ unsupported
+fi
diff --git a/tools/linux/Makefile.am b/tools/linux/Makefile.am
index 0830734..51196c0 100644
--- a/tools/linux/Makefile.am
+++ b/tools/linux/Makefile.am
@@ -6,27 +6,33 @@ NULL =
SUBDIRS = \
$(NULL)
-INCLUDES = \
- -I. \
- -I$(srcdir) \
- -I$(top_srcdir)/src \
- $(CONSOLE_KIT_CFLAGS) \
- $(DISABLE_DEPRECATED_CFLAGS) \
- -DPREFIX=\""$(prefix)"\" \
- -DBINDIR=\""$(bindir)"\" \
- -DLIBDIR=\""$(libdir)"\" \
- -DLIBEXECDIR=\""$(libexecdir)"\" \
- -DDATADIR=\""$(datadir)"\" \
- -DSYSCONFDIR=\""$(sysconfdir)"\" \
- $(WARN_CFLAGS) \
- $(DEBUG_CFLAGS) \
- $(TOOLS_CFLAGS) \
+scriptdir = $(libdir)/ConsoleKit/scripts
+script_SCRIPTS = \
+ ck-system-stop \
+ ck-system-restart \
$(NULL)
-
EXTRA_DIST = \
+ $(script_SCRIPTS) \
$(NULL)
MAINTAINERCLEANFILES = \
*~ \
Makefile.in
+
+
+check:
+ for f in $(script_SCRIPTS); do \
+ echo -n "Validate bash syntax in $$f : "; \
+ bash -n $(srcdir)/$$f 2> bash.error;\
+ if test -s bash.error; then \
+ echo failed; \
+ cat bash.error; \
+ rm -f bash.error; \
+ exit 1; \
+ else \
+ echo ok; \
+ rm -f bash.error; \
+ fi; \
+ done;
+
diff --git a/tools/linux/ck-system-restart b/tools/linux/ck-system-restart
new file mode 100755
index 0000000..8e0664e
--- /dev/null
+++ b/tools/linux/ck-system-restart
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -r now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -r now
+ exit $?
+else
+ exit 1
+fi
diff --git a/tools/linux/ck-system-stop b/tools/linux/ck-system-stop
new file mode 100755
index 0000000..e26bca3
--- /dev/null
+++ b/tools/linux/ck-system-stop
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -h now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -h now
+ exit $?
+else
+ exit 1
+fi
diff --git a/tools/solaris/Makefile.am b/tools/solaris/Makefile.am
new file mode 100644
index 0000000..d25930e
--- /dev/null
+++ b/tools/solaris/Makefile.am
@@ -0,0 +1,38 @@
+## We require new-style dependency handling.
+AUTOMAKE_OPTIONS = 1.7
+
+NULL =
+
+SUBDIRS = \
+ $(NULL)
+
+scriptdir = $(libdir)/ConsoleKit/scripts
+script_SCRIPTS = \
+ ck-system-stop \
+ ck-system-restart \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(script_SCRIPTS) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
+
+
+check:
+ for f in $(script_SCRIPTS); do \
+ echo -n "Validate bash syntax in $$f : "; \
+ bash -n $(srcdir)/$$f 2> bash.error;\
+ if test -s bash.error; then \
+ echo failed; \
+ cat bash.error; \
+ rm -f bash.error; \
+ exit 1; \
+ else \
+ echo ok; \
+ rm -f bash.error; \
+ fi; \
+ done;
+
diff --git a/tools/solaris/ck-system-restart b/tools/solaris/ck-system-restart
new file mode 100755
index 0000000..8e0664e
--- /dev/null
+++ b/tools/solaris/ck-system-restart
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -r now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -r now
+ exit $?
+else
+ exit 1
+fi
diff --git a/tools/solaris/ck-system-stop b/tools/solaris/ck-system-stop
new file mode 100755
index 0000000..e26bca3
--- /dev/null
+++ b/tools/solaris/ck-system-stop
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#Try for common tools
+if [ -x "/sbin/shutdown" ] ; then
+ /sbin/shutdown -h now
+ exit $?
+elif [ -x "/usr/sbin/shutdown" ] ; then
+ /usr/sbin/shutdown -h now
+ exit $?
+else
+ exit 1
+fi