diff options
author | David Zeuthen <davidz@redhat.com> | 2007-03-25 18:25:32 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2007-03-25 18:25:32 -0400 |
commit | ce1a29366fa816ade302159db0f64efe8000d310 (patch) | |
tree | 800d9482e97a6e354dfb70533e217cd03eef7542 | |
parent | f7cb7e7828ae6d54f06dad49b63b0f8c0a553a41 (diff) |
add interface locking and remove generic locking API committed yesterday
Now to write some docs how all this works...
-rwxr-xr-x | examples/interface-locking-test.py | 51 | ||||
-rwxr-xr-x | examples/mandatory-locking-test.py | 20 | ||||
-rw-r--r-- | hald/access-check.c | 113 | ||||
-rw-r--r-- | hald/access-check.h | 4 | ||||
-rw-r--r-- | hald/device.c | 36 | ||||
-rw-r--r-- | hald/device.h | 4 | ||||
-rw-r--r-- | hald/hald_dbus.c | 400 | ||||
-rw-r--r-- | hald/hald_dbus.h | 4 | ||||
-rw-r--r-- | libhal/libhal.c | 243 | ||||
-rw-r--r-- | libhal/libhal.h | 30 | ||||
-rw-r--r-- | tools/hal-storage-mount.c | 2 | ||||
-rw-r--r-- | tools/hal-storage-shared.c | 23 | ||||
-rw-r--r-- | tools/hal-storage-shared.h | 2 |
13 files changed, 843 insertions, 89 deletions
diff --git a/examples/interface-locking-test.py b/examples/interface-locking-test.py new file mode 100755 index 00000000..ff0c7ddc --- /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 d863814f..00000000 --- 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 b001eeaa..d96ddaaa 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 8514824a..ab05f074 100644 --- a/hald/access-check.h +++ b/hald/access-check.h @@ -36,5 +36,9 @@ gboolean access_check_message_caller_is_root_or_hal (CITracker *cit, 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 81cfa91c..a471d2c5 100644 --- a/hald/device.c +++ b/hald/device.c @@ -1622,23 +1622,31 @@ hal_device_are_all_addons_ready (HalDevice *device) * 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 *device, const char *lock_name, const char *s 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 774d3dc0..5dd11f57 100644 --- a/hald/device.h +++ b/hald/device.h @@ -206,10 +206,12 @@ gboolean hal_device_inc_num_ready_addons (HalDevice *device); 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 798e093e..2df8e0d0 100644 --- a/hald/hald_dbus.c +++ b/hald/hald_dbus.c @@ -223,13 +223,16 @@ raise_device_already_locked (DBusConnection *connection, 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 (DBusConnection *connection, 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 *connection, } +/** + * 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 * connection, 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 (DBusConnection *connection, DBusMessage *message) 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 (DBusConnection *connection, DBusMessage *message) 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 (DBusConnection *connection, DBusMessage *message) 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, &lock_name, + DBUS_TYPE_STRING, &interface_name, + DBUS_TYPE_STRING, &caller_sysbus_name, DBUS_TYPE_INVALID)) { - raise_syntax (connection, message, "ReleaseMandatoryLock"); + 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); - 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_BOOLEAN, &exclusive, + DBUS_TYPE_INVALID)) { + 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); + + /* 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 *connection, " <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 *connection, " <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 (DBusConnection *connection, DBusMessage *messag 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 (DBusConnection *connection, DBusMessage *messag 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 (DBusConnection *connection, DBusMessage *messag } } + /* 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 3fba19d7..d7f9accd 100644 --- a/hald/hald_dbus.h +++ b/hald/hald_dbus.h @@ -64,10 +64,6 @@ DBusHandlerResult device_lock (DBusConnection *connection, 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 141ad61c..c9697cef 100644 --- a/libhal/libhal.c +++ b/libhal/libhal.c @@ -4128,3 +4128,246 @@ libhal_device_free_changeset (LibHalChangeSet *changeset) 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 acddc118..5021f877 100644 --- a/libhal/libhal.h +++ b/libhal/libhal.h @@ -603,6 +603,36 @@ dbus_bool_t libhal_device_claim_interface (LibHalContext *ctx, 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 6514d48e..ee5c3813 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 5931cd21..6c8e9d2b 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 96cd7607..529cf493 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, |