summaryrefslogtreecommitdiff
path: root/hald
diff options
context:
space:
mode:
Diffstat (limited to 'hald')
-rw-r--r--hald/access-check.c122
-rw-r--r--hald/access-check.h5
-rw-r--r--hald/ci-tracker.c26
-rw-r--r--hald/ci-tracker.h1
-rw-r--r--hald/device.c77
-rw-r--r--hald/device.h10
-rw-r--r--hald/device_store.c63
-rw-r--r--hald/device_store.h10
-rw-r--r--hald/hald.c35
-rw-r--r--hald/hald_dbus.c305
-rw-r--r--hald/hald_dbus.h6
-rw-r--r--hald/hald_marshal.list2
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