2003-04-13 Havoc Pennington <hp@pobox.com>
+ * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting
+ callbacks
+
+ * test/data/valid-config-files/debug-allow-all.conf.in: allow all
+ users
+
+ * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status):
+ fix to only recover unused bytes if we're already authenticated
+ (_dbus_transport_get_is_authenticated): fix to still mark us
+ authenticated if there are unused bytes.
+
+ * bus/dispatch.c: implement security policy checking
+
+ * bus/connection.c (bus_transaction_send_from_driver): new
+
+ * bus/bus.c (bus_context_check_security_policy): new
+
+ * bus/dispatch.c (send_service_nonexistent_error): delete this,
+ now we just set the DBusError and it gets converted to an error
+ reply.
+
+ * bus/connection.c (allow_user_function): enable code using actual
+ data from the config file
+
+ * bus/policy.c (list_allows_user): handle wildcard rules for
+ user/group connection perms
+
+2003-04-13 Havoc Pennington <hp@pobox.com>
+
* bus/config-parser.c: Load up the BusPolicy and BusPolicyRules
* dbus/dbus-sysdeps.c (_dbus_get_user_id): new function
goto error;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
- !dbus_message_append_args (message,
+ if (!dbus_message_append_args (message,
DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
0))
{
goto error;
}
- if (!bus_transaction_send_message (transaction, entry->connection, message))
+ if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
{
dbus_message_unref (message);
BUS_SET_OOM (error);
how->message);
if (!message)
goto error;
-
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
- {
- dbus_message_unref (message);
- goto error;
- }
- if (!bus_transaction_send_message (transaction, entry->connection, message))
+ if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
{
dbus_message_unref (message);
goto error;
return FALSE;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
- !dbus_message_append_args (message,
+ if (!dbus_message_append_args (message,
DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,
0))
{
return FALSE;
}
- retval = bus_transaction_send_message (transaction, connection, message);
+ retval = bus_transaction_send_from_driver (transaction, connection, message);
dbus_message_unref (message);
if (!retval)
{
return context->activation_timeout;
}
+
+dbus_bool_t
+bus_context_check_security_policy (BusContext *context,
+ DBusConnection *sender,
+ DBusConnection *recipient,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusClientPolicy *sender_policy;
+ BusClientPolicy *recipient_policy;
+
+ /* NULL sender/receiver means the bus driver */
+
+ if (sender != NULL)
+ {
+ _dbus_assert (dbus_connection_get_is_authenticated (sender));
+ sender_policy = bus_connection_get_policy (sender);
+ }
+ else
+ sender_policy = NULL;
+
+ if (recipient != NULL)
+ {
+ _dbus_assert (dbus_connection_get_is_authenticated (recipient));
+ recipient_policy = bus_connection_get_policy (recipient);
+ }
+ else
+ recipient_policy = NULL;
+
+ if (sender_policy &&
+ !bus_client_policy_check_can_send (sender_policy,
+ context->registry, recipient,
+ message))
+ {
+ const char *dest = dbus_message_get_service (message);
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "A security policy in place prevents this sender "
+ "from sending this message to this recipient, "
+ "see message bus configuration file (rejected message "
+ "had name \"%s\" destination \"%s\")",
+ dbus_message_get_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS);
+ return FALSE;
+ }
+
+ if (recipient_policy &&
+ !bus_client_policy_check_can_receive (recipient_policy,
+ context->registry, sender,
+ message))
+ {
+ const char *dest = dbus_message_get_service (message);
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "A security policy in place prevents this recipient "
+ "from receiving this message from this sender, "
+ "see message bus configuration file (rejected message "
+ "had name \"%s\" destination \"%s\")",
+ dbus_message_get_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS);
+ return FALSE;
+ }
+
+ return TRUE;
+}
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection);
int bus_context_get_activation_timeout (BusContext *context);
+dbus_bool_t bus_context_check_security_policy (BusContext *context,
+ DBusConnection *sender,
+ DBusConnection *recipient,
+ DBusMessage *message,
+ DBusError *error);
#endif /* BUS_BUS_H */
if (rule == NULL)
goto nomem;
- /* FIXME the wildcard needs storing in the rule somehow */
+ rule->d.user.uid = DBUS_UID_UNSET;
}
else
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
if (rule == NULL)
goto nomem;
-
- rule->d.user.user = _dbus_strdup (user);
- if (rule->d.user.user == NULL)
- goto nomem;
+
rule->d.user.uid = uid;
}
else
if (rule == NULL)
goto nomem;
- /* FIXME the wildcard needs storing in the rule somehow */
+ rule->d.group.gid = DBUS_GID_UNSET;
}
else
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
if (rule == NULL)
goto nomem;
-
- rule->d.group.group = _dbus_strdup (group);
- if (rule->d.group.group == NULL)
- goto nomem;
+
rule->d.group.gid = gid;
}
else
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
-
- return TRUE; /* FIXME - this is just until we can parse a config file */
return bus_context_allow_user (d->connections->context, uid);
}
if (dbus_connection_get_unix_user (connection, &uid))
{
- if (!_dbus_get_groups (uid, &d->group_ids, &d->n_group_ids))
+ if (!_dbus_get_groups (uid, &d->group_ids, &d->n_group_ids, NULL))
{
_dbus_verbose ("Did not get any groups for UID %lu\n",
uid);
}
dbus_bool_t
-bus_transaction_send_message (BusTransaction *transaction,
- DBusConnection *connection,
- DBusMessage *message)
+bus_transaction_send_from_driver (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ /* We have to set the sender to the driver, and have
+ * to check security policy since it was not done in
+ * dispatch.c
+ */
+ _dbus_verbose ("Sending %s from driver\n",
+ dbus_message_get_name (message));
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ return FALSE;
+
+ /* If security policy doesn't allow the message, we silently
+ * eat it; the driver doesn't care about getting a reply.
+ */
+ if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
+ NULL, connection, message, NULL))
+ return TRUE;
+
+ return bus_transaction_send (transaction, connection, message);
+}
+
+dbus_bool_t
+bus_transaction_send (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message)
{
MessageToSend *to_send;
BusConnectionData *d;
_dbus_verbose (" trying to add %s %s to transaction%s\n",
dbus_message_get_is_error (message) ? "error" :
- dbus_message_get_reply_serial (message) != 0 ? "reply" :
+ dbus_message_get_reply_serial (message) != -1 ? "reply" :
"message",
dbus_message_get_name (message),
dbus_connection_get_is_connected (connection) ?
if (reply == NULL)
return FALSE;
- if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS) ||
- !bus_transaction_send_message (transaction, connection, reply))
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
dbus_message_unref (reply);
return FALSE;
BusTransaction* bus_transaction_new (BusContext *context);
BusContext* bus_transaction_get_context (BusTransaction *transaction);
BusConnections* bus_transaction_get_connections (BusTransaction *transaction);
-dbus_bool_t bus_transaction_send_message (BusTransaction *transaction,
+dbus_bool_t bus_transaction_send (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message);
+dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message);
dbus_bool_t bus_transaction_send_error_reply (BusTransaction *transaction,
typedef struct
{
+ BusContext *context;
+ DBusConnection *sender;
DBusMessage *message;
BusTransaction *transaction;
DBusError *error;
if (!bus_connection_is_active (connection))
return TRUE;
- if (!bus_transaction_send_message (d->transaction,
- connection,
- d->message))
+ if (!bus_context_check_security_policy (d->context,
+ d->sender,
+ connection,
+ d->message,
+ NULL))
+ return TRUE; /* silently don't send it */
+
+ if (!bus_transaction_send (d->transaction,
+ connection,
+ d->message))
{
BUS_SET_OOM (d->error);
return FALSE;
dbus_bool_t
bus_dispatch_broadcast_message (BusTransaction *transaction,
+ DBusConnection *sender,
DBusMessage *message,
DBusError *error)
{
connections = bus_transaction_get_connections (transaction);
dbus_error_init (&tmp_error);
+ d.sender = sender;
+ d.context = bus_transaction_get_context (transaction);
d.message = message;
d.transaction = transaction;
d.error = &tmp_error;
return TRUE;
}
-static dbus_bool_t
-send_service_nonexistent_error (BusTransaction *transaction,
- DBusConnection *connection,
- const char *service_name,
- DBusMessage *in_reply_to,
- DBusError *error)
-{
- DBusMessage *error_reply;
- DBusString error_message;
- const char *error_str;
-
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
- /* Trying to send a message to a non-existant service,
- * bounce back an error message.
- */
-
- if (!_dbus_string_init (&error_message))
- {
- BUS_SET_OOM (error);
- return FALSE;
- }
-
- if (!_dbus_string_append (&error_message, "Service \"") ||
- !_dbus_string_append (&error_message, service_name) ||
- !_dbus_string_append (&error_message, "\" does not exist"))
- {
- _dbus_string_free (&error_message);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
- error_str = _dbus_string_get_const_data (&error_message);
- error_reply = dbus_message_new_error_reply (in_reply_to,
- DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
- error_str);
-
- _dbus_string_free (&error_message);
-
- if (error_reply == NULL)
- {
- BUS_SET_OOM (error);
- return FALSE;
- }
-
- if (!dbus_message_set_sender (error_reply, DBUS_SERVICE_DBUS))
- {
- dbus_message_unref (error_reply);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
- if (!bus_transaction_send_message (transaction, connection, error_reply))
- {
- dbus_message_unref (error_reply);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
- dbus_message_unref (error_reply);
-
- return TRUE;
-}
-
static void
bus_dispatch (DBusConnection *connection,
DBusMessage *message)
_dbus_verbose ("DISPATCH: %s to %s\n",
message_name, service_name ? service_name : "peer");
- /* If service_name is NULL, this is a message to the bus daemon, not intended
- * to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
- * immediately, especially disconnection messages.
+ /* If service_name is NULL, this is a message to the bus daemon, not
+ * intended to actually go "on the bus"; e.g. a peer-to-peer
+ * ping. Handle these immediately, especially disconnection
+ * messages. There are no security policy checks on these.
*/
if (service_name == NULL)
{
if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
{
+ if (!bus_context_check_security_policy (context,
+ connection, NULL, message, &error))
+ goto out;
+
if (!bus_driver_handle_message (connection, transaction, message, &error))
goto out;
}
*/
else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
{
- if (!bus_dispatch_broadcast_message (transaction, message, &error))
+ if (!bus_dispatch_broadcast_message (transaction, connection, message, &error))
goto out;
}
else /* route to named service */
if (service == NULL)
{
- if (!send_service_nonexistent_error (transaction, connection,
- service_name,
- message, &error))
- goto out;
+ dbus_set_error (&error,
+ DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
+ "Service \"%s\" does not exist",
+ service_name);
+ goto out;
}
else
{
- _dbus_assert (bus_service_get_primary_owner (service) != NULL);
-
+ DBusConnection *recipient;
+
+ recipient = bus_service_get_primary_owner (service);
+ _dbus_assert (recipient != NULL);
+
+ if (!bus_context_check_security_policy (context,
+ connection, recipient, message, &error))
+ goto out;
+
/* Dispatch the message */
- if (!bus_transaction_send_message (transaction,
- bus_service_get_primary_owner (service),
- message))
+ if (!bus_transaction_send (transaction, recipient, message))
{
BUS_SET_OOM (&error);
goto out;
&error, message))
{
bus_connection_send_oom_error (connection, message);
-
+
/* cancel transaction due to OOM */
if (transaction != NULL)
{
/* dispatching disconnect handler will unref once */
if (bus_connection_dispatch_one_message (connection))
_dbus_assert_not_reached ("message other than disconnect dispatched after failure to register");
- dbus_connection_unref (connection);
+
_dbus_assert (!bus_test_client_listed (connection));
+ dbus_connection_unref (connection);
}
typedef struct
DBusError error;
char *name;
char *acquired;
-
+
+ retval = FALSE;
dbus_error_init (&error);
name = NULL;
acquired = NULL;
+ message = NULL;
message = dbus_message_new (DBUS_SERVICE_DBUS,
DBUS_MESSAGE_HELLO);
dbus_message_unref (message);
message = NULL;
- bus_test_run_everything (context);
+ /* send our message */
+ bus_test_run_clients_loop (TRUE);
+
+ dbus_connection_ref (connection); /* because we may get disconnected */
+ block_connection_until_message_from_bus (context, connection);
if (!dbus_connection_get_is_connected (connection))
{
_dbus_verbose ("connection was disconnected\n");
+
+ dbus_connection_unref (connection);
+
return TRUE;
}
-
- retval = FALSE;
+
+ dbus_connection_unref (connection);
message = pop_message_waiting_for_memory (connection);
if (message == NULL)
message = dbus_connection_borrow_message (connection);
got_error = message != NULL && dbus_message_get_is_error (message);
if (message)
- dbus_connection_return_message (connection, message);
+ {
+ dbus_connection_return_message (connection, message);
+ message = NULL;
+ }
if (!got_error)
{
if (!check_hello_message (context, baz))
_dbus_assert_not_reached ("hello message failed");
+ if (!check_no_leftovers (context))
+ {
+ _dbus_warn ("Messages were left over after setting up initial connections");
+ _dbus_assert_not_reached ("initial connection setup failed");
+ }
+
check1_try_iterations (context, "create_and_hello",
check_hello_connection);
dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
void bus_dispatch_remove_connection (DBusConnection *connection);
dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction,
+ DBusConnection *sender,
DBusMessage *message,
DBusError *error);
return FALSE;
}
- retval = bus_dispatch_broadcast_message (transaction, message, error);
+ retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
dbus_message_unref (message);
return retval;
return FALSE;
}
- retval = bus_dispatch_broadcast_message (transaction, message, error);
+ retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
dbus_message_unref (message);
return retval;
return FALSE;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
- {
- dbus_message_unref (message);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
if (!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
0))
return FALSE;
}
- if (!bus_transaction_send_message (transaction, connection, message))
+ if (!bus_transaction_send_from_driver (transaction, connection, message))
{
dbus_message_unref (message);
BUS_SET_OOM (error);
return FALSE;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
- {
- dbus_message_unref (message);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
if (!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
0))
return FALSE;
}
- if (!bus_transaction_send_message (transaction, connection, message))
+ if (!bus_transaction_send_from_driver (transaction, connection, message))
{
dbus_message_unref (message);
BUS_SET_OOM (error);
return FALSE;
}
- if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS))
- {
- dbus_message_unref (welcome);
- BUS_SET_OOM (error);
- return FALSE;
- }
-
if (!dbus_message_append_args (welcome,
DBUS_TYPE_STRING, name,
NULL))
return FALSE;
}
- if (!bus_transaction_send_message (transaction, connection, welcome))
+ if (!bus_transaction_send_from_driver (transaction, connection, welcome))
{
dbus_message_unref (welcome);
BUS_SET_OOM (error);
dbus_free_string_array (services);
- if (!bus_transaction_send_message (transaction, connection, reply))
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
dbus_message_unref (reply);
BUS_SET_OOM (error);
goto out;
}
- if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
- {
- BUS_SET_OOM (error);
- goto out;
- }
-
if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, DBUS_TYPE_INVALID))
{
BUS_SET_OOM (error);
goto out;
}
- if (!bus_transaction_send_message (transaction, connection, reply))
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
BUS_SET_OOM (error);
goto out;
BUS_SET_OOM (error);
goto out;
}
-
- if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
- {
- BUS_SET_OOM (error);
- goto out;
- }
if (!dbus_message_append_args (reply,
DBUS_TYPE_UINT32, service != NULL,
goto out;
}
- if (!bus_transaction_send_message (transaction, connection, reply))
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
BUS_SET_OOM (error);
goto out;
return FALSE;
}
+ if (dbus_message_get_reply_serial (message) != -1)
+ {
+ _dbus_verbose ("Client sent a reply to the bus driver, ignoring it\n");
+ return TRUE;
+ }
+
i = 0;
while (i < _DBUS_N_ELEMENTS (message_handlers))
{
_dbus_assert (rule->refcount > 0);
rule->refcount -= 1;
-
+
if (rule->refcount == 0)
{
switch (rule->type)
dbus_free (rule->d.own.service_name);
break;
case BUS_POLICY_RULE_USER:
- dbus_free (rule->d.user.user);
break;
case BUS_POLICY_RULE_GROUP:
- dbus_free (rule->d.group.group);
break;
}
{
BusClientPolicy *client;
unsigned long uid;
- DBusList **list;
_dbus_assert (dbus_connection_get_is_authenticated (connection));
i = 0;
while (i < n_groups)
{
+ DBusList **list;
+
list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
groups[i]);
if (!dbus_connection_get_unix_user (connection, &uid))
goto failed;
- list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
- uid);
+ if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
+ {
+ DBusList **list;
+
+ list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
+ uid);
+
+ if (list != NULL)
+ {
+ if (!add_list_to_client (list, client))
+ goto failed;
+ }
+ }
- if (!add_list_to_client (list, client))
- goto failed;
-
if (!add_list_to_client (&policy->mandatory_rules,
client))
goto failed;
{
DBusList *link;
dbus_bool_t allowed;
-
- /* FIXME there's currently no handling of wildcard user/group rules.
- */
allowed = def;
if (rule->type == BUS_POLICY_RULE_USER)
{
- if (rule->d.user.uid != uid)
+ _dbus_verbose ("List %p user rule uid="DBUS_UID_FORMAT"\n",
+ list, rule->d.user.uid);
+
+ if (rule->d.user.uid == DBUS_UID_UNSET)
+ ; /* '*' wildcard */
+ else if (rule->d.user.uid != uid)
continue;
}
else if (rule->type == BUS_POLICY_RULE_GROUP)
{
- int i;
-
- i = 0;
- while (i < n_group_ids)
+ _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n",
+ list, rule->d.user.uid);
+
+ if (rule->d.group.gid == DBUS_GID_UNSET)
+ ; /* '*' wildcard */
+ else
{
- if (rule->d.group.gid == group_ids[i])
- break;
- ++i;
+ int i;
+
+ i = 0;
+ while (i < n_group_ids)
+ {
+ if (rule->d.group.gid == group_ids[i])
+ break;
+ ++i;
+ }
+
+ if (i == n_group_ids)
+ continue;
}
-
- if (i == n_group_ids)
- continue;
}
else
continue;
int n_group_ids;
/* On OOM or error we always reject the user */
- if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
+ if (!_dbus_get_groups (uid, &group_ids, &n_group_ids, NULL))
{
_dbus_verbose ("Did not get any groups for UID %lu\n",
uid);
dbus_free (group_ids);
+ _dbus_verbose ("UID %lu allowed = %d\n", uid, allowed);
+
return allowed;
}
{
DBusList *link;
- link = _dbus_list_get_first (&policy->rules);
+ link = _dbus_list_get_first_link (&policy->rules);
while (link != up_to)
{
BusPolicyRule *rule = link->data;
DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
- bus_policy_rule_unref (rule);
- _dbus_list_remove_link (&policy->rules, link);
-
+ if (rule->type == type)
+ {
+ _dbus_list_remove_link (&policy->rules, link);
+ bus_policy_rule_unref (rule);
+ }
+
link = next;
}
}
_dbus_verbose ("Optimizing policy with %d rules\n",
_dbus_list_get_length (&policy->rules));
- link = _dbus_list_get_first (&policy->rules);
+ link = _dbus_list_get_first_link (&policy->rules);
while (link != NULL)
{
- BusPolicyRule *rule = link->data;
- DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
+ BusPolicyRule *rule;
+ DBusList *next;
dbus_bool_t remove_preceding;
+ next = _dbus_list_get_next_link (&policy->rules, link);
+ rule = link->data;
+
remove_preceding = FALSE;
+
+ _dbus_assert (rule != NULL);
switch (rule->type)
{
_dbus_assert_not_reached ("invalid rule");
break;
}
-
+
if (remove_preceding)
remove_rules_by_type_up_to (policy, rule->type,
link);
bus_client_policy_append_rule (BusClientPolicy *policy,
BusPolicyRule *rule)
{
+ _dbus_verbose ("Appending rule %p with type %d to policy %p\n",
+ rule, rule->type, policy);
+
if (!_dbus_list_append (&policy->rules, rule))
return FALSE;
*/
allowed = FALSE;
- link = _dbus_list_get_first (&policy->rules);
+ link = _dbus_list_get_first_link (&policy->rules);
while (link != NULL)
{
BusPolicyRule *rule = link->data;
*/
allowed = FALSE;
- link = _dbus_list_get_first (&policy->rules);
+ link = _dbus_list_get_first_link (&policy->rules);
while (link != NULL)
{
BusPolicyRule *rule = link->data;
*/
allowed = FALSE;
- link = _dbus_list_get_first (&policy->rules);
+ link = _dbus_list_get_first_link (&policy->rules);
while (link != NULL)
{
BusPolicyRule *rule = link->data;
struct
{
- char *user;
+ /* can be DBUS_UID_UNSET meaning "any" */
dbus_uid_t uid;
} user;
struct
{
- char *group;
+ /* can be DBUS_GID_UNSET meaning "any" */
dbus_gid_t gid;
} group;
<allow send="*"/>
<allow receive="*"/>
<allow own="*"/>
+ <allow user="*"/>
</policy>
<!-- This is included last so local configuration can override what's
<deny send="*"/>
<deny receive="*"/>
<deny own="*"/>
+ <!-- But allow all users to connect -->
+ <allow user="*"/>
</policy>
<!-- This is included last so local configuration can override what's
}
}
- _dbus_verbose (" done dispatching %p (%s)\n", message,
- dbus_message_get_name (message));
+ _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message,
+ dbus_message_get_name (message), connection);
out:
_dbus_connection_release_dispatch (connection);
typedef struct
{
+ int refcount;
CallbackType type;
void *data;
DBusFreeFunction free_data_func;
#define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
static WatchCallback*
-watch_callback_new (DBusWatch *watch,
+watch_callback_new (DBusWatch *watch,
DBusWatchFunction function,
- void *data,
- DBusFreeFunction free_data_func)
+ void *data,
+ DBusFreeFunction free_data_func)
{
WatchCallback *cb;
cb->watch = watch;
cb->function = function;
cb->last_iteration_oom = FALSE;
+ cb->callback.refcount = 1;
cb->callback.type = CALLBACK_WATCH;
cb->callback.data = data;
cb->callback.free_data_func = free_data_func;
-
+
return cb;
}
static TimeoutCallback*
-timeout_callback_new (DBusTimeout *timeout,
+timeout_callback_new (DBusTimeout *timeout,
DBusTimeoutFunction function,
- void *data,
- DBusFreeFunction free_data_func)
+ void *data,
+ DBusFreeFunction free_data_func)
{
TimeoutCallback *cb;
cb->function = function;
_dbus_get_current_time (&cb->last_tv_sec,
&cb->last_tv_usec);
+ cb->callback.refcount = 1;
cb->callback.type = CALLBACK_TIMEOUT;
cb->callback.data = data;
cb->callback.free_data_func = free_data_func;
}
static void
-callback_free (Callback *cb)
+callback_ref (Callback *cb)
+{
+ _dbus_assert (cb->refcount > 0);
+
+ cb->refcount += 1;
+}
+
+static void
+callback_unref (Callback *cb)
{
- if (cb->free_data_func)
- (* cb->free_data_func) (cb->data);
+ _dbus_assert (cb->refcount > 0);
+
+ cb->refcount -= 1;
- dbus_free (cb);
+ if (cb->refcount == 0)
+ {
+ if (cb->free_data_func)
+ (* cb->free_data_func) (cb->data);
+
+ dbus_free (cb);
+ }
}
static dbus_bool_t
break;
}
- callback_free (cb);
+ callback_unref (cb);
_dbus_list_remove_link (&loop->callbacks, link);
loop->callback_list_serial += 1;
}
if (!add_callback (loop, (Callback*) wcb))
{
wcb->callback.free_data_func = NULL; /* don't want to have this side effect */
- callback_free ((Callback*) wcb);
+ callback_unref ((Callback*) wcb);
return FALSE;
}
if (!add_callback (loop, (Callback*) tcb))
{
tcb->callback.free_data_func = NULL; /* don't want to have this side effect */
- callback_free ((Callback*) tcb);
+ callback_unref ((Callback*) tcb);
return FALSE;
}
fds = NULL;
watches_for_fds = NULL;
+ n_fds = 0;
oom_watch_pending = FALSE;
orig_depth = loop->depth;
else if (dbus_watch_get_enabled (wcb->watch))
{
watches_for_fds[i] = wcb;
+
+ callback_ref (cb);
flags = dbus_watch_get_flags (wcb->watch);
unsigned int condition;
wcb = watches_for_fds[i];
-
+
condition = 0;
if (fds[i].revents & _DBUS_POLLIN)
condition |= DBUS_WATCH_READABLE;
next_iteration:
if (fds && fds != static_fds)
dbus_free (fds);
- if (watches_for_fds && watches_for_fds != static_watches_for_fds)
- dbus_free (watches_for_fds);
+ if (watches_for_fds)
+ {
+ i = 0;
+ while (i < n_fds)
+ {
+ callback_unref (&watches_for_fds[i]->callback);
+ ++i;
+ }
+
+ if (watches_for_fds != static_watches_for_fds)
+ dbus_free (watches_for_fds);
+ }
if (_dbus_loop_dispatch (loop))
retval = TRUE;
*/
dbus_bool_t
dbus_message_set_reply_serial (DBusMessage *message,
- dbus_int32_t reply_serial)
+ dbus_int32_t reply_serial)
{
_dbus_assert (!message->locked);
store_user_info (struct passwd *p,
DBusCredentials *credentials,
DBusString *homedir,
- DBusString *username_out)
+ DBusString *username_out,
+ DBusError *error)
{
int old_homedir_len;
if (!_dbus_string_append (homedir, p->pw_dir))
{
- _dbus_verbose ("No memory to get homedir\n");
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
}
{
if (homedir)
_dbus_string_set_length (homedir, old_homedir_len);
- _dbus_verbose ("No memory to get username\n");
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
* @param credentials to fill in or #NULL
* @param homedir string to append homedir to or #NULL
* @param username_out string to append username to or #NULL
+ * @param error return location for reason for failure
*
* @returns #TRUE on success
*/
dbus_uid_t uid,
DBusCredentials *credentials,
DBusString *homedir,
- DBusString *username_out)
+ DBusString *username_out,
+ DBusError *error)
{
const char *username_c_str;
if (result == 0 && p == &p_str)
{
return store_user_info (p, credentials, homedir,
- username_out);
+ username_out, error);
}
else
{
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "User \"%s\" unknown or no memory to allocate password entry\n",
+ username_c_str);
_dbus_verbose ("User %s unknown\n", username_c_str);
return FALSE;
}
if (p != NULL)
{
return store_user_info (p, credentials, homedir,
- username_out);
+ username_out, error);
}
else
{
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "User \"%s\" unknown or no memory to allocate password entry\n",
+ username_c_str);
_dbus_verbose ("User %s unknown\n", username_c_str);
return FALSE;
}
_dbus_credentials_from_username (const DBusString *username,
DBusCredentials *credentials)
{
- return get_user_info (username, -1, credentials, NULL, NULL);
+ return get_user_info (username, -1, credentials, NULL, NULL, NULL);
}
/**
_dbus_credentials_from_user_id (unsigned long user_id,
DBusCredentials *credentials)
{
- return get_user_info (NULL, user_id, credentials, NULL, NULL);
+ return get_user_info (NULL, user_id, credentials, NULL, NULL, NULL);
}
_DBUS_DEFINE_GLOBAL_LOCK (user_info);
_dbus_credentials_clear (&u.creds);
if (!get_user_info (NULL, getuid (),
- &u.creds, &u.dir, &u.name))
+ &u.creds, &u.dir, &u.name, NULL))
goto fail_init;
if (!_dbus_register_shutdown_func (shutdown_user_info,
_dbus_homedir_from_username (const DBusString *username,
DBusString *homedir)
{
- return get_user_info (username, -1, NULL, homedir, NULL);
+ return get_user_info (username, -1, NULL, homedir, NULL, NULL);
}
/**
/**
* Gets all groups for a particular user. Returns #FALSE
* if no memory, or user isn't known, but always initializes
- * group_ids to a NULL array.
- *
- * @todo failing to distinguish "out of memory" from
- * "unknown user" is kind of bogus and would probably
- * result in a failure in a comprehensive test suite.
+ * group_ids to a NULL array. Sets error to the reason
+ * for returning #FALSE.
*
* @param uid the user ID
* @param group_ids return location for array of group IDs
* @param n_group_ids return location for length of returned array
+ * @param error return location for error
* @returns #TRUE on success
*/
dbus_bool_t
_dbus_get_groups (unsigned long uid,
unsigned long **group_ids,
- int *n_group_ids)
+ int *n_group_ids,
+ DBusError *error)
{
DBusCredentials creds;
DBusString username;
retval = FALSE;
if (!_dbus_string_init (&username))
- return FALSE;
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
if (!get_user_info (NULL, uid, &creds,
- NULL, &username) ||
+ NULL, &username, error) ||
creds.gid == DBUS_GID_UNSET)
goto out;
buf_count = 17;
buf = dbus_new (gid_t, buf_count);
if (buf == NULL)
- goto out;
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto out;
+ }
if (getgrouplist (username_c,
creds.gid,
gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
if (new == NULL)
{
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
dbus_free (buf);
goto out;
}
*group_ids = dbus_new (unsigned long, buf_count);
if (*group_ids == NULL)
{
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
dbus_free (buf);
goto out;
}
/* We just get the one group ID */
*group_ids = dbus_new (unsigned long, 1);
if (*group_ids == NULL)
- goto out;
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto out;
+ }
*n_group_ids = 1;
(*group_ids)[0] = creds.gid;
}
#endif /* HAVE_GETGROUPLIST */
+
+ retval = TRUE;
+
+ out:
+ _dbus_string_free (&username);
- retval = TRUE;
-
- out:
- _dbus_string_free (&username);
- return retval;
+ if (retval)
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ else
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+
+ return retval;
}
/**
dbus_gid_t *gid);
dbus_bool_t _dbus_get_groups (dbus_uid_t uid,
dbus_gid_t **group_ids,
- int *n_group_ids);
+ int *n_group_ids,
+ DBusError *error);
unsigned long _dbus_getpid (void);
unsigned int send_credentials_pending : 1; /**< #TRUE if we need to send credentials */
unsigned int receive_credentials_pending : 1; /**< #TRUE if we need to receive credentials */
unsigned int is_server : 1; /**< #TRUE if on the server side */
+ unsigned int unused_bytes_recovered : 1; /**< #TRUE if we've recovered unused bytes from auth */
};
dbus_bool_t _dbus_transport_init_base (DBusTransport *transport,
maybe_authenticated =
(!(transport->send_credentials_pending ||
- transport->receive_credentials_pending)) &&
- _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED;
+ transport->receive_credentials_pending));
+ if (maybe_authenticated)
+ {
+ switch (_dbus_auth_do_work (transport->auth))
+ {
+ case DBUS_AUTH_STATE_AUTHENTICATED:
+ case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
+ /* leave as maybe_authenticated */
+ break;
+ default:
+ maybe_authenticated = FALSE;
+ }
+ }
+
/* If we've authenticated as some identity, check that the auth
* identity is the same as our own identity. In the future, we
* may have API allowing applications to specify how this is
if (!_dbus_transport_get_is_authenticated (transport))
{
- switch (_dbus_auth_do_work (transport->auth))
- {
- case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
- return DBUS_DISPATCH_NEED_MEMORY;
- case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
- if (!recover_unused_bytes (transport))
- return DBUS_DISPATCH_NEED_MEMORY;
- break;
- default:
- break;
- }
+ if (_dbus_auth_do_work (transport->auth) ==
+ DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
+ return DBUS_DISPATCH_NEED_MEMORY;
+ else
+ return DBUS_DISPATCH_COMPLETE;
}
+
+ if (!transport->unused_bytes_recovered &&
+ !recover_unused_bytes (transport))
+ return DBUS_DISPATCH_NEED_MEMORY;
+
+ transport->unused_bytes_recovered = TRUE;
if (!_dbus_message_loader_queue_messages (transport->loader))
return DBUS_DISPATCH_NEED_MEMORY;
after the message bus has processed your message but before the service has replied,
it would be nice if the message bus sent you an error reply.
+ - We have a limit on the number of messages a connection can send, but
+ not on how many can be buffered for a given connection.
+
+ - make client serial and reply serial unsigned and add dbus_message_get_is_reply()
<allow send="*"/>
<allow receive="*"/>
<allow own="*"/>
+ <allow user="*"/>
</policy>
</busconfig>