return bus_service_get_primary_owners_connection (serv);
}
-static DBusConnection *
+BusDriverFound
bus_driver_get_conn_helper (DBusConnection *connection,
DBusMessage *message,
const char *what_we_want,
const char **name_p,
+ DBusConnection **peer_conn_p,
DBusError *error)
{
DBusConnection *conn;
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID))
- return NULL;
+ return BUS_DRIVER_FOUND_ERROR;
_dbus_assert (name != NULL);
_dbus_verbose ("asked for %s of connection %s\n", what_we_want, name);
+ if (name_p != NULL)
+ *name_p = name;
+
+ if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
+ return BUS_DRIVER_FOUND_SELF;
+
conn = bus_driver_get_owner_of_name (connection, name);
if (conn == NULL)
dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
"Could not get %s of name '%s': no such name",
what_we_want, name);
- return NULL;
+ return BUS_DRIVER_FOUND_ERROR;
}
- if (name_p != NULL)
- *name_p = name;
+ if (peer_conn_p != NULL)
+ *peer_conn_p = conn;
- return conn;
+ return BUS_DRIVER_FOUND_PEER;
}
/*
DBusError *error);
dbus_bool_t
+bus_driver_send_connection_overflow (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusError *error)
+{
+ DBusMessage *message;
+ dbus_bool_t retval;
+ const char *name;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ message = dbus_message_new_signal (DBUS_PATH_DBUS,
+ DBUS_INTERFACE_TIZEN,
+ DBUS_TIZEN_CONNECTION_OVERFLOW_SIGNAL);
+
+ if (message == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ goto oom;
+
+ name = bus_connection_get_name (connection);
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ goto oom;
+
+ _dbus_assert (dbus_message_has_signature (message, "s"));
+
+ if (!bus_transaction_capture (transaction, NULL, NULL, message))
+ goto oom;
+
+ switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error))
+ {
+ case BUS_RESULT_TRUE:
+ retval = TRUE;
+ break;
+ case BUS_RESULT_FALSE:
+ retval = FALSE;
+ break;
+ case BUS_RESULT_LATER:
+ default:
+ /* should never happen */
+ _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
+ retval = FALSE;
+ break;
+ }
+ dbus_message_unref (message);
+
+ return retval;
+
+ oom:
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+}
+
+dbus_bool_t
bus_driver_send_service_owner_changed (const char *service_name,
const char *old_owner,
const char *new_owner,
_dbus_assert (dbus_message_has_signature (message, "sss"));
- if (!bus_transaction_capture (transaction, NULL, message))
+ if (!bus_transaction_capture (transaction, NULL, NULL, message))
goto oom;
- retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
+ switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error))
+ {
+ case BUS_RESULT_TRUE:
+ retval = TRUE;
+ break;
+ case BUS_RESULT_FALSE:
+ retval = FALSE;
+ break;
+ default:
+ /* should never happen */
+ _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
+ retval = FALSE;
+ break;
+ }
dbus_message_unref (message);
return retval;
return TRUE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_hello (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
{
DBusString unique_name;
BusService *service;
- dbus_bool_t retval;
+ BusResult retval;
BusRegistry *registry;
BusConnections *connections;
+ DBusError tmp_error;
+ int limit;
+ const char *limit_name;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
/* We already handled an Hello message for this connection. */
dbus_set_error (error, DBUS_ERROR_FAILED,
"Already handled an Hello message");
- return FALSE;
+ return BUS_RESULT_FALSE;
}
/* Note that when these limits are exceeded we don't disconnect the
* incomplete connections. It's even OK if the connection wants to
* retry the hello message, we support that.
*/
+ dbus_error_init (&tmp_error);
connections = bus_connection_get_connections (connection);
if (!bus_connections_check_limits (connections, connection,
- error))
+ &limit_name, &limit,
+ &tmp_error))
{
- _DBUS_ASSERT_ERROR_IS_SET (error);
- return FALSE;
+ BusContext *context;
+
+ _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+ context = bus_connection_get_context (connection);
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s (%s=%d)",
+ tmp_error.message, limit_name, limit);
+ dbus_move_error (&tmp_error, error);
+ return BUS_RESULT_FALSE;
}
if (!_dbus_string_init (&unique_name))
{
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
registry = bus_connection_get_registry (connection);
goto out_0;
_dbus_assert (bus_connection_is_active (connection));
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out_0:
_dbus_string_free (&unique_name);
}
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_list_services (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
if (reply == NULL)
{
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
if (!bus_registry_list_services (registry, &services, &len))
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
dbus_message_iter_init_append (reply, &iter);
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
{
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
}
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
++i;
}
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
else
{
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
}
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_list_activatable_services (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
if (reply == NULL)
{
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
if (!bus_activation_list_services (activation, &services, &len))
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
dbus_message_iter_init_append (reply, &iter);
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
{
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
}
dbus_free_string_array (services);
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
++i;
}
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
else
{
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
}
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_acquire_service (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
const char *name;
dbus_uint32_t service_reply;
dbus_uint32_t flags;
- dbus_bool_t retval;
+ BusResult retval;
BusRegistry *registry;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
DBUS_TYPE_STRING, &name,
DBUS_TYPE_UINT32, &flags,
DBUS_TYPE_INVALID))
- return FALSE;
+ return BUS_RESULT_FALSE;
_dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
reply = NULL;
_dbus_string_init_const (&service_name, name);
- if (!bus_registry_acquire_service (registry, connection,
- &service_name, flags,
- &service_reply, transaction,
- error))
- goto out;
+ switch (bus_registry_acquire_service (registry, connection, message,
+ &service_name, flags,
+ &service_reply, transaction,
+ error))
+ {
+ case BUS_RESULT_TRUE:
+ break;
+ case BUS_RESULT_FALSE:
+ goto out;
+ case BUS_RESULT_LATER:
+ retval = BUS_RESULT_LATER;
+ goto out;
+ }
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto out;
}
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out:
if (reply)
return retval;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_release_service (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusString service_name;
const char *name;
dbus_uint32_t service_reply;
- dbus_bool_t retval;
+ BusResult retval;
BusRegistry *registry;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID))
- return FALSE;
+ return BUS_RESULT_FALSE;
_dbus_verbose ("Trying to release name %s\n", name);
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
reply = NULL;
_dbus_string_init_const (&service_name, name);
goto out;
}
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out:
if (reply)
return retval;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_service_exists (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
BusService *service;
dbus_bool_t service_exists;
const char *name;
- dbus_bool_t retval;
+ BusResult retval;
BusRegistry *registry;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID))
- return FALSE;
+ return BUS_RESULT_FALSE;
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
{
goto out;
}
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out:
if (reply)
return retval;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_activate_service (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
{
dbus_uint32_t flags;
const char *name;
- dbus_bool_t retval;
+ BusResult retval;
BusActivation *activation;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_verbose ("No memory to get arguments to StartServiceByName\n");
- return FALSE;
+ return BUS_RESULT_FALSE;
}
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
- if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
- message, name, error))
+ if (bus_activation_activate_service (activation, connection, transaction, FALSE,
+ message, name, error, NULL) == BUS_RESULT_FALSE)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_verbose ("bus_activation_activate_service() failed\n");
goto out;
}
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out:
return retval;
}
-static dbus_bool_t
-send_ack_reply (DBusConnection *connection,
- BusTransaction *transaction,
- DBusMessage *message,
- DBusError *error)
+dbus_bool_t
+bus_driver_send_ack_reply (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
{
DBusMessage *reply;
return TRUE;
}
+/*
+ * Send a message from the driver, activating the destination if necessary.
+ * The message must already have a destination set.
+ */
static dbus_bool_t
+bus_driver_send_or_activate (BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusContext *context;
+ BusService *service;
+ const char *service_name;
+ DBusString service_string;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ service_name = dbus_message_get_destination (message);
+
+ _dbus_assert (service_name != NULL);
+
+ _dbus_string_init_const (&service_string, service_name);
+
+ context = bus_transaction_get_context (transaction);
+
+ service = bus_registry_lookup (bus_context_get_registry (context),
+ &service_string);
+
+ if (service == NULL)
+ {
+ /* destination isn't connected yet; pass the message to activation */
+ BusActivation *activation;
+
+ activation = bus_context_get_activation (context);
+
+ if (!bus_transaction_capture (transaction, NULL, NULL, message))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory for bus_transaction_capture()");
+ return FALSE;
+ }
+
+ if (bus_activation_activate_service (activation, NULL, transaction, TRUE,
+ message, service_name, error, NULL) == BUS_RESULT_FALSE)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_verbose ("bus_activation_activate_service() failed");
+ return FALSE;
+ }
+ }
+ else
+ {
+ DBusConnection *service_conn;
+
+ service_conn = bus_service_get_primary_owners_connection (service);
+
+ if (!bus_transaction_send_from_driver (transaction, service_conn, message))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory for bus_transaction_send_from_driver()");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static BusResult
bus_driver_handle_update_activation_environment (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
- dbus_bool_t retval;
+ BusResult retval;
BusActivation *activation;
+ BusContext *context;
DBusMessageIter iter;
DBusMessageIter dict_iter;
DBusMessageIter dict_entry_iter;
int key_type;
DBusList *keys, *key_link;
DBusList *values, *value_link;
+ DBusMessage *systemd_message;
+ DBusMessageIter systemd_iter;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (!bus_driver_check_message_is_for_us (message, error))
- return FALSE;
+ context = bus_connection_get_context (connection);
-#ifdef DBUS_UNIX
+ if (bus_context_get_servicehelper (context) != NULL)
{
- /* UpdateActivationEnvironment is basically a recipe for privilege
- * escalation so let's be extra-careful: do not allow the sysadmin
- * to shoot themselves in the foot.
- */
- if (!bus_driver_check_caller_is_privileged (connection, transaction,
- message, error))
- return FALSE;
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Cannot change activation environment "
+ "on a system bus.");
+ return BUS_RESULT_FALSE;
}
-#endif
activation = bus_connection_get_activation (connection);
dbus_message_iter_recurse (&iter, &dict_iter);
- retval = FALSE;
+ retval = BUS_RESULT_FALSE;
+ systemd_message = NULL;
/* Then loop through the sent dictionary, add the location of
* the environment keys and values to lists. The result will
_dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values));
+ if (bus_context_get_systemd_activation (bus_connection_get_context (connection)))
+ {
+ /* Prepare a call to forward environment updates to systemd */
+ systemd_message = dbus_message_new_method_call ("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetEnvironment");
+ if (systemd_message == NULL ||
+ !dbus_message_set_sender (systemd_message, DBUS_SERVICE_DBUS))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory to create systemd message\n");
+ goto out;
+ }
+
+ dbus_message_set_no_reply (systemd_message, TRUE);
+ dbus_message_iter_init_append (systemd_message, &iter);
+
+ if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
+ &systemd_iter))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory to open systemd message container\n");
+ goto out;
+ }
+ }
+
key_link = keys;
value_link = values;
while (key_link != NULL)
if (!bus_activation_set_environment_variable (activation,
key, value, error))
- {
+ {
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_verbose ("bus_activation_set_environment_variable() failed\n");
break;
- }
+ }
+
+ if (systemd_message != NULL)
+ {
+ DBusString envline;
+ const char *s;
+
+ /* SetEnvironment wants an array of KEY=VALUE strings */
+ if (!_dbus_string_init (&envline) ||
+ !_dbus_string_append_printf (&envline, "%s=%s", key, value))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory to format systemd environment line\n");
+ _dbus_string_free (&envline);
+ break;
+ }
+
+ s = _dbus_string_get_data (&envline);
+
+ if (!dbus_message_iter_append_basic (&systemd_iter,
+ DBUS_TYPE_STRING, &s))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory to append systemd environment line\n");
+ _dbus_string_free (&envline);
+ break;
+ }
+
+ _dbus_string_free (&envline);
+ }
+
key_link = _dbus_list_get_next_link (&keys, key_link);
value_link = _dbus_list_get_next_link (&values, value_link);
}
* matter, so we're punting for now.
*/
if (key_link != NULL)
- goto out;
+ {
+ if (systemd_message != NULL)
+ dbus_message_iter_abandon_container (&iter, &systemd_iter);
+ goto out;
+ }
+
+ if (systemd_message != NULL)
+ {
+ if (!dbus_message_iter_close_container (&iter, &systemd_iter))
+ {
+ BUS_SET_OOM (error);
+ _dbus_verbose ("No memory to close systemd message container\n");
+ goto out;
+ }
- if (!send_ack_reply (connection, transaction,
- message, error))
+ if (!bus_driver_send_or_activate (transaction, systemd_message, error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_verbose ("bus_driver_send_or_activate() failed\n");
+ goto out;
+ }
+ }
+
+ if (!bus_driver_send_ack_reply (connection, transaction, message, error))
goto out;
- retval = TRUE;
+ retval = BUS_RESULT_TRUE;
out:
+ if (systemd_message != NULL)
+ dbus_message_unref (systemd_message);
_dbus_list_clear (&keys);
_dbus_list_clear (&values);
return retval;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_add_match (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
const char *text, *bustype;
DBusString str;
BusMatchmaker *matchmaker;
+ int limit;
BusContext *context;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
text = NULL;
rule = NULL;
- if (bus_connection_get_n_match_rules (connection) >=
- bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
+ context = bus_transaction_get_context (transaction);
+ limit = bus_context_get_max_match_rules_per_connection (context);
+
+ if (bus_connection_get_n_match_rules (connection) >= limit)
{
- dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+ DBusError tmp_error;
+
+ dbus_error_init (&tmp_error);
+ dbus_set_error (&tmp_error, DBUS_ERROR_LIMITS_EXCEEDED,
"Connection \"%s\" is not allowed to add more match rules "
- "(increase limits in configuration file if required)",
+ "(increase limits in configuration file if required; "
+ "max_match_rules_per_connection=%d)",
bus_connection_is_active (connection) ?
bus_connection_get_name (connection) :
- "(inactive)");
+ "(inactive)",
+ limit);
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s",
+ tmp_error.message);
+ dbus_move_error (&tmp_error, error);
goto failed;
}
if (rule == NULL)
goto failed;
- context = bus_transaction_get_context (transaction);
- bustype = context ? bus_context_get_type (context) : NULL;
- if (bus_match_rule_get_client_is_eavesdropping (rule) &&
- !bus_apparmor_allows_eavesdropping (connection, bustype, error))
- goto failed;
+ bustype = bus_context_get_type (context);
+
+ if (bus_match_rule_get_client_is_eavesdropping (rule))
+ {
+ if (!bus_driver_check_caller_is_privileged (connection,
+ transaction,
+ message,
+ error) ||
+ !bus_apparmor_allows_eavesdropping (connection, bustype, error))
+ goto failed;
+ }
matchmaker = bus_connection_get_matchmaker (connection);
goto failed;
}
- if (!send_ack_reply (connection, transaction,
- message, error))
+ if (!bus_driver_send_ack_reply (connection, transaction, message, error))
{
bus_matchmaker_remove_rule (matchmaker, rule);
goto failed;
bus_match_rule_unref (rule);
- return TRUE;
+ return BUS_RESULT_TRUE;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (rule)
bus_match_rule_unref (rule);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_remove_match (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
/* Send the ack before we remove the rule, since the ack is undone
* on transaction cancel, but rule removal isn't.
*/
- if (!send_ack_reply (connection, transaction,
- message, error))
+ if (!bus_driver_send_ack_reply (connection, transaction, message, error))
goto failed;
matchmaker = bus_connection_get_matchmaker (connection);
bus_match_rule_unref (rule);
- return TRUE;
+ return BUS_RESULT_TRUE;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (rule)
bus_match_rule_unref (rule);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_service_owner (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_list_queued_owners (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
+ static const char dbus_service_name[] = DBUS_SERVICE_DBUS;
+
const char *text;
DBusList *base_names;
DBusList *link;
BusService *service;
DBusMessage *reply;
DBusMessageIter iter, array_iter;
- char *dbus_service_name = DBUS_SERVICE_DBUS;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
_dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS))
{
/* ORG_FREEDESKTOP_DBUS owns itself */
- if (! _dbus_list_append (&base_names, dbus_service_name))
+ if (! _dbus_list_append (&base_names, (char *) dbus_service_name))
goto oom;
}
else if (service == NULL)
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
if (base_names)
_dbus_list_clear (&base_names);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
{
DBusConnection *conn;
DBusMessage *reply;
- unsigned long uid;
+ dbus_uid_t uid;
dbus_uint32_t uid32;
const char *service;
+ BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
reply = NULL;
- conn = bus_driver_get_conn_helper (connection, message, "UID", &service,
- error);
-
- if (conn == NULL)
- goto failed;
-
- reply = dbus_message_new_method_return (message);
- if (reply == NULL)
- goto oom;
+ found = bus_driver_get_conn_helper (connection, message, "UID", &service,
+ &conn, error);
+ switch (found)
+ {
+ case BUS_DRIVER_FOUND_SELF:
+ uid = _dbus_getuid ();
+ break;
+ case BUS_DRIVER_FOUND_PEER:
+ if (!dbus_connection_get_unix_user (conn, &uid))
+ uid = DBUS_UID_UNSET;
+ break;
+ case BUS_DRIVER_FOUND_ERROR:
+ /* fall through */
+ default:
+ goto failed;
+ }
- if (!dbus_connection_get_unix_user (conn, &uid))
+ if (uid == DBUS_UID_UNSET)
{
dbus_set_error (error,
DBUS_ERROR_FAILED,
goto failed;
}
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
uid32 = uid;
if (! dbus_message_append_args (reply,
DBUS_TYPE_UINT32, &uid32,
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
{
DBusConnection *conn;
DBusMessage *reply;
- unsigned long pid;
+ dbus_pid_t pid;
dbus_uint32_t pid32;
const char *service;
+ BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
reply = NULL;
- conn = bus_driver_get_conn_helper (connection, message, "PID", &service,
- error);
-
- if (conn == NULL)
- goto failed;
-
- reply = dbus_message_new_method_return (message);
- if (reply == NULL)
- goto oom;
+ found = bus_driver_get_conn_helper (connection, message, "PID", &service,
+ &conn, error);
+ switch (found)
+ {
+ case BUS_DRIVER_FOUND_SELF:
+ pid = _dbus_getpid ();
+ break;
+ case BUS_DRIVER_FOUND_PEER:
+ if (!dbus_connection_get_unix_process_id (conn, &pid))
+ pid = DBUS_PID_UNSET;
+ break;
+ case BUS_DRIVER_FOUND_ERROR:
+ /* fall through */
+ default:
+ goto failed;
+ }
- if (!dbus_connection_get_unix_process_id (conn, &pid))
+ if (pid == DBUS_PID_UNSET)
{
dbus_set_error (error,
DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
goto failed;
}
- pid32 = pid;
- if (! dbus_message_append_args (reply,
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
+ pid32 = pid;
+ if (! dbus_message_append_args (reply,
DBUS_TYPE_UINT32, &pid32,
DBUS_TYPE_INVALID))
goto oom;
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusConnection *conn;
DBusMessage *reply;
void *data = NULL;
- dbus_uint32_t data_size;
+ dbus_int32_t data_size;
const char *service;
+ BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
reply = NULL;
- conn = bus_driver_get_conn_helper (connection, message,
- "audit session data", &service, error);
+ found = bus_driver_get_conn_helper (connection, message, "audit session data",
+ &service, &conn, error);
- if (conn == NULL)
+ if (found == BUS_DRIVER_FOUND_ERROR)
goto failed;
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto oom;
- if (!dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || data == NULL)
+ /* We don't know how to find "ADT audit session data" for the bus daemon
+ * itself. Is that even meaningful?
+ * FIXME: Implement this or briefly note it makes no sense.
+ */
+ if (found != BUS_DRIVER_FOUND_PEER ||
+ !dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) ||
+ data == NULL)
{
dbus_set_error (error,
DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN,
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusMessage *reply;
BusSELinuxID *context;
const char *service;
+ BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
reply = NULL;
- conn = bus_driver_get_conn_helper (connection, message, "security context",
- &service, error);
+ found = bus_driver_get_conn_helper (connection, message, "security context",
+ &service, &conn, error);
- if (conn == NULL)
+ if (found == BUS_DRIVER_FOUND_ERROR)
goto failed;
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto oom;
- context = bus_connection_get_selinux_id (conn);
+ if (found == BUS_DRIVER_FOUND_SELF)
+ context = bus_selinux_get_self ();
+ else if (found == BUS_DRIVER_FOUND_PEER)
+ context = bus_connection_get_selinux_id (conn);
+ else
+ context = NULL;
+
if (!context)
{
dbus_set_error (error,
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_connection_credentials (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusMessage *reply;
DBusMessageIter reply_iter;
DBusMessageIter array_iter;
- unsigned long ulong_val;
+ unsigned long ulong_uid, ulong_pid;
char *s;
const char *service;
+ BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
reply = NULL;
- conn = bus_driver_get_conn_helper (connection, message, "credentials",
- &service, error);
+ found = bus_driver_get_conn_helper (connection, message, "credentials",
+ &service, &conn, error);
- if (conn == NULL)
- goto failed;
+ switch (found)
+ {
+ case BUS_DRIVER_FOUND_SELF:
+ ulong_pid = _dbus_getpid ();
+ ulong_uid = _dbus_getuid ();
+ break;
+
+ case BUS_DRIVER_FOUND_PEER:
+ if (!dbus_connection_get_unix_process_id (conn, &ulong_pid))
+ ulong_pid = DBUS_PID_UNSET;
+ if (!dbus_connection_get_unix_user (conn, &ulong_uid))
+ ulong_uid = DBUS_UID_UNSET;
+ break;
+ case BUS_DRIVER_FOUND_ERROR:
+ /* fall through */
+ default:
+ goto failed;
+ }
reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter);
if (reply == NULL)
/* we can't represent > 32-bit pids; if your system needs them, please
* add ProcessID64 to the spec or something */
- if (dbus_connection_get_unix_process_id (conn, &ulong_val) &&
- ulong_val <= _DBUS_UINT32_MAX)
- {
- if (!_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_val))
- goto oom;
- }
+ if (ulong_pid <= _DBUS_UINT32_MAX && ulong_pid != DBUS_PID_UNSET &&
+ !_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_pid))
+ goto oom;
/* we can't represent > 32-bit uids; if your system needs them, please
* add UnixUserID64 to the spec or something */
- if (dbus_connection_get_unix_user (conn, &ulong_val) &&
- ulong_val <= _DBUS_UINT32_MAX)
- {
- if (!_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_val))
- goto oom;
- }
+ if (ulong_uid <= _DBUS_UINT32_MAX && ulong_uid != DBUS_UID_UNSET &&
+ !_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_uid))
+ goto oom;
- if (dbus_connection_get_windows_user (conn, &s))
+ /* FIXME: Obtain the Windows user of the bus daemon itself */
+ if (found == BUS_DRIVER_FOUND_PEER &&
+ dbus_connection_get_windows_user (conn, &s))
{
DBusString str;
dbus_bool_t result;
dbus_free (s);
}
- if (_dbus_connection_get_linux_security_label (conn, &s))
+ /* FIXME: Obtain the security label for the bus daemon itself */
+ if (found == BUS_DRIVER_FOUND_PEER &&
+ _dbus_connection_get_linux_security_label (conn, &s))
{
if (s == NULL)
goto oom;
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
dbus_message_unref (reply);
}
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_reload_config (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
goto oom;
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
}
#endif
-static dbus_bool_t
+static BusResult
bus_driver_handle_get_id (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
if (!_dbus_string_init (&uuid))
{
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
reply = NULL;
_dbus_string_free (&uuid);
dbus_message_unref (reply);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (reply)
dbus_message_unref (reply);
_dbus_string_free (&uuid);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
static dbus_bool_t
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (!bus_driver_check_message_is_for_us (message, error))
- goto out;
-
context = bus_transaction_get_context (transaction);
bustype = context ? bus_context_get_type (context) : NULL;
if (!bus_apparmor_allows_eavesdropping (connection, bustype, error))
goto out;
- if (!bus_driver_check_caller_is_privileged (connection, transaction,
- message, error))
- goto out;
-
if (!dbus_message_get_args (message, error,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &match_rules, &n_match_rules,
DBUS_TYPE_UINT32, &flags,
rule = bus_match_rule_parse (connection, &str, error);
if (rule == NULL)
- {
- BUS_SET_OOM (error);
- goto out;
- }
+ goto out;
/* monitors always eavesdrop */
bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
/* Send the ack before we remove the rule, since the ack is undone
* on transaction cancel, but becoming a monitor isn't.
*/
- if (!send_ack_reply (connection, transaction, message, error))
+ if (!bus_driver_send_ack_reply (connection, transaction, message, error))
goto out;
if (!bus_connection_be_monitor (connection, transaction, &rules, error))
return ret;
}
+static dbus_bool_t
+bus_driver_handle_get_machine_id (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply = NULL;
+ DBusString uuid;
+ const char *str;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (!_dbus_string_init (&uuid))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!_dbus_get_local_machine_uuid_encoded (&uuid, error))
+ goto fail;
+
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL)
+ goto oom;
+
+ str = _dbus_string_get_const_data (&uuid);
+
+ if (!dbus_message_append_args (reply,
+ DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID))
+ goto oom;
+
+ _dbus_assert (dbus_message_has_signature (reply, "s"));
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ _dbus_string_free (&uuid);
+ dbus_message_unref (reply);
+ return TRUE;
+
+oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ BUS_SET_OOM (error);
+
+fail:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ _dbus_string_free (&uuid);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_ping (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ return bus_driver_send_ack_reply (connection, transaction, message, error);
+}
+
+static dbus_bool_t bus_driver_handle_get (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+
+static dbus_bool_t bus_driver_handle_get_all (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+
+static dbus_bool_t bus_driver_handle_set (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+
+static dbus_bool_t features_getter (BusContext *context,
+ DBusMessageIter *variant_iter);
+static dbus_bool_t interfaces_getter (BusContext *context,
+ DBusMessageIter *variant_iter);
+
+typedef enum
+{
+ /* Various older methods were available at every object path. We have to
+ * preserve that behaviour for backwards compatibility, but we can at least
+ * stop doing that for newly added methods.
+ * The special Peer interface should also work at any object path.
+ * <https://bugs.freedesktop.org/show_bug.cgi?id=101256> */
+ METHOD_FLAG_ANY_PATH = (1 << 0),
+
+ /* If set, callers must be privileged. On Unix, the uid of the connection
+ * must either be the uid of this process, or 0 (root). On Windows,
+ * the SID of the connection must be the SID of this process. */
+ METHOD_FLAG_PRIVILEGED = (1 << 1),
+
+ METHOD_FLAG_NONE = 0
+} MethodFlags;
+
typedef struct
{
const char *name;
const char *in_args;
const char *out_args;
- dbus_bool_t (* handler) (DBusConnection *connection,
- BusTransaction *transaction,
- DBusMessage *message,
- DBusError *error);
+ BusResult (* handler) (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+ MethodFlags flags;
} MessageHandler;
+typedef struct
+{
+ const char *name;
+ const char *type;
+ dbus_bool_t (* getter) (BusContext *context,
+ DBusMessageIter *variant_iter);
+} PropertyHandler;
+
/* For speed it might be useful to sort this in order of
* frequency of use (but doesn't matter with only a few items
* anyhow)
{ "Hello",
"",
DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_hello },
+ bus_driver_handle_hello,
+ METHOD_FLAG_ANY_PATH },
{ "RequestName",
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
- bus_driver_handle_acquire_service },
+ bus_driver_handle_acquire_service,
+ METHOD_FLAG_ANY_PATH },
{ "ReleaseName",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
- bus_driver_handle_release_service },
+ bus_driver_handle_release_service,
+ METHOD_FLAG_ANY_PATH },
{ "StartServiceByName",
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
- bus_driver_handle_activate_service },
+ bus_driver_handle_activate_service,
+ METHOD_FLAG_ANY_PATH },
{ "UpdateActivationEnvironment",
DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
"",
- bus_driver_handle_update_activation_environment },
+ bus_driver_handle_update_activation_environment,
+ METHOD_FLAG_PRIVILEGED },
{ "NameHasOwner",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_BOOLEAN_AS_STRING,
- bus_driver_handle_service_exists },
+ bus_driver_handle_service_exists,
+ METHOD_FLAG_ANY_PATH },
{ "ListNames",
"",
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_list_services },
+ bus_driver_handle_list_services,
+ METHOD_FLAG_ANY_PATH },
{ "ListActivatableNames",
"",
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_list_activatable_services },
+ bus_driver_handle_list_activatable_services,
+ METHOD_FLAG_ANY_PATH },
{ "AddMatch",
DBUS_TYPE_STRING_AS_STRING,
"",
- bus_driver_handle_add_match },
+ bus_driver_handle_add_match,
+ METHOD_FLAG_ANY_PATH },
{ "RemoveMatch",
DBUS_TYPE_STRING_AS_STRING,
"",
- bus_driver_handle_remove_match },
+ bus_driver_handle_remove_match,
+ METHOD_FLAG_ANY_PATH },
{ "GetNameOwner",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_get_service_owner },
+ bus_driver_handle_get_service_owner,
+ METHOD_FLAG_ANY_PATH },
{ "ListQueuedOwners",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_list_queued_owners },
+ bus_driver_handle_list_queued_owners,
+ METHOD_FLAG_ANY_PATH },
{ "GetConnectionUnixUser",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
- bus_driver_handle_get_connection_unix_user },
+ bus_driver_handle_get_connection_unix_user,
+ METHOD_FLAG_ANY_PATH },
{ "GetConnectionUnixProcessID",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
- bus_driver_handle_get_connection_unix_process_id },
+ bus_driver_handle_get_connection_unix_process_id,
+ METHOD_FLAG_ANY_PATH },
{ "GetAdtAuditSessionData",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
- bus_driver_handle_get_adt_audit_session_data },
+ bus_driver_handle_get_adt_audit_session_data,
+ METHOD_FLAG_ANY_PATH },
{ "GetConnectionSELinuxSecurityContext",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
- bus_driver_handle_get_connection_selinux_security_context },
+ bus_driver_handle_get_connection_selinux_security_context,
+ METHOD_FLAG_ANY_PATH },
{ "ReloadConfig",
"",
"",
- bus_driver_handle_reload_config },
+ bus_driver_handle_reload_config,
+ METHOD_FLAG_ANY_PATH },
{ "GetId",
"",
DBUS_TYPE_STRING_AS_STRING,
- bus_driver_handle_get_id },
+ bus_driver_handle_get_id,
+ METHOD_FLAG_ANY_PATH },
{ "GetConnectionCredentials", "s", "a{sv}",
- bus_driver_handle_get_connection_credentials },
+ bus_driver_handle_get_connection_credentials,
+ METHOD_FLAG_ANY_PATH },
{ NULL, NULL, NULL, NULL }
};
-static dbus_bool_t bus_driver_handle_introspect (DBusConnection *,
+static const PropertyHandler dbus_property_handlers[] = {
+ { "Features", "as", features_getter },
+ { "Interfaces", "as", interfaces_getter },
+ { NULL, NULL, NULL }
+};
+
+static BusResult bus_driver_handle_introspect (DBusConnection *,
BusTransaction *, DBusMessage *, DBusError *);
+static const MessageHandler properties_message_handlers[] = {
+ { "Get", "ss", "v", bus_driver_handle_get, METHOD_FLAG_NONE },
+ { "GetAll", "s", "a{sv}", bus_driver_handle_get_all, METHOD_FLAG_NONE },
+ { "Set", "ssv", "", bus_driver_handle_set, METHOD_FLAG_NONE },
+ { NULL, NULL, NULL, NULL }
+};
+
static const MessageHandler introspectable_message_handlers[] = {
- { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect },
+ { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect,
+ METHOD_FLAG_ANY_PATH },
{ NULL, NULL, NULL, NULL }
};
static const MessageHandler monitoring_message_handlers[] = {
- { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor },
+ { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor,
+ METHOD_FLAG_PRIVILEGED },
{ NULL, NULL, NULL, NULL }
};
#ifdef DBUS_ENABLE_VERBOSE_MODE
static const MessageHandler verbose_message_handlers[] = {
- { "EnableVerbose", "", "", bus_driver_handle_enable_verbose},
- { "DisableVerbose", "", "", bus_driver_handle_disable_verbose},
+ { "EnableVerbose", "", "", bus_driver_handle_enable_verbose,
+ METHOD_FLAG_NONE },
+ { "DisableVerbose", "", "", bus_driver_handle_disable_verbose,
+ METHOD_FLAG_NONE },
{ NULL, NULL, NULL, NULL }
};
#endif
#ifdef DBUS_ENABLE_STATS
static const MessageHandler stats_message_handlers[] = {
- { "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
- { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats },
- { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules },
+ { "GetStats", "", "a{sv}", bus_stats_handle_get_stats,
+ METHOD_FLAG_NONE },
+ { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats,
+ METHOD_FLAG_NONE },
+ { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules,
+ METHOD_FLAG_NONE },
{ NULL, NULL, NULL, NULL }
};
#endif
+static const MessageHandler peer_message_handlers[] = {
+ { "GetMachineId", "", "s", bus_driver_handle_get_machine_id,
+ METHOD_FLAG_ANY_PATH },
+ { "Ping", "", "", bus_driver_handle_ping, METHOD_FLAG_ANY_PATH },
+ { NULL, NULL, NULL, NULL }
+};
+
+typedef enum
+{
+ /* Various older interfaces were available at every object path. We have to
+ * preserve that behaviour for backwards compatibility, but we can at least
+ * stop doing that for newly added interfaces:
+ * <https://bugs.freedesktop.org/show_bug.cgi?id=101256>
+ * Introspectable and Peer are also useful at all object paths. */
+ INTERFACE_FLAG_ANY_PATH = (1 << 0),
+
+ /* Set this flag for interfaces that should not show up in the
+ * Interfaces property. */
+ INTERFACE_FLAG_UNINTERESTING = (1 << 1),
+
+ INTERFACE_FLAG_NONE = 0
+} InterfaceFlags;
+
typedef struct {
const char *name;
const MessageHandler *message_handlers;
const char *extra_introspection;
+ InterfaceFlags flags;
+ const PropertyHandler *property_handlers;
} InterfaceHandler;
/* These should ideally be sorted by frequency of use, although it
" </signal>\n"
" <signal name=\"NameAcquired\">\n"
" <arg type=\"s\"/>\n"
- " </signal>\n" },
- { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
- { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL },
+ " </signal>\n",
+ /* Not in the Interfaces property because if you can get the properties
+ * of the o.fd.DBus interface, then you certainly have the o.fd.DBus
+ * interface, so there is little point in listing it explicitly.
+ * Partially available at all paths for backwards compatibility. */
+ INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING,
+ dbus_property_handlers },
+ { DBUS_INTERFACE_PROPERTIES, properties_message_handlers,
+ " <signal name=\"PropertiesChanged\">\n"
+ " <arg type=\"s\" name=\"interface_name\"/>\n"
+ " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
+ " <arg type=\"as\" name=\"invalidated_properties\"/>\n"
+ " </signal>\n",
+ /* Not in the Interfaces property because if you can get the properties
+ * of the o.fd.DBus interface, then you certainly have Properties. */
+ INTERFACE_FLAG_UNINTERESTING },
+ { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL,
+ /* Not in the Interfaces property because introspection isn't really a
+ * feature in the same way as e.g. Monitoring.
+ * Available at all paths so tools like d-feet can start from "/". */
+ INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING },
+ { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL,
+ INTERFACE_FLAG_NONE },
#ifdef DBUS_ENABLE_VERBOSE_MODE
- { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL },
+ { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL,
+ INTERFACE_FLAG_NONE },
#endif
#ifdef DBUS_ENABLE_STATS
- { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
+ { BUS_INTERFACE_STATS, stats_message_handlers, NULL,
+ INTERFACE_FLAG_NONE },
#endif
+ { DBUS_INTERFACE_PEER, peer_message_handlers, NULL,
+ /* Not in the Interfaces property because it's a pseudo-interface
+ * on all object paths of all connections, rather than a feature of the
+ * bus driver object. */
+ INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING },
{ NULL, NULL, NULL }
};
}
dbus_bool_t
-bus_driver_generate_introspect_string (DBusString *xml)
+bus_driver_generate_introspect_string (DBusString *xml,
+ dbus_bool_t is_canonical_path,
+ DBusMessage *message)
{
const InterfaceHandler *ih;
const MessageHandler *mh;
+ const PropertyHandler *ph;
if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
return FALSE;
for (ih = interface_handlers; ih->name != NULL; ih++)
{
+ if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+ continue;
+
if (!_dbus_string_append_printf (xml, " <interface name=\"%s\">\n",
ih->name))
return FALSE;
return FALSE;
}
+ for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+ {
+ /* We only have constant properties so far, so hard-code that bit */
+ if (!_dbus_string_append_printf (xml,
+ " <property name=\"%s\" type=\"%s\" access=\"read\">\n",
+ ph->name, ph->type))
+ return FALSE;
+
+ if (!_dbus_string_append (xml,
+ " <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n"
+ " </property>\n"))
+ return FALSE;
+ }
+
if (ih->extra_introspection != NULL &&
!_dbus_string_append (xml, ih->extra_introspection))
return FALSE;
return FALSE;
}
+ if (message != NULL)
+ {
+ /* Make the bus driver object path discoverable */
+ if (dbus_message_has_path (message, "/"))
+ {
+ if (!_dbus_string_append (xml,
+ " <node name=\"org/freedesktop/DBus\"/>\n"))
+ return FALSE;
+ }
+ else if (dbus_message_has_path (message, "/org"))
+ {
+ if (!_dbus_string_append (xml,
+ " <node name=\"freedesktop/DBus\"/>\n"))
+ return FALSE;
+ }
+ else if (dbus_message_has_path (message, "/org/freedesktop"))
+ {
+ if (!_dbus_string_append (xml, " <node name=\"DBus\"/>\n"))
+ return FALSE;
+ }
+ }
+
if (!_dbus_string_append (xml, "</node>\n"))
return FALSE;
return TRUE;
}
-static dbus_bool_t
+static BusResult
bus_driver_handle_introspect (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusString xml;
DBusMessage *reply;
const char *v_STRING;
+ dbus_bool_t is_canonical_path;
_dbus_verbose ("Introspect() on bus driver\n");
DBUS_TYPE_INVALID))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
if (!_dbus_string_init (&xml))
{
BUS_SET_OOM (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
- if (!bus_driver_generate_introspect_string (&xml))
+ is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS);
+
+ if (!bus_driver_generate_introspect_string (&xml, is_canonical_path, message))
goto oom;
v_STRING = _dbus_string_get_const_data (&xml);
dbus_message_unref (reply);
_dbus_string_free (&xml);
- return TRUE;
+ return BUS_RESULT_TRUE;
oom:
BUS_SET_OOM (error);
_dbus_string_free (&xml);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
-/*
- * Set @error and return FALSE if the message is not directed to the
- * dbus-daemon by its canonical object path. This is hardening against
- * system services with poorly-written security policy files, which
- * might allow sending dangerously broad equivalence classes of messages
- * such as "anything with this assumed-to-be-safe object path".
- *
- * dbus-daemon is unusual in that it normally ignores the object path
- * of incoming messages; we need to keep that behaviour for the "read"
- * read-only method calls like GetConnectionUnixUser for backwards
- * compatibility, but it seems safer to be more restrictive for things
- * intended to be root-only or privileged-developers-only.
- *
- * It is possible that there are other system services with the same
- * quirk as dbus-daemon.
- */
-dbus_bool_t
-bus_driver_check_message_is_for_us (DBusMessage *message,
- DBusError *error)
-{
- if (!dbus_message_has_path (message, DBUS_PATH_DBUS))
- {
- dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
- "Method '%s' is only available at the canonical object path '%s'",
- dbus_message_get_member (message), DBUS_PATH_DBUS);
-
- return FALSE;
- }
-
- return TRUE;
-}
-
-dbus_bool_t
+BusResult
bus_driver_handle_message (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
const InterfaceHandler *ih;
const MessageHandler *mh;
dbus_bool_t found_interface = FALSE;
+ dbus_bool_t is_canonical_path;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
BusContext *context;
DBusConnection *systemd;
+ /* This is a directed signal, not a method call, so the log message
+ * is a little weird (it talks about "calling" ActivationFailure),
+ * but it's close enough */
+ if (!bus_driver_check_caller_is_privileged (connection,
+ transaction,
+ message,
+ error))
+ return BUS_RESULT_FALSE;
+
context = bus_connection_get_context (connection);
systemd = bus_driver_get_owner_of_name (connection,
"org.freedesktop.systemd1");
attacker ? attacker : "(unauthenticated)",
bus_connection_get_loginfo (connection));
/* ignore it */
- return TRUE;
+ return BUS_RESULT_TRUE;
+ }
+
+ if (!bus_context_get_systemd_activation (context))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "Ignoring unexpected ActivationFailure message "
+ "while not using systemd activation");
+ return BUS_RESULT_FALSE;
}
- return dbus_activation_systemd_failure(bus_context_get_activation(context), message);
+ return dbus_activation_systemd_failure(bus_context_get_activation(context), message) == TRUE ? BUS_RESULT_TRUE : BUS_RESULT_FALSE;
}
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
{
_dbus_verbose ("Driver got a non-method-call message, ignoring\n");
- return TRUE; /* we just ignore this */
+ return BUS_RESULT_TRUE; /* we just ignore this */
}
/* may be NULL, which means "any interface will do" */
_dbus_assert (dbus_message_get_sender (message) != NULL ||
strcmp (name, "Hello") == 0);
+ is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS);
+
for (ih = interface_handlers; ih->name != NULL; ih++)
{
+ if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+ continue;
+
if (interface != NULL && strcmp (interface, ih->name) != 0)
continue;
_dbus_verbose ("Found driver handler for %s\n", name);
+ if ((mh->flags & METHOD_FLAG_PRIVILEGED) &&
+ !bus_driver_check_caller_is_privileged (connection, transaction,
+ message, error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return BUS_RESULT_FALSE;
+ }
+
+ if (!(is_canonical_path || (mh->flags & METHOD_FLAG_ANY_PATH)))
+ {
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Method '%s' is only available at the canonical object path '%s'",
+ dbus_message_get_member (message), DBUS_PATH_DBUS);
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return BUS_RESULT_FALSE;
+ }
+
if (!dbus_message_has_signature (message, mh->in_args))
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
name, dbus_message_get_signature (message),
mh->in_args);
_DBUS_ASSERT_ERROR_IS_SET (error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
- if ((* mh->handler) (connection, transaction, message, error))
- {
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- _dbus_verbose ("Driver handler succeeded\n");
- return TRUE;
- }
- else
+ switch ((* mh->handler) (connection, transaction, message, error))
{
- _DBUS_ASSERT_ERROR_IS_SET (error);
- _dbus_verbose ("Driver handler returned failure\n");
- return FALSE;
+ case BUS_RESULT_TRUE:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ _dbus_verbose ("Driver handler succeeded\n");
+ return BUS_RESULT_TRUE;
+ case BUS_RESULT_FALSE:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_verbose ("Driver handler returned failure\n");
+ return BUS_RESULT_FALSE;
+ case BUS_RESULT_LATER:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ _dbus_verbose ("Driver handler delayed message processing due to policy check\n");
+ return BUS_RESULT_LATER;
}
}
}
"%s does not understand message %s",
DBUS_SERVICE_DBUS, name);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
void
* with the bus driver.
*/
}
+
+static dbus_bool_t
+features_getter (BusContext *context,
+ DBusMessageIter *variant_iter)
+{
+ DBusMessageIter arr_iter;
+
+ if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &arr_iter))
+ return FALSE;
+
+ if (bus_apparmor_enabled ())
+ {
+ const char *s = "AppArmor";
+
+ if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+ goto abandon;
+ }
+
+ if (bus_selinux_enabled ())
+ {
+ const char *s = "SELinux";
+
+ if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+ goto abandon;
+ }
+
+ if (bus_context_get_systemd_activation (context))
+ {
+ const char *s = "SystemdActivation";
+
+ if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s))
+ goto abandon;
+ }
+
+ return dbus_message_iter_close_container (variant_iter, &arr_iter);
+
+abandon:
+ dbus_message_iter_abandon_container (variant_iter, &arr_iter);
+ return FALSE;
+}
+
+static dbus_bool_t
+interfaces_getter (BusContext *context,
+ DBusMessageIter *variant_iter)
+{
+ DBusMessageIter arr_iter;
+ const InterfaceHandler *ih;
+
+ if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &arr_iter))
+ return FALSE;
+
+ for (ih = interface_handlers; ih->name != NULL; ih++)
+ {
+ if (ih->flags & INTERFACE_FLAG_UNINTERESTING)
+ continue;
+
+ if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING,
+ &ih->name))
+ goto abandon;
+ }
+
+ return dbus_message_iter_close_container (variant_iter, &arr_iter);
+
+abandon:
+ dbus_message_iter_abandon_container (variant_iter, &arr_iter);
+ return FALSE;
+}
+
+static const InterfaceHandler *
+bus_driver_find_interface (const char *name,
+ dbus_bool_t canonical_path,
+ DBusError *error)
+{
+ const InterfaceHandler *ih;
+
+ for (ih = interface_handlers; ih->name != NULL; ih++)
+ {
+ if (!(canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH)))
+ continue;
+
+ if (strcmp (name, ih->name) == 0)
+ return ih;
+ }
+
+ dbus_set_error (error, DBUS_ERROR_UNKNOWN_INTERFACE,
+ "Interface \"%s\" not found", name);
+ return NULL;
+}
+
+static const PropertyHandler *
+interface_handler_find_property (const InterfaceHandler *ih,
+ const char *name,
+ DBusError *error)
+{
+ const PropertyHandler *ph;
+
+ for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+ {
+ if (strcmp (name, ph->name) == 0)
+ return ph;
+ }
+
+ dbus_set_error (error, DBUS_ERROR_UNKNOWN_PROPERTY,
+ "Property \"%s.%s\" not found", ih->name, name);
+ return NULL;
+}
+
+static dbus_bool_t
+bus_driver_handle_get (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ const InterfaceHandler *ih;
+ const PropertyHandler *handler;
+ const char *iface;
+ const char *prop;
+ BusContext *context;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter var_iter;
+
+ /* The message signature has already been checked for us,
+ * so this should always succeed. */
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_STRING, &prop,
+ DBUS_TYPE_INVALID))
+ return FALSE;
+
+ /* We only implement Properties on /org/freedesktop/DBus so far. */
+ ih = bus_driver_find_interface (iface, TRUE, error);
+
+ if (ih == NULL)
+ return FALSE;
+
+ handler = interface_handler_find_property (ih, prop, error);
+
+ if (handler == NULL)
+ return FALSE;
+
+ context = bus_transaction_get_context (transaction);
+
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL)
+ goto oom;
+
+ dbus_message_iter_init_append (reply, &iter);
+
+ if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT,
+ handler->type, &var_iter))
+ goto oom;
+
+ if (!handler->getter (context, &var_iter))
+ {
+ dbus_message_iter_abandon_container (&iter, &var_iter);
+ goto oom;
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &var_iter))
+ goto oom;
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+oom:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ BUS_SET_OOM (error);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_get_all (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ const InterfaceHandler *ih;
+ const char *iface;
+ const PropertyHandler *ph;
+ DBusMessageIter reply_iter;
+ DBusMessageIter array_iter;
+ BusContext *context;
+ DBusMessage *reply = NULL;
+
+ /* The message signature has already been checked for us,
+ * so this should always succeed. */
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_INVALID))
+ return FALSE;
+
+ /* We only implement Properties on /org/freedesktop/DBus so far. */
+ ih = bus_driver_find_interface (iface, TRUE, error);
+
+ if (ih == NULL)
+ return FALSE;
+
+ context = bus_transaction_get_context (transaction);
+
+ reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter);
+
+ if (reply == NULL)
+ goto oom;
+
+ for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++)
+ {
+ DBusMessageIter entry_iter;
+ DBusMessageIter var_iter;
+
+ if (!_dbus_asv_open_entry (&array_iter, &entry_iter, ph->name,
+ ph->type, &var_iter))
+ goto oom_abandon_message;
+
+ if (!ph->getter (context, &var_iter))
+ {
+ _dbus_asv_abandon_entry (&array_iter, &entry_iter, &var_iter);
+ goto oom_abandon_message;
+ }
+
+ if (!_dbus_asv_close_entry (&array_iter, &entry_iter, &var_iter))
+ goto oom_abandon_message;
+ }
+
+ if (!_dbus_asv_close (&reply_iter, &array_iter))
+ goto oom;
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+oom_abandon_message:
+ _dbus_asv_abandon (&reply_iter, &array_iter);
+ /* fall through */
+oom:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ BUS_SET_OOM (error);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_set (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ const InterfaceHandler *ih;
+ const char *iface;
+ const char *prop;
+ const PropertyHandler *handler;
+ DBusMessageIter iter;
+
+ /* We already checked this in bus_driver_handle_message() */
+ _dbus_assert (dbus_message_has_signature (message, "ssv"));
+
+ if (!dbus_message_iter_init (message, &iter))
+ _dbus_assert_not_reached ("Message type was already checked to be 'ssv'");
+
+ dbus_message_iter_get_basic (&iter, &iface);
+
+ if (!dbus_message_iter_next (&iter))
+ _dbus_assert_not_reached ("Message type was already checked to be 'ssv'");
+
+ dbus_message_iter_get_basic (&iter, &prop);
+
+ /* We only implement Properties on /org/freedesktop/DBus so far. */
+ ih = bus_driver_find_interface (iface, TRUE, error);
+
+ if (ih == NULL)
+ return FALSE;
+
+ handler = interface_handler_find_property (ih, prop, error);
+
+ if (handler == NULL)
+ return FALSE;
+
+ /* We don't implement any properties that can be set yet. */
+ dbus_set_error (error, DBUS_ERROR_PROPERTY_READ_ONLY,
+ "Property '%s.%s' cannot be set", iface, prop);
+ return FALSE;
+}