hal: Branch 'master'
David Zeuthen
david at kemper.freedesktop.org
Sun Mar 25 15:25:34 PDT 2007
examples/interface-locking-test.py | 51 ++++
examples/mandatory-locking-test.py | 20 -
hald/access-check.c | 113 ++++++++++
hald/access-check.h | 4
hald/device.c | 36 +++
hald/device.h | 4
hald/hald_dbus.c | 400 +++++++++++++++++++++++++++++++------
hald/hald_dbus.h | 4
libhal/libhal.c | 243 ++++++++++++++++++++++
libhal/libhal.h | 30 ++
tools/hal-storage-mount.c | 2
tools/hal-storage-shared.c | 23 ++
tools/hal-storage-shared.h | 2
13 files changed, 843 insertions(+), 89 deletions(-)
New commits:
diff-tree ce1a29366fa816ade302159db0f64efe8000d310 (from f7cb7e7828ae6d54f06dad49b63b0f8c0a553a41)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun Mar 25 18:25:32 2007 -0400
add interface locking and remove generic locking API committed yesterday
Now to write some docs how all this works...
diff --git a/examples/interface-locking-test.py b/examples/interface-locking-test.py
new file mode 100755
index 0000000..ff0c7dd
--- /dev/null
+++ b/examples/interface-locking-test.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+
+import dbus
+import sys
+import time
+import os
+
+# this is just various test code
+
+bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+
+manager = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/Manager"),
+ "org.freedesktop.Hal.Manager")
+
+computer = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/computer"),
+ "org.freedesktop.Hal.Device")
+
+# "/org/freedesktop/Hal/devices/volume_uuid_456C_AAA8"),
+
+device = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/macbook_pro_keyboard_backlight"),
+ "org.freedesktop.Hal.Device")
+device2 = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/macbook_pro_keyboard_backlight"),
+ "org.freedesktop.Hal.Device.KeyboardBacklight")
+
+device3 = dbus.Interface(bus.get_object("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/storage_serial_Kingston_DataTraveler_2_0_07F0E4611101494D"),
+ "org.freedesktop.Hal.Device")
+
+manager.AcquireGlobalInterfaceLock("org.freedesktop.Hal.Device.Storage", True)
+time.sleep(10000)
+
+#device3.AcquireInterfaceLock("org.freedesktop.Hal.Device.Storage", True)
+#time.sleep(100000)
+
+#manager.AcquireGlobalInterfaceLock("org.freedesktop.Hal.Device.KeyboardBacklight")
+#device.AcquireInterfaceLock("org.freedesktop.Hal.Device.KeyboardBacklight")
+#n = 0
+#while True:
+# time.sleep(1)
+# device2.SetBrightness (n)
+# n = n + 10
+# if (n > 200):
+# n = 0
+#manager.ReleaseGlobalInterfaceLock("org.freedesktop.Hal.Device.KeyboardBacklight")
+#device.ReleaseInterfaceLock("org.freedesktop.Hal.Device.KeyboardBacklight")
+
diff --git a/examples/mandatory-locking-test.py b/examples/mandatory-locking-test.py
deleted file mode 100755
index d863814..0000000
--- a/examples/mandatory-locking-test.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/python
-
-
-import dbus
-import sys
-import time
-import os
-
-bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
-device = dbus.Interface(bus.get_object("org.freedesktop.Hal",
- "/org/freedesktop/Hal/devices/computer"),
-# "/org/freedesktop/Hal/devices/volume_label_EOS_DIGITAL"),
- "org.freedesktop.Hal.Device")
-
-device.AcquireMandatoryLock("foo")
-device.AcquireMandatoryLock("foo2")
-time.sleep(2)
-device.ReleaseMandatoryLock("foo2")
-#device.ReleaseMandatoryLock("foo")
-time.sleep(2)
diff --git a/hald/access-check.c b/hald/access-check.c
index b001eea..d96ddaa 100644
--- a/hald/access-check.c
+++ b/hald/access-check.c
@@ -38,6 +38,7 @@
#include <dbus/dbus.h>
#include <glib.h>
+#include "hald.h"
#include "logger.h"
#include "access-check.h"
@@ -107,6 +108,7 @@ out:
/**
* access_check_caller_have_access_to_device:
+ * @cit: the CITracker object
* @device: The device to check for
* @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller
*
@@ -169,3 +171,114 @@ out:
return TRUE;
}
#endif
+
+/**
+ * access_check_caller_locked_out:
+ * @cit: the CITracker object
+ * @device: The device to check for
+ * @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller
+ * @interface_name: the interface to check for
+ *
+ * This method determines if a caller is locked out to access a given
+ * interface on a given device. A caller is locked out when:
+ *
+ * 1. Another caller is holding a lock on the interface on the device
+ * non-withstanding that the caller to check for holds the lock
+ * himself.
+ *
+ * 2. Another caller is holding the global lock for the interface on
+ * the root computer device object and that other caller has
+ * access to the device in question.
+ *
+ * (In other words, a client Foo can grab a lock on the root
+ * computer device object, but that doesn't mean Foo can lock
+ * other clients out of devices that Foo doesn't have access to.)
+ *
+ * Specifically a caller is not locked out if he has locked the
+ * interface and he is the only one holding the lock. However, if two
+ * clients have a lock on a device neither of them can access the
+ * device.
+ *
+ * Returns: TRUE iff the caller is locked out
+ */
+gboolean
+access_check_caller_locked_out (CITracker *cit,
+ HalDevice *device,
+ const char *caller_unique_sysbus_name,
+ const char *interface_name)
+{
+ int n;
+ gboolean ret;
+ char *global_lock_name;
+ char **holders;
+ char **global_holders;
+ HalDevice *computer;
+
+ global_lock_name = NULL;
+ holders = NULL;
+ global_holders = NULL;
+ ret = TRUE;
+
+ computer = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
+ if (computer == NULL)
+ computer = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
+ if (computer == NULL)
+ goto out;
+
+ global_lock_name = g_strdup_printf ("Global.%s", interface_name);
+
+ holders = hal_device_get_lock_holders (device, interface_name);
+ global_holders = hal_device_get_lock_holders (computer, global_lock_name);
+
+ /* check if there are other holders than us - these are
+ * assumed to have access to the device since they got to hold
+ * the lock in the first place.
+ */
+ if (holders != NULL) {
+ for (n = 0; holders[n] != NULL; n++) {
+ if (strcmp (holders[n], caller_unique_sysbus_name) != 0) {
+ /* Yup, there's someone else... can't do it Sally */
+ HAL_INFO (("Caller '%s' is locked out of interface '%s' on device '%s' "
+ "because caller '%s' got a lock on the interface on the device",
+ caller_unique_sysbus_name,
+ interface_name,
+ hal_device_get_udi (device),
+ holders[n]));
+ goto out;
+ }
+ }
+ }
+
+ if (global_holders != NULL) {
+ for (n = 0; global_holders[n] != NULL; n++) {
+ if (strcmp (global_holders[n], caller_unique_sysbus_name) != 0) {
+ /* Someone else is holding the global
+ * lock.. check if that someone actually have
+ * access to the device...
+ */
+ if (access_check_caller_have_access_to_device (cit, device, global_holders[n])) {
+ /* They certainly do. Give up. */
+
+ HAL_INFO (("Caller '%s' is locked out of interface '%s' on device '%s' "
+ "because caller '%s' got a lock on the global interface and "
+ "have access to the device",
+ caller_unique_sysbus_name,
+ interface_name,
+ hal_device_get_udi (device),
+ global_holders[n]));
+ goto out;
+ }
+ }
+ }
+ }
+
+ /* done all the checks so we're not locked out */
+ ret = FALSE;
+
+out:
+ g_strfreev (global_holders);
+ g_strfreev (holders);
+ g_free (global_lock_name);
+ return ret;
+}
+
diff --git a/hald/access-check.h b/hald/access-check.h
index 8514824..ab05f07 100644
--- a/hald/access-check.h
+++ b/hald/access-check.h
@@ -36,5 +36,9 @@ gboolean access_check_message_caller_is_
gboolean access_check_caller_have_access_to_device (CITracker *cit,
HalDevice *device,
const char *caller_unique_sysbus_name);
+gboolean access_check_caller_locked_out (CITracker *cit,
+ HalDevice *device,
+ const char *caller_unique_sysbus_name,
+ const char *interface_name);
#endif /* ACCESS_CHECK_H */
diff --git a/hald/device.c b/hald/device.c
index 81cfa91..a471d2c 100644
--- a/hald/device.c
+++ b/hald/device.c
@@ -1622,23 +1622,31 @@ hal_device_are_all_addons_ready (HalDevi
* Returns: FALSE if the caller already holds this lock. TRUE if the caller got the lock.
*/
gboolean
-hal_device_acquire_lock (HalDevice *device, const char *lock_name, const char *sender)
+hal_device_acquire_lock (HalDevice *device, const char *lock_name, gboolean exclusive, const char *sender)
{
gboolean ret;
char buf[256];
ret = FALSE;
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.exclusive", lock_name);
+ if (hal_device_property_get_bool (device, buf) == TRUE) {
+ /* exclusively locked */
+ goto out;
+ }
+ hal_device_property_set_bool (device, buf, exclusive);
+
g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
if (hal_device_property_strlist_contains (device, buf, sender)) {
/* already locked */
goto out;
}
+
hal_device_property_strlist_append (device, buf, sender);
g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
hal_device_property_set_bool (device, buf, TRUE);
- hal_device_property_strlist_append (device, "info.named_locks", lock_name);
+ hal_device_property_strlist_add (device, "info.named_locks", lock_name);
add_to_locked_set (device);
@@ -1681,6 +1689,8 @@ hal_device_release_lock (HalDevice *devi
if (hal_device_property_get_strlist_length (device, buf) == 1) {
/* last one to hold the lock */
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.exclusive", lock_name);
+ hal_device_property_remove (device, buf);
g_snprintf (buf, sizeof (buf), "info.named_locks.%s.locked", lock_name);
hal_device_property_remove (device, buf);
g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
@@ -1704,6 +1714,28 @@ out:
}
/**
+ * hal_device_get_lock_holders:
+ * @device: the device to check for
+ * @lock_name: the lock name
+ *
+ * Get the lock holders on a device.
+ *
+ * Returns: NULL if there are no lock holders; otherwise a
+ * NULL-terminated array of strings with the dbus names of the
+ * holders. Caller must free this with g_strfreev().
+ */
+char **
+hal_device_get_lock_holders (HalDevice *device, const char *lock_name)
+{
+ char **ret;
+ char buf[256];
+
+ g_snprintf (buf, sizeof (buf), "info.named_locks.%s.dbus_name", lock_name);
+ ret = hal_device_property_dup_strlist_as_strv (device, buf);
+ return ret;
+}
+
+/**
* hal_device_client_disconnected:
* @sender: the client that disconnected from the bus
*
diff --git a/hald/device.h b/hald/device.h
index 774d3dc..5dd11f5 100644
--- a/hald/device.h
+++ b/hald/device.h
@@ -206,10 +206,12 @@ gboolean hal_device_inc_num_ready_a
gboolean hal_device_are_all_addons_ready (HalDevice *device);
-gboolean hal_device_acquire_lock (HalDevice *device, const char *lock_name, const char *sender);
+gboolean hal_device_acquire_lock (HalDevice *device, const char *lock_name, gboolean exclusive, const char *sender);
gboolean hal_device_release_lock (HalDevice *device, const char *lock_name, const char *sender);
+char **hal_device_get_lock_holders (HalDevice *device, const char *lock_name);
+
/* static method */
void hal_device_client_disconnected (const char *sender);
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index 798e093..2df8e0d 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -223,13 +223,16 @@ raise_device_already_locked (DBusConnect
const char *reason;
reason = hal_device_property_get_string (device, "info.locked.reason");
- HAL_WARNING (("Device %s is already locked: %s",
- hal_device_get_udi (device), reason));
+ if (reason != NULL) {
+ HAL_WARNING (("Device %s is already locked: %s", hal_device_get_udi (device), reason));
+ } else {
+ HAL_WARNING (("Device %s is already locked", hal_device_get_udi (device)));
+ }
reply = dbus_message_new_error (in_reply_to,
"org.freedesktop.Hal.DeviceAlreadyLocked",
- reason);
+ reason != NULL ? reason : "Device is already locked");
if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
DIE (("No memory"));
@@ -237,7 +240,7 @@ raise_device_already_locked (DBusConnect
dbus_message_unref (reply);
}
-/**
+/**
* raise_permission_denied:
* @connection: D-Bus connection
* @in_reply_to: message to report error on
@@ -259,6 +262,64 @@ raise_permission_denied (DBusConnection
}
+/**
+ * raise_interface_locked:
+ * @connection: D-Bus connection
+ * @in_reply_to: message to report error on
+ * @interface: the interface that is locked
+ *
+ * Raise the org.freedesktop.Hal.Device.InterfaceLocked error
+ */
+static void
+raise_interface_locked (DBusConnection *connection,
+ DBusMessage *in_reply_to,
+ const char *interface)
+{
+ raise_error (connection, in_reply_to,
+ "org.freedesktop.Hal.Device.InterfaceLocked",
+ "The interface %s is locked by someone else",
+ interface);
+}
+
+/**
+ * raise_interface_locked:
+ * @connection: D-Bus connection
+ * @in_reply_to: message to report error on
+ * @interface: the interface that is locked
+ *
+ * Raise the org.freedesktop.Hal.Device.InterfaceLocked error
+ */
+static void
+raise_interface_already_locked (DBusConnection *connection,
+ DBusMessage *in_reply_to,
+ const char *interface)
+{
+ raise_error (connection, in_reply_to,
+ "org.freedesktop.Hal.Device.InterfaceAlreadyLocked",
+ "The interface %s is already exclusively locked either by someone else or it's already locked by yourself",
+ interface);
+}
+
+/**
+ * raise_interface_locked:
+ * @connection: D-Bus connection
+ * @in_reply_to: message to report error on
+ * @interface: the interface that is locked
+ *
+ * Raise the org.freedesktop.Hal.Device.InterfaceLocked error
+ */
+static void
+raise_interface_not_locked (DBusConnection *connection,
+ DBusMessage *in_reply_to,
+ const char *interface)
+{
+ raise_error (connection, in_reply_to,
+ "org.freedesktop.Hal.Device.InterfaceNotLocked",
+ "The interface %s is not locked by you",
+ interface);
+}
+
+
static gboolean
foreach_device_get_udi (HalDeviceStore *store, HalDevice *device,
gpointer user_data)
@@ -1814,31 +1875,17 @@ device_query_capability (DBusConnection
return DBUS_HANDLER_RESULT_HANDLED;
}
-/**
- * device_acquire_mandatory_lock:
- * @connection: D-BUS connection
- * @message: Message
- *
- * Returns: What to do with the message
- *
- * Acquire a named mandatory lock on a device.
- *
- * <pre>
- * void Device.AcquireMandatoryLock(string lock_name)
- *
- * raises org.freedesktop.Hal.NoSuchDevice,
- * org.freedesktop.Hal.DeviceAlreadyLocked (if the caller already got a lock on the device with the given name)
- * </pre>
- */
-DBusHandlerResult
-device_acquire_mandatory_lock (DBusConnection *connection, DBusMessage *message)
+/*------------------------------------------------------------------------*/
+static DBusHandlerResult
+device_acquire_interface_lock (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
{
const char *udi;
HalDevice *d;
DBusMessage *reply;
DBusError error;
- char *lock_name;
+ char *interface_name;
const char *sender;
+ gboolean exclusive;
HAL_TRACE (("entering"));
@@ -1853,18 +1900,82 @@ device_acquire_mandatory_lock (DBusConne
return DBUS_HANDLER_RESULT_HANDLED;
}
+ sender = dbus_message_get_sender (message);
+
+ if (!local_interface) {
+ if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) {
+ raise_permission_denied (connection, message, "AcquireInterfaceLock: no access to device");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+
dbus_error_init (&error);
if (!dbus_message_get_args (message, &error,
- DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_BOOLEAN, &exclusive,
DBUS_TYPE_INVALID)) {
- raise_syntax (connection, message, "AqcuireMandatoryLock");
+ raise_syntax (connection, message, "AqcuireInterfaceLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (!hal_device_acquire_lock (d, interface_name, exclusive, sender)) {
+ raise_interface_already_locked (connection, message, interface_name);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+device_release_interface_lock (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ const char *sender;
+ char *interface_name;
+
+ HAL_TRACE (("entering"));
+
+ udi = dbus_message_get_path (message);
+
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+
+ if (d == NULL) {
+ raise_no_such_device (connection, message, udi);
return DBUS_HANDLER_RESULT_HANDLED;
}
sender = dbus_message_get_sender (message);
- if (!hal_device_acquire_lock (d, lock_name, sender)) {
- raise_device_already_locked (connection, message, d);
+ if (!local_interface) {
+ if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) {
+ raise_permission_denied (connection, message, "ReleaseInterfaceLock: no access to device");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "ReleaseInterfaceLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (!hal_device_release_lock (d, interface_name, sender)) {
+ raise_interface_not_locked (connection, message, interface_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1879,31 +1990,19 @@ device_acquire_mandatory_lock (DBusConne
return DBUS_HANDLER_RESULT_HANDLED;
}
-/**
- * device_release_mandatory_lock:
- * @connection: D-BUS connection
- * @message: Message
- *
- * Returns: What to do with the message
- *
- * Released a named mandatory lock on a device.
- *
- * <pre>
- * void Device.ReleaseMandatoryLock(string lock_name)
- *
- * raises org.freedesktop.Hal.NoSuchDevice,
- * org.freedesktop.Hal.DeviceNotLocked (if the caller haven't a lock on the device with the given name)
- * </pre>
- */
-DBusHandlerResult
-device_release_mandatory_lock (DBusConnection *connection, DBusMessage *message)
+
+static DBusHandlerResult
+device_is_caller_locked_out (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
{
const char *udi;
HalDevice *d;
DBusMessage *reply;
DBusError error;
const char *sender;
- char *lock_name;
+ char *interface_name;
+ char *caller_sysbus_name;
+ dbus_bool_t result;
+ DBusMessageIter iter;
HAL_TRACE (("entering"));
@@ -1918,20 +2017,154 @@ device_release_mandatory_lock (DBusConne
return DBUS_HANDLER_RESULT_HANDLED;
}
+ sender = dbus_message_get_sender (message);
+
+ /* only allow HAL helpers to ask this question */
+ if (!local_interface) {
+ raise_permission_denied (connection, message, "IsCallerLockedOut: not privileged");
+ }
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_STRING, &caller_sysbus_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "ReleaseInterfaceLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ result = access_check_caller_locked_out (ci_tracker, d, caller_sysbus_name, interface_name);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &result);
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/*------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+device_acquire_global_interface_lock (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ char *interface_name;
+ char *lock_name;
+ const char *sender;
+ gboolean exclusive;
+
+ HAL_TRACE (("entering"));
+
+ udi = "/org/freedesktop/Hal/devices/computer";
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+
+ if (d == NULL) {
+ raise_no_such_device (connection, message, udi);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ sender = dbus_message_get_sender (message);
+
+ /* no security checks; global locks are special; anyone can
+ * take them but it might not have any effect... a global lock
+ * will only have effect if a lock owner have access to the
+ * device - see the function
+ *
+ * hald/access-check.c:access_check_caller_locked_out()
+ *
+ * for details.
+ */
+
dbus_error_init (&error);
if (!dbus_message_get_args (message, &error,
- DBUS_TYPE_STRING, &lock_name,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_BOOLEAN, &exclusive,
DBUS_TYPE_INVALID)) {
- raise_syntax (connection, message, "ReleaseMandatoryLock");
+ raise_syntax (connection, message, "AqcuireGlobalInterfaceLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ lock_name = g_strdup_printf ("Global.%s", interface_name);
+ if (!hal_device_acquire_lock (d, lock_name, exclusive, sender)) {
+ raise_interface_already_locked (connection, message, interface_name);
+ g_free (lock_name);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ g_free (lock_name);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ DIE (("No memory"));
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ DIE (("No memory"));
+
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+device_release_global_interface_lock (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
+{
+ const char *udi;
+ HalDevice *d;
+ DBusMessage *reply;
+ DBusError error;
+ const char *sender;
+ char *interface_name;
+ char *lock_name;
+
+ HAL_TRACE (("entering"));
+
+ udi = "/org/freedesktop/Hal/devices/computer";
+ d = hal_device_store_find (hald_get_gdl (), udi);
+ if (d == NULL)
+ d = hal_device_store_find (hald_get_tdl (), udi);
+
+ if (d == NULL) {
+ raise_no_such_device (connection, message, udi);
return DBUS_HANDLER_RESULT_HANDLED;
}
sender = dbus_message_get_sender (message);
- if (!hal_device_release_lock (d, lock_name, sender)) {
- raise_device_already_locked (connection, message, d);
+ /* no security checks; global locks are special; anyone can
+ * take them but it might not have any effect... a global lock
+ * will only have effect if a lock owner have access to the
+ * device - see the function
+ *
+ * hald/access-check.c:access_check_caller_locked_out()
+ *
+ * for details.
+ */
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_INVALID)) {
+ raise_syntax (connection, message, "ReleaseGlobalInterfaceLock");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ lock_name = g_strdup_printf ("Global.%s", interface_name);
+ if (!hal_device_release_lock (d, interface_name, sender)) {
+ raise_interface_not_locked (connection, message, interface_name);
+ g_free (lock_name);
return DBUS_HANDLER_RESULT_HANDLED;
}
+ g_free (lock_name);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@@ -3464,6 +3697,14 @@ do_introspect (DBusConnection *connecti
" <arg name=\"global_udi\" direction=\"in\" type=\"s\"/>\n"
" </method>\n"
+ " <method name=\"AcquireGlobalInterfaceLock\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " <arg name=\"exclusive\" direction=\"in\" type=\"b\"/>\n"
+ " </method>\n"
+ " <method name=\"ReleaseGlobalInterfaceLock\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+
" <signal name=\"DeviceAdded\">\n"
" <arg name=\"udi\" type=\"s\"/>\n"
" </signal>\n"
@@ -3571,11 +3812,17 @@ do_introspect (DBusConnection *connecti
" <arg name=\"released_lock\" direction=\"out\" type=\"b\"/>\n"
" </method>\n"
- " <method name=\"AcquireMandatoryLock\">\n"
- " <arg name=\"lock_name\" direction=\"in\" type=\"s\"/>\n"
+ " <method name=\"AcquireInterfaceLock\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " <arg name=\"exclusive\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
- " <method name=\"ReleaseMandatoryLock\">\n"
- " <arg name=\"lock_name\" direction=\"in\" type=\"s\"/>\n"
+ " <method name=\"ReleaseInterfaceLock\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"IsCallerLockedOut\">\n"
+ " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+ " <arg name=\"caller_sysbus_name\" direction=\"in\" type=\"s\"/>\n"
+ " <arg name=\"whether_caller_is_locked_out\" direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"StringListAppend\">\n"
@@ -3822,6 +4069,31 @@ hald_dbus_filter_handle_methods (DBusCon
strcmp (dbus_message_get_path (message),
"/org/freedesktop/Hal/Manager") == 0) {
return manager_commit_to_gdl (connection, message, local_interface);
+
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Manager",
+ "AcquireGlobalInterfaceLock") &&
+ strcmp (dbus_message_get_path (message), "/org/freedesktop/Hal/Manager") == 0) {
+ return device_acquire_global_interface_lock (connection, message, local_interface);
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Manager",
+ "ReleaseGlobalInterfaceLock") &&
+ strcmp (dbus_message_get_path (message), "/org/freedesktop/Hal/Manager") == 0) {
+ return device_release_global_interface_lock (connection, message, local_interface);
+
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
+ "AcquireInterfaceLock")) {
+ return device_acquire_interface_lock (connection, message, local_interface);
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
+ "ReleaseInterfaceLock")) {
+ return device_release_interface_lock (connection, message, local_interface);
+ } else if (dbus_message_is_method_call (message,
+ "org.freedesktop.Hal.Device",
+ "IsCallerLockedOut")) {
+ return device_is_caller_locked_out (connection, message, local_interface);
+
} else if (dbus_message_is_method_call (message,
"org.freedesktop.Hal.Device",
"GetAllProperties")) {
@@ -3904,14 +4176,6 @@ hald_dbus_filter_handle_methods (DBusCon
return device_unlock (connection, message);
} else if (dbus_message_is_method_call (message,
"org.freedesktop.Hal.Device",
- "AcquireMandatoryLock")) {
- return device_acquire_mandatory_lock (connection, message);
- } else if (dbus_message_is_method_call (message,
- "org.freedesktop.Hal.Device",
- "ReleaseMandatoryLock")) {
- return device_release_mandatory_lock (connection, message);
- } else if (dbus_message_is_method_call (message,
- "org.freedesktop.Hal.Device",
"StringListAppend")) {
return device_string_list_append_prepend (connection, message, FALSE);
} else if (dbus_message_is_method_call (message,
@@ -4001,6 +4265,18 @@ hald_dbus_filter_handle_methods (DBusCon
}
}
+ /* check if the interface on the device is locked by someone else
+ *
+ * Note that method implementations can and will do their own
+ * checks too; e.g. operations on org.freedesktop.Hal.Device.Volume
+ * will check if the interface org.freedesktop.Hal.Device.Storage
+ * is locked on the enclosing drive.
+ */
+ if (access_check_caller_locked_out (ci_tracker, d, caller, interface)) {
+ raise_interface_locked (connection, message, interface);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
/* first see if an addon grabbed the interface */
for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
HelperInterfaceHandler *hih = i->data;
diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h
index 3fba19d..d7f9acc 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -64,10 +64,6 @@ DBusHandlerResult device_lock
DBusMessage *message);
DBusHandlerResult device_unlock (DBusConnection *connection,
DBusMessage *message);
-DBusHandlerResult device_acquire_mandatory_lock (DBusConnection *connection,
- DBusMessage *message);
-DBusHandlerResult device_release_mandatory_lock (DBusConnection *connection,
- DBusMessage *message);
DBusHandlerResult manager_new_device (DBusConnection *connection,
DBusMessage *message,
dbus_bool_t local_interface);
diff --git a/libhal/libhal.c b/libhal/libhal.c
index 141ad61..c9697ce 100644
--- a/libhal/libhal.c
+++ b/libhal/libhal.c
@@ -4128,3 +4128,246 @@ libhal_device_free_changeset (LibHalChan
free (changeset->udi);
free (changeset);
}
+
+
+dbus_bool_t
+libhal_device_acquire_interface_lock (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+ LIBHAL_CHECK_PARAM_VALID(udi, "*udi", FALSE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ udi,
+ "org.freedesktop.Hal.Device",
+ "AcquireInterfaceLock");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return FALSE;
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+ LIBHAL_CHECK_PARAM_VALID(udi, "*udi", FALSE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ udi,
+ "org.freedesktop.Hal.Device",
+ "ReleaseInterfaceLock");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return FALSE;
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx,
+ const char *interface,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/Manager",
+ "org.freedesktop.Hal.Device",
+ "AcquireGlobalInterfaceLock");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return FALSE;
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx,
+ const char *interface,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ "/org/freedesktop/Hal/Manager",
+ "org.freedesktop.Hal.Device",
+ "ReleaseGlobalInterfaceLock");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return FALSE;
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+dbus_bool_t
+libhal_device_is_caller_locked_out (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ const char *caller,
+ DBusError *error)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusMessageIter reply_iter;
+ dbus_bool_t value;
+
+ LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
+ LIBHAL_CHECK_PARAM_VALID(udi, "*udi", FALSE);
+ LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE);
+ LIBHAL_CHECK_PARAM_VALID(caller, "*caller", FALSE);
+
+ message = dbus_message_new_method_call ("org.freedesktop.Hal",
+ udi,
+ "org.freedesktop.Hal.Device",
+ "IsCallerLockedOut");
+
+ if (message == NULL) {
+ fprintf (stderr,
+ "%s %d : Couldn't allocate D-BUS message\n",
+ __FILE__, __LINE__);
+ return TRUE;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &caller);
+
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection,
+ message, -1,
+ error);
+
+ if (error != NULL && dbus_error_is_set (error)) {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ return TRUE;
+
+ /* now analyze reply */
+ dbus_message_iter_init (reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ return TRUE;
+ }
+ dbus_message_iter_get_basic (&reply_iter, &value);
+ dbus_message_unref (reply);
+ return value;
+}
+
diff --git a/libhal/libhal.h b/libhal/libhal.h
index acddc11..5021f87 100644
--- a/libhal/libhal.h
+++ b/libhal/libhal.h
@@ -603,6 +603,36 @@ dbus_bool_t libhal_device_claim_interfac
dbus_bool_t libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error);
+/* Take a mandatory lock on an interface on a device. */
+dbus_bool_t libhal_device_acquire_interface_lock (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error);
+
+/* Release a mandatory lock on an interface on a device. */
+dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ DBusError *error);
+
+/* Take a mandatory lock on an interface (the lock affects all devices the caller have access to). */
+dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx,
+ const char *interface,
+ DBusError *error);
+
+/* Release a mandatory lock on an interface (affects all devices the caller have access to). */
+dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx,
+ const char *interface,
+ DBusError *error);
+
+/* Determine if a given caller is locked out of a given interface on a given device */
+dbus_bool_t libhal_device_is_caller_locked_out (LibHalContext *ctx,
+ const char *udi,
+ const char *interface,
+ const char *caller,
+ DBusError *error);
+
+
#if defined(__cplusplus)
}
#endif
diff --git a/tools/hal-storage-mount.c b/tools/hal-storage-mount.c
index 6514d48..ee5c381 100644
--- a/tools/hal-storage-mount.c
+++ b/tools/hal-storage-mount.c
@@ -509,6 +509,8 @@ handle_mount (LibHalContext *hal_ctx,
bailout_if_in_fstab (hal_ctx, device, label, uuid);
+ bailout_if_drive_is_locked (hal_ctx, drive, invoked_by_syscon_name);
+
/* TODO: sanity check that what hal exports is correct (cf. Martin Pitt's email) */
/* read from stdin */
diff --git a/tools/hal-storage-shared.c b/tools/hal-storage-shared.c
index 5931cd2..6c8e9d2 100644
--- a/tools/hal-storage-shared.c
+++ b/tools/hal-storage-shared.c
@@ -204,6 +204,26 @@ fstab_close (gpointer handle)
#endif
void
+bailout_if_drive_is_locked (LibHalContext *hal_ctx, LibHalDrive *drive, const char *invoked_by_syscon_name)
+{
+ DBusError error;
+
+ if (drive != NULL) {
+ dbus_error_init (&error);
+ if (libhal_device_is_caller_locked_out (hal_ctx,
+ libhal_drive_get_udi (drive),
+ "org.freedesktop.Hal.Device.Storage",
+ invoked_by_syscon_name,
+ &error)) {
+ fprintf (stderr, "org.freedesktop.Hal.Device.InterfaceLocked\n");
+ fprintf (stderr, "The enclosing drive for the volume is locked\n");
+ exit (1);
+ }
+ }
+}
+
+
+void
unknown_error (const char *detail)
{
fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFailure\n");
@@ -303,6 +323,7 @@ handle_unmount (LibHalContext *hal_ctx,
}
}
+ bailout_if_drive_is_locked (hal_ctx, drive, invoked_by_syscon_name);
/* check hal's mtab file to verify the device to unmount is actually mounted by hal */
hal_mtab_orig = fopen ("/media/.hal-mtab", "r");
@@ -560,6 +581,8 @@ try_open_excl_again:
printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
#endif
+ bailout_if_drive_is_locked (hal_ctx, drive, invoked_by_syscon_name);
+
/* construct arguments to EJECT (e.g. /usr/bin/eject) */
na = 0;
args[na++] = EJECT;
diff --git a/tools/hal-storage-shared.h b/tools/hal-storage-shared.h
index 96cd760..529cf49 100644
--- a/tools/hal-storage-shared.h
+++ b/tools/hal-storage-shared.h
@@ -46,6 +46,8 @@ void unlock_hal_mtab (void);
void unknown_error (const char *detail);
+void bailout_if_drive_is_locked (LibHalContext *hal_ctx, LibHalDrive *drive, const char *invoked_by_syscon_name);
+
void handle_unmount (LibHalContext *hal_ctx,
#ifdef HAVE_POLKIT
LibPolKitContext *pol_ctx,
More information about the hal-commit
mailing list