diff options
Diffstat (limited to 'hald')
-rw-r--r-- | hald/access-check.c | 122 | ||||
-rw-r--r-- | hald/access-check.h | 5 | ||||
-rw-r--r-- | hald/ci-tracker.c | 26 | ||||
-rw-r--r-- | hald/ci-tracker.h | 1 | ||||
-rw-r--r-- | hald/device.c | 77 | ||||
-rw-r--r-- | hald/device.h | 10 | ||||
-rw-r--r-- | hald/device_store.c | 63 | ||||
-rw-r--r-- | hald/device_store.h | 10 | ||||
-rw-r--r-- | hald/hald.c | 35 | ||||
-rw-r--r-- | hald/hald_dbus.c | 305 | ||||
-rw-r--r-- | hald/hald_dbus.h | 6 | ||||
-rw-r--r-- | hald/hald_marshal.list | 2 |
12 files changed, 626 insertions, 36 deletions
diff --git a/hald/access-check.c b/hald/access-check.c index 6f0542b6..ab68ce4f 100644 --- a/hald/access-check.c +++ b/hald/access-check.c @@ -110,17 +110,30 @@ 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 + * @privilege: the type of access; right now this can be #NULL or + * "lock"; will be replaced by PolicyKit privileges in the future + * @caller_unique_sysbus_name: The unique system bus connection + * name (e.g. ":1.43") of the caller * * Determine if a given caller should have access to a device. This * depends on how the security is set up and may change according to * how the system is configured. * - * If ConsoleKit is used this function currently will return TRUE if, - * and only if, the caller is in an active session. TODO: once - * multi-seat is properly supported it will also depend on what seat - * the device belongs to and what seat the caller's session belongs - * to. + * If the privilege parameter is #NULL, it means "check if the caller + * can access D-Bus interfaces". If it is "lock" it means "check if + * the caller can lock an interface on the device". + * + * If ConsoleKit is used this function currently will return TRUE when + * privilege is #NULL if, and only if, the caller is in an active + * local session. If privilege is "lock" the only difference is that + * the it will always return TRUE for the root computer device + * object. This is used to ensure that any caller can always lock the + * SystemPowerManagement interface cf. the "Locking Guidelines" + * section of the HAL spec. + * + * (TODO: once PolicyKit and multi-seat is properly supported, this + * result from this function will also depend on what seat the device + * belongs to and what seat the caller's session belongs to.) * * If ConsoleKit is not used, this function will just return TRUE; the * OS vendor is supposed to have locked down access to HAL through OS @@ -132,7 +145,7 @@ out: * Returns: TRUE iff the caller have access to the device. */ gboolean -access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, const char *caller_unique_sysbus_name) +access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, const char *privilege, const char *caller_unique_sysbus_name) #ifdef HAVE_CONKIT { gboolean ret; @@ -152,19 +165,30 @@ access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, co goto out; } + /* must be tracked by ConsoleKit */ if (ci_tracker_caller_get_ck_session_path (ci) == NULL) { goto out; } + /* require caller to be local */ + if (!ci_tracker_caller_is_local (ci)) + goto out; - if (!ci_tracker_caller_in_active_session (ci)) { + /* allow inactive sessions to lock interfaces on root computer device object */ + if (privilege != NULL && + strcmp (privilege, "lock") == 0 && + strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) { + ret = TRUE; goto out; } - + + /* require caller to be in active session */ + if (!ci_tracker_caller_in_active_session (ci)) + goto out; + ret = TRUE; out: return ret; - } #else /* HAVE_CONKIT */ { @@ -254,7 +278,7 @@ access_check_caller_locked_out (CITracker *cit, for (n = 0; global_holders[n] != NULL; n++) { if (strcmp (global_holders[n], caller_unique_sysbus_name) == 0) { /* we are holding the global lock... */ - if (access_check_caller_have_access_to_device (cit, device, global_holders[n])) { + if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) { /* only applies if the caller can access the device... */ is_locked_by_self = TRUE; /* this is good enough; we are holding the lock ourselves */ @@ -265,7 +289,7 @@ access_check_caller_locked_out (CITracker *cit, /* 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])) { + if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) { /* They certainly do. Mark as locked. */ is_locked = TRUE; } @@ -293,3 +317,77 @@ out: return ret; } + + +/** + * access_check_locked_by_others: + * @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 other processes than the caller holds a lock + * on the given device. + * + * Returns: TRUE iff other processes is holding a lock on the device + */ +gboolean +access_check_locked_by_others (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); + + if (holders != NULL) { + for (n = 0; holders[n] != NULL; n++) { + if (strcmp (holders[n], caller_unique_sysbus_name) != 0) { + /* someone else is holding the lock */ + 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... */ + if (access_check_caller_have_access_to_device (cit, device, NULL, global_holders[n])) { + /* ... and they can can access the device */ + goto out; + } + } + } + } + + /* done all the checks so noone else is locking... */ + 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 ab05f074..3da49ed4 100644 --- a/hald/access-check.h +++ b/hald/access-check.h @@ -35,10 +35,15 @@ gboolean access_check_message_caller_is_root_or_hal (CITracker *cit, DBusMessage *message); gboolean access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, + const char *privilege, 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); +gboolean access_check_locked_by_others (CITracker *cit, + HalDevice *device, + const char *caller_unique_sysbus_name, + const char *interface_name); #endif /* ACCESS_CHECK_H */ diff --git a/hald/ci-tracker.c b/hald/ci-tracker.c index 6a8bd816..af836547 100644 --- a/hald/ci-tracker.c +++ b/hald/ci-tracker.c @@ -52,6 +52,7 @@ struct CICallerInfo_s { #ifdef HAVE_CONKIT pid_t pid; /* process ID of caller */ gboolean in_active_session; /* caller is in an active session */ + gboolean is_local; /* session is on a local seat */ char *session_objpath; /* obj path of ConsoleKit session */ #endif char *system_bus_unique_name; /* unique name of caller on the system bus */ @@ -261,6 +262,25 @@ ci_tracker_get_info (CITracker *cit, const char *system_bus_unique_name) dbus_message_iter_get_basic (&iter, &ci->in_active_session); dbus_message_unref (message); dbus_message_unref (reply); + + + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + ci->session_objpath, + "org.freedesktop.ConsoleKit.Session", + "IsLocal"); + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (cit->dbus_connection, message, -1, &error); + if (reply == NULL || dbus_error_is_set (&error)) { + HAL_WARNING (("Error doing IsLocal on ConsoleKit: %s: %s", error.name, error.message)); + dbus_message_unref (message); + if (reply != NULL) + dbus_message_unref (reply); + goto error; + } + dbus_message_iter_init (reply, &iter); + dbus_message_iter_get_basic (&iter, &ci->is_local); + dbus_message_unref (message); + dbus_message_unref (reply); store_caller_info: #endif /* HAVE_CONKIT */ @@ -311,6 +331,12 @@ ci_tracker_caller_get_pid (CICallerInfo *ci) } gboolean +ci_tracker_caller_is_local (CICallerInfo *ci) +{ + return ci->is_local; +} + +gboolean ci_tracker_caller_in_active_session (CICallerInfo *ci) { return ci->in_active_session; diff --git a/hald/ci-tracker.h b/hald/ci-tracker.h index 7d762e98..5b0794a7 100644 --- a/hald/ci-tracker.h +++ b/hald/ci-tracker.h @@ -63,6 +63,7 @@ uid_t ci_tracker_caller_get_uid (CICallerInfo *ci); const char *ci_tracker_caller_get_sysbus_unique_name (CICallerInfo *ci); #ifdef HAVE_CONKIT pid_t ci_tracker_caller_get_pid (CICallerInfo *ci); +gboolean ci_tracker_caller_is_local (CICallerInfo *ci); gboolean ci_tracker_caller_in_active_session (CICallerInfo *ci); const char *ci_tracker_caller_get_ck_session_path (CICallerInfo *ci); #endif diff --git a/hald/device.c b/hald/device.c index f1f58477..e95cc19f 100644 --- a/hald/device.c +++ b/hald/device.c @@ -376,6 +376,8 @@ struct _HalDevicePrivate enum { PROPERTY_CHANGED, CAPABILITY_ADDED, + LOCK_ACQUIRED, + LOCK_RELEASED, LAST_SIGNAL }; @@ -441,6 +443,30 @@ hal_device_class_init (HalDeviceClass *klass) hald_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[LOCK_ACQUIRED] = + g_signal_new ("lock_acquired", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (HalDeviceClass, + lock_acquired), + NULL, NULL, + hald_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[LOCK_RELEASED] = + g_signal_new ("lock_released", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (HalDeviceClass, + lock_released), + NULL, NULL, + hald_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); } static void @@ -1654,6 +1680,8 @@ hal_device_acquire_lock (HalDevice *device, const char *lock_name, gboolean excl add_to_locked_set (device); + g_signal_emit (device, signals[LOCK_ACQUIRED], 0, lock_name, sender); + ret = TRUE; out: return ret; @@ -1711,6 +1739,8 @@ hal_device_release_lock (HalDevice *device, const char *lock_name, const char *s hal_device_property_strlist_remove (device, buf, sender); } + g_signal_emit (device, signals[LOCK_RELEASED], 0, lock_name, sender); + ret = TRUE; out: @@ -1740,6 +1770,32 @@ hal_device_get_lock_holders (HalDevice *device, const char *lock_name) } /** + * hal_device_get_lock_holders: + * @device: the device to check for + * @lock_name: the lock name + * + * Get the number of lock holders on a device. + * + * Returns: Number of callers holding the given lock. + */ +int +hal_device_get_num_lock_holders (HalDevice *device, const char *lock_name) +{ + int num; + char **holders; + + num = 0; + holders = hal_device_get_lock_holders (device, lock_name); + if (holders == NULL) + goto out; + + num = g_strv_length (holders); + g_strfreev (holders); +out: + return num; +} + +/** * hal_device_client_disconnected: * @sender: the client that disconnected from the bus * @@ -1756,20 +1812,19 @@ hal_device_client_disconnected (const char *sender) for (i = locked_devices; i != NULL; i = g_slist_next (i)) { HalDevice *device = i->data; - GSList *locks; - GSList *j; - GSList *k; + char **locks; + int n; HAL_INFO (("Looking at udi '%s'", device->private->udi)); - locks = hal_device_property_get_strlist (device, "info.named_locks"); - for (j = locks; j != NULL; j = k) { - char *lock_name = j->data; - k = g_slist_next (j); - - HAL_INFO (("Lock '%s'", lock_name)); - - hal_device_release_lock (device, lock_name, sender); + locks = hal_device_property_dup_strlist_as_strv (device, "info.named_locks"); + if (locks != NULL) { + for (n = 0; locks[n] != NULL; n++) { + char *lock_name = locks[n]; + HAL_INFO (("Lock '%s'", lock_name)); + hal_device_release_lock (device, lock_name, sender); + } + g_strfreev (locks); } } } diff --git a/hald/device.h b/hald/device.h index 5dd11f57..1942e2f2 100644 --- a/hald/device.h +++ b/hald/device.h @@ -53,6 +53,14 @@ struct _HalDeviceClass { void (*capability_added) (HalDevice *device, const char *capability); + + void (*lock_acquired) (HalDevice *device, + const char *lock_name, + const char *lock_owner); + + void (*lock_released) (HalDevice *device, + const char *lock_name, + const char *lock_owner); }; #define HAL_TYPE_DEVICE (hal_device_get_type ()) @@ -212,6 +220,8 @@ gboolean hal_device_release_lock (HalDevice *device, const char *lock_name, char **hal_device_get_lock_holders (HalDevice *device, const char *lock_name); +int hal_device_get_num_lock_holders (HalDevice *device, const char *lock_name); + /* static method */ void hal_device_client_disconnected (const char *sender); diff --git a/hald/device_store.c b/hald/device_store.c index 7c06aabe..23c054d3 100644 --- a/hald/device_store.c +++ b/hald/device_store.c @@ -41,6 +41,8 @@ enum { STORE_CHANGED, DEVICE_PROPERTY_CHANGED, DEVICE_CAPABILITY_ADDED, + DEVICE_LOCK_ACQUIRED, + DEVICE_LOCK_RELEASED, LAST_SIGNAL }; @@ -103,6 +105,33 @@ hal_device_store_class_init (HalDeviceStoreClass *klass) G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING); + + signals[DEVICE_LOCK_ACQUIRED] = + g_signal_new ("device_lock_acquired", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (HalDeviceStoreClass, + device_lock_acquired), + NULL, NULL, + hald_marshal_VOID__OBJECT_STRING_STRING, + G_TYPE_NONE, 3, + G_TYPE_OBJECT, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[DEVICE_LOCK_RELEASED] = + g_signal_new ("device_lock_released", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (HalDeviceStoreClass, + device_lock_released), + NULL, NULL, + hald_marshal_VOID__OBJECT_STRING_STRING, + G_TYPE_NONE, 3, + G_TYPE_OBJECT, + G_TYPE_STRING, + G_TYPE_STRING); + } static void @@ -169,6 +198,30 @@ emit_device_capability_added (HalDevice *device, device, capability); } +static void +emit_device_lock_acquired (HalDevice *device, + const char *lock_name, + const char *lock_owner, + gpointer data) +{ + HalDeviceStore *store = HAL_DEVICE_STORE (data); + + g_signal_emit (store, signals[DEVICE_LOCK_ACQUIRED], 0, + device, lock_name, lock_owner); +} + +static void +emit_device_lock_released (HalDevice *device, + const char *lock_name, + const char *lock_owner, + gpointer data) +{ + HalDeviceStore *store = HAL_DEVICE_STORE (data); + + g_signal_emit (store, signals[DEVICE_LOCK_RELEASED], 0, + device, lock_name, lock_owner); +} + void hal_device_store_add (HalDeviceStore *store, HalDevice *device) { @@ -187,6 +240,10 @@ hal_device_store_add (HalDeviceStore *store, HalDevice *device) G_CALLBACK (emit_device_property_changed), store); g_signal_connect (device, "capability_added", G_CALLBACK (emit_device_capability_added), store); + g_signal_connect (device, "lock_acquired", + G_CALLBACK (emit_device_lock_acquired), store); + g_signal_connect (device, "lock_released", + G_CALLBACK (emit_device_lock_released), store); g_signal_emit (store, signals[STORE_CHANGED], 0, device, TRUE); @@ -208,6 +265,12 @@ hal_device_store_remove (HalDeviceStore *store, HalDevice *device) g_signal_handlers_disconnect_by_func (device, (gpointer)emit_device_capability_added, store); + g_signal_handlers_disconnect_by_func (device, + (gpointer)emit_device_lock_acquired, + store); + g_signal_handlers_disconnect_by_func (device, + (gpointer)emit_device_lock_released, + store); g_signal_emit (store, signals[STORE_CHANGED], 0, device, FALSE); diff --git a/hald/device_store.h b/hald/device_store.h index 0e1578a4..300f4c70 100644 --- a/hald/device_store.h +++ b/hald/device_store.h @@ -58,6 +58,16 @@ struct _HalDeviceStoreClass { HalDevice *device, const char *capability); + + void (*device_lock_acquired) (HalDeviceStore *store, + HalDevice *device, + const char *lock_name, + const char *lock_owner); + + void (*device_lock_released) (HalDeviceStore *store, + HalDevice *device, + const char *lock_name, + const char *lock_owner); }; #define HAL_TYPE_DEVICE_STORE (hal_device_store_get_type ()) diff --git a/hald/hald.c b/hald/hald.c index c130ca80..1a13a316 100644 --- a/hald/hald.c +++ b/hald/hald.c @@ -161,6 +161,32 @@ gdl_capability_added (HalDeviceStore *store, HalDevice *device, /*hal_callout_capability (device, capability, TRUE)*/; } +static void +gdl_lock_acquired (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner) +{ + if (hal_device_are_all_addons_ready (device)) { + if (strncmp (lock_name, "Global.", 7) == 0 && + strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) { + manager_send_signal_interface_lock_acquired (lock_name + 7, lock_owner); + } else { + device_send_signal_interface_lock_acquired (device, lock_name, lock_owner); + } + } +} + +static void +gdl_lock_released (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner) +{ + if (hal_device_are_all_addons_ready (device)) { + if (strncmp (lock_name, "Global.", 7) == 0 && + strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) { + manager_send_signal_interface_lock_released (lock_name + 7, lock_owner); + } else { + device_send_signal_interface_lock_released (device, lock_name, lock_owner); + } + } +} + HalDeviceStore * hald_get_gdl (void) { @@ -176,6 +202,15 @@ hald_get_gdl (void) g_signal_connect (global_device_list, "device_capability_added", G_CALLBACK (gdl_capability_added), NULL); + g_signal_connect (global_device_list, + "device_property_changed", + G_CALLBACK (gdl_property_changed), NULL); + g_signal_connect (global_device_list, + "device_lock_acquired", + G_CALLBACK (gdl_lock_acquired), NULL); + g_signal_connect (global_device_list, + "device_lock_released", + G_CALLBACK (gdl_lock_released), NULL); } return global_device_list; diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c index 28169475..90dc9f7c 100644 --- a/hald/hald_dbus.c +++ b/hald/hald_dbus.c @@ -761,6 +761,146 @@ out: ; } +void +manager_send_signal_interface_lock_acquired (const char *interface_name, const char *sender) +{ + const char *udi; + char *lock_name; + int num_locks; + HalDevice *d; + DBusMessage *message; + DBusMessageIter iter; + + if (dbus_connection == NULL || hald_is_initialising) + goto out; + + 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) + goto out; + + lock_name = g_strdup_printf ("Global.%s", interface_name); + num_locks = hal_device_get_num_lock_holders (d, lock_name); + g_free (lock_name); + + message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "GlobalInterfaceLockAcquired"); + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks); + + if (!dbus_connection_send (dbus_connection, message, NULL)) + DIE (("error broadcasting message")); + + dbus_message_unref (message); +out: + ; +} + +void +manager_send_signal_interface_lock_released (const char *interface_name, const char *sender) +{ + const char *udi; + char *lock_name; + int num_locks; + HalDevice *d; + DBusMessage *message; + DBusMessageIter iter; + + if (dbus_connection == NULL || hald_is_initialising) + goto out; + + 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) + goto out; + + lock_name = g_strdup_printf ("Global.%s", interface_name); + num_locks = hal_device_get_num_lock_holders (d, lock_name); + g_free (lock_name); + + message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "GlobalInterfaceLockReleased"); + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks); + + if (!dbus_connection_send (dbus_connection, message, NULL)) + DIE (("error broadcasting message")); + + dbus_message_unref (message); +out: + ; +} + +void +device_send_signal_interface_lock_acquired (HalDevice *device, const char *interface_name, const char *sender) +{ + int num_locks; + DBusMessage *message; + DBusMessageIter iter; + + if (dbus_connection == NULL || hald_is_initialising) + goto out; + + num_locks = hal_device_get_num_lock_holders (device, interface_name); + + message = dbus_message_new_signal (hal_device_get_udi (device), + "org.freedesktop.Hal.Device", + "InterfaceLockAcquired"); + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks); + + if (!dbus_connection_send (dbus_connection, message, NULL)) + DIE (("error broadcasting message")); + + dbus_message_unref (message); +out: + ; +} + +void +device_send_signal_interface_lock_released (HalDevice *device, const char *interface_name, const char *sender) +{ + int num_locks; + DBusMessage *message; + DBusMessageIter iter; + + if (dbus_connection == NULL || hald_is_initialising) + goto out; + + num_locks = hal_device_get_num_lock_holders (device, interface_name); + + message = dbus_message_new_signal (hal_device_get_udi (device), + "org.freedesktop.Hal.Device", + "InterfaceLockReleased"); + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &num_locks); + + if (!dbus_connection_send (dbus_connection, message, NULL)) + DIE (("error broadcasting message")); + + dbus_message_unref (message); +out: + ; +} + static void foreach_property_append (HalDevice *device, const char *key, @@ -1903,7 +2043,7 @@ device_acquire_interface_lock (DBusConnection *connection, DBusMessage *message, sender = dbus_message_get_sender (message); if (!local_interface) { - if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) { + if (!access_check_caller_have_access_to_device (ci_tracker, d, "lock", sender)) { raise_permission_denied (connection, message, "AcquireInterfaceLock: no access to device"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -1960,7 +2100,7 @@ device_release_interface_lock (DBusConnection *connection, DBusMessage *message, sender = dbus_message_get_sender (message); if (!local_interface) { - if (!access_check_caller_have_access_to_device (ci_tracker, d, sender)) { + if (!access_check_caller_have_access_to_device (ci_tracker, d, "lock", sender)) { raise_permission_denied (connection, message, "ReleaseInterfaceLock: no access to device"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -1990,7 +2130,6 @@ device_release_interface_lock (DBusConnection *connection, DBusMessage *message, return DBUS_HANDLER_RESULT_HANDLED; } - static DBusHandlerResult device_is_caller_locked_out (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface) { @@ -2049,6 +2188,62 @@ device_is_caller_locked_out (DBusConnection *connection, DBusMessage *message, d return DBUS_HANDLER_RESULT_HANDLED; } + +/*------------------------------------------------------------------------*/ + +static DBusHandlerResult +device_is_locked_by_others (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface) +{ + const char *udi; + HalDevice *d; + DBusMessage *reply; + DBusError error; + const char *sender; + char *interface_name; + dbus_bool_t result; + DBusMessageIter iter; + + 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); + + /* anyone can ask this question */ + + dbus_error_init (&error); + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &interface_name, + DBUS_TYPE_INVALID)) { + raise_syntax (connection, message, "IsLockedByOthers"); + return DBUS_HANDLER_RESULT_HANDLED; + } + + result = access_check_locked_by_others (ci_tracker, d, sender, 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 @@ -3707,6 +3902,16 @@ do_introspect (DBusConnection *connection, " <arg name=\"udi\" type=\"s\"/>\n" " <arg name=\"cap_name\" type=\"s\"/>\n" " </signal>\n" + " <signal name=\"GlobalInterfaceLockAcquired\">\n" + " <arg name=\"interface_name\" type=\"s\"/>\n" + " <arg name=\"lock_holder\" type=\"s\"/>\n" + " <arg name=\"num_locks\" type=\"i\"/>\n" + " </signal>\n" + " <signal name=\"GlobalInterfaceLockReleased\">\n" + " <arg name=\"interface_name\" type=\"s\"/>\n" + " <arg name=\"lock_holder\" type=\"s\"/>\n" + " <arg name=\"num_locks\" type=\"i\"/>\n" + " </signal>\n" " </interface>\n"); } else { @@ -3816,6 +4021,10 @@ do_introspect (DBusConnection *connection, " <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=\"IsLockedByOthers\">\n" + " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n" + " <arg name=\"whether_it_is_locked_by_others\" direction=\"out\" type=\"b\"/>\n" + " </method>\n" " <method name=\"StringListAppend\">\n" " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n" @@ -3860,6 +4069,17 @@ do_introspect (DBusConnection *connection, " <arg name=\"cond_details\" type=\"s\"/>\n" " </signal>\n" + " <signal name=\"InterfaceLockAcquired\">\n" + " <arg name=\"interface_name\" type=\"s\"/>\n" + " <arg name=\"lock_holder\" type=\"s\"/>\n" + " <arg name=\"num_locks\" type=\"i\"/>\n" + " </signal>\n" + " <signal name=\"InterfaceLockReleased\">\n" + " <arg name=\"interface_name\" type=\"s\"/>\n" + " <arg name=\"lock_holder\" type=\"s\"/>\n" + " <arg name=\"num_locks\" type=\"i\"/>\n" + " </signal>\n" + " </interface>\n"); HalDeviceStrListIter if_iter; @@ -4085,7 +4305,10 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag "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", + "IsLockedByOthers")) { + return device_is_locked_by_others (connection, message, local_interface); } else if (dbus_message_is_method_call (message, "org.freedesktop.Hal.Device", "GetAllProperties")) { @@ -4249,7 +4472,7 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag /* bypass security checks on direct connections */ if (!local_interface) { - if (!access_check_caller_have_access_to_device (ci_tracker, d, caller)) { + if (!access_check_caller_have_access_to_device (ci_tracker, d, NULL, caller)) { HAL_INFO (("Caller '%s' does not have access to device '%s'", caller, udi)); /* TODO: need to fix up reason */ raise_permission_denied (connection, message, "Not in active session"); @@ -4366,13 +4589,6 @@ DBusHandlerResult hald_dbus_filter_function (DBusConnection * connection, DBusMessage * message, void *user_data) { -#ifdef HAVE_CONKIT - /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */ - if (ck_tracker != NULL) { - ck_tracker_process_system_bus_message (ck_tracker, message); - } -#endif - if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) { @@ -4439,10 +4655,26 @@ hald_dbus_filter_function (DBusConnection * connection, HAL_INFO (("active=%d for session %s", is_active, session_objpath)); ci_tracker_active_changed (ci_tracker, session_objpath, is_active); #endif /* HAVE_CONKIT */ - } else + } else { + +#ifdef HAVE_CONKIT + /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */ + if (ck_tracker != NULL) { + ck_tracker_process_system_bus_message (ck_tracker, message); + } +#endif return hald_dbus_filter_handle_methods (connection, message, user_data, FALSE); + } out: + +#ifdef HAVE_CONKIT + /* TODO: only push the appropriate messages to the tracker; see ck-tracker.h */ + if (ck_tracker != NULL) { + ck_tracker_process_system_bus_message (ck_tracker, message); + } +#endif + return DBUS_HANDLER_RESULT_HANDLED; } @@ -4698,6 +4930,50 @@ hald_dbus_seat_removed (CKTracker *tracker, CKSeat *seat, void *user_data) /* TODO: we could run callouts here... but they wouldn't do anything useful right now */ } +static gboolean +validate_lock_for_device (HalDeviceStore *store, + HalDevice *device, + gpointer user_data) +{ + int n, m; + char **holders; + char **locked_interfaces; + + locked_interfaces = hal_device_property_dup_strlist_as_strv (device, "info.named_locks"); + if (locked_interfaces == NULL) + goto out; + + for (n = 0; locked_interfaces[n] != NULL; n++) { + holders = hal_device_get_lock_holders (device, locked_interfaces[n]); + if (holders == NULL) + continue; + for (m = 0; holders[m] != NULL; m++) { + HAL_INFO (("Validating lock holder '%s' on interface '%s' on udi '%s'", + holders[m], locked_interfaces[n], hal_device_get_udi (device))); + + if (!access_check_caller_have_access_to_device (ci_tracker, device, "lock", holders[m])) { + HAL_INFO (("Kicking out lock holder '%s' on interface '%s' on udi '%s' " + "as he no longer has access to the device", + holders[m], locked_interfaces[n], hal_device_get_udi (device))); + hal_device_release_lock (device, locked_interfaces[n], holders[m]); + } + + } + g_strfreev (holders); + } + + g_strfreev (locked_interfaces); +out: + return TRUE; +} + +static void +validate_locks (void) +{ + hal_device_store_foreach (hald_get_tdl (), validate_lock_for_device, NULL); + hal_device_store_foreach (hald_get_gdl (), validate_lock_for_device, NULL); +} + static void hald_dbus_session_active_changed (CKTracker *tracker, CKSession *session, void *user_data) { @@ -4713,6 +4989,9 @@ hald_dbus_session_active_changed (CKTracker *tracker, CKSession *session, void * ck_session_get_id (session), ck_session_is_active (session) ? "ACTIVE" : "INACTIVE")); + /* revalidate all locks (to remove locks from callers in that session who no longer has access to devices */ + validate_locks (); + d = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer"); if (d == NULL) { d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer"); diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h index d7f9accd..4a5deb18 100644 --- a/hald/hald_dbus.h +++ b/hald/hald_dbus.h @@ -83,6 +83,12 @@ void manager_send_signal_device_removed (HalDevice *device); void manager_send_signal_new_capability (HalDevice *device, const char *capability); +void manager_send_signal_interface_lock_acquired (const char *interface_name, const char *sender); +void manager_send_signal_interface_lock_released (const char *interface_name, const char *sender); + +void device_send_signal_interface_lock_acquired (HalDevice *device, const char *interface_name, const char *sender); +void device_send_signal_interface_lock_released (HalDevice *device, const char *interface_name, const char *sender); + void device_send_signal_property_modified (HalDevice *device, const char *key, dbus_bool_t removed, diff --git a/hald/hald_marshal.list b/hald/hald_marshal.list index 8e3863a8..14dd6f82 100644 --- a/hald/hald_marshal.list +++ b/hald/hald_marshal.list @@ -1,3 +1,5 @@ +VOID:OBJECT,STRING,STRING +VOID:STRING,STRING VOID:STRING,BOOL,BOOL VOID:STRING VOID:OBJECT,BOOL |