Commit 777707ed authored by Havoc Pennington's avatar Havoc Pennington

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
parent 8aabca8d
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
......
......@@ -582,8 +582,7 @@ bus_activation_service_created (BusActivation *activation,
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))
{
......@@ -592,7 +591,7 @@ bus_activation_service_created (BusActivation *activation,
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);
......@@ -654,14 +653,8 @@ try_send_activation_failure (BusPendingActivation *pending_activation,
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;
......@@ -861,8 +854,7 @@ bus_activation_activate_service (BusActivation *activation,
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))
{
......@@ -872,7 +864,7 @@ bus_activation_activate_service (BusActivation *activation,
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)
{
......
......@@ -796,3 +796,66 @@ bus_context_get_activation_timeout (BusContext *context)
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;
}
......@@ -57,6 +57,11 @@ dbus_bool_t bus_context_allow_user (BusContext *context,
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 */
......@@ -859,7 +859,7 @@ append_rule_from_element (BusConfigParser *parser,
if (rule == NULL)
goto nomem;
/* FIXME the wildcard needs storing in the rule somehow */
rule->d.user.uid = DBUS_UID_UNSET;
}
else
{
......@@ -873,10 +873,7 @@ append_rule_from_element (BusConfigParser *parser,
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
......@@ -894,7 +891,7 @@ append_rule_from_element (BusConfigParser *parser,
if (rule == NULL)
goto nomem;
/* FIXME the wildcard needs storing in the rule somehow */
rule->d.group.gid = DBUS_GID_UNSET;
}
else
{
......@@ -908,10 +905,7 @@ append_rule_from_element (BusConfigParser *parser,
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
......
......@@ -283,8 +283,6 @@ allow_user_function (DBusConnection *connection,
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);
}
......@@ -504,7 +502,7 @@ bus_connection_get_groups (DBusConnection *connection,
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);
......@@ -924,9 +922,34 @@ bus_transaction_get_connections (BusTransaction *transaction)
}
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;
......@@ -934,7 +957,7 @@ bus_transaction_send_message (BusTransaction *transaction,
_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) ?
......@@ -1152,8 +1175,7 @@ bus_transaction_send_error_reply (BusTransaction *transaction,
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;
......
......@@ -84,7 +84,10 @@ typedef void (* BusTransactionCancelFunction) (void *data);
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,
......
......@@ -37,6 +37,8 @@ static int message_handler_slot_refcount;
typedef struct
{
BusContext *context;
DBusConnection *sender;
DBusMessage *message;
BusTransaction *transaction;
DBusError *error;
......@@ -50,9 +52,16 @@ send_one_message (DBusConnection *connection, void *data)
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;
......@@ -63,6 +72,7 @@ send_one_message (DBusConnection *connection, void *data)
dbus_bool_t
bus_dispatch_broadcast_message (BusTransaction *transaction,
DBusConnection *sender,
DBusMessage *message,
DBusError *error)
{
......@@ -77,6 +87,8 @@ bus_dispatch_broadcast_message (BusTransaction *transaction,
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;
......@@ -92,70 +104,6 @@ bus_dispatch_broadcast_message (BusTransaction *transaction,
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)
......@@ -188,9 +136,10 @@ bus_dispatch (DBusConnection *connection,
_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)
{
......@@ -235,6 +184,10 @@ bus_dispatch (DBusConnection *connection,
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;
}
......@@ -249,7 +202,7 @@ bus_dispatch (DBusConnection *connection,
*/
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 */
......@@ -265,19 +218,25 @@ bus_dispatch (DBusConnection *connection,
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;
......@@ -316,7 +275,7 @@ bus_dispatch (DBusConnection *connection,
&error, message))
{
bus_connection_send_oom_error (connection, message);
/* cancel transaction due to OOM */
if (transaction != NULL)
{
......@@ -608,8 +567,9 @@ kill_client_connection_unchecked (DBusConnection *connection)
/* 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
......@@ -740,10 +700,12 @@ check_hello_message (BusContext *context,
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);
......@@ -760,15 +722,22 @@ check_hello_message (BusContext *context,
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)
......@@ -1390,7 +1359,10 @@ check_send_exit_to_service (BusContext *context,
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)
{
......@@ -1944,6 +1916,12 @@ bus_dispatch_test (const DBusString *test_data_dir)
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);
......
......@@ -30,6 +30,7 @@
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);
......
......@@ -67,7 +67,7 @@ bus_driver_send_service_deleted (const char *service_name,
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;
......@@ -107,7 +107,7 @@ bus_driver_send_service_created (const char *service_name,
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;
......@@ -131,13 +131,6 @@ bus_driver_send_service_lost (DBusConnection *connection,
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))
......@@ -147,7 +140,7 @@ bus_driver_send_service_lost (DBusConnection *connection,
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);
......@@ -178,13 +171,6 @@ bus_driver_send_service_acquired (DBusConnection *connection,
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))
......@@ -194,7 +180,7 @@ bus_driver_send_service_acquired (DBusConnection *connection,
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);
......@@ -347,13 +333,6 @@ bus_driver_send_welcome_message (DBusConnection *connection,
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))
......@@ -363,7 +342,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
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);
......@@ -417,7 +396,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
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);
......@@ -474,19 +453,13 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
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;
......@@ -534,12 +507,6 @@ bus_driver_handle_service_exists (DBusConnection *connection,
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,
......@@ -549,7 +516,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
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;
......@@ -653,6 +620,12 @@ bus_driver_handle_message (DBusConnection *connection,
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))
{
......
......@@ -73,7 +73,7 @@ bus_policy_rule_unref (BusPolicyRule *rule)
_dbus_assert (rule->refcount > 0);
rule->refcount -= 1;
if (rule->refcount == 0)
{
switch (rule->type)
......@@ -90,10 +90,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
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;
}
......@@ -239,7 +237,6 @@ bus_policy_create_client_policy (BusPolicy *policy,
{
BusClientPolicy *client;
unsigned long uid;
DBusList **list;
_dbus_assert (dbus_connection_get_is_authenticated (connection));
......@@ -266,6 +263,8 @@ bus_policy_create_client_policy (BusPolicy *policy,
i = 0;
while (i < n_groups)
<