BusConnections *connections;
BusActivation *activation;
BusRegistry *registry;
- DBusList *default_rules; /**< Default policy rules */
- DBusList *mandatory_rules; /**< Mandatory policy rules */
- DBusHashTable *rules_by_uid; /**< per-UID policy rules */
- DBusHashTable *rules_by_gid; /**< per-GID policy rules */
- int activation_timeout; /**< How long to wait for an activation to time out */
- int auth_timeout; /**< How long to wait for an authentication to time out */
- int max_completed_connections; /**< Max number of authorized connections */
- int max_incomplete_connections; /**< Max number of incomplete connections */
- int max_connections_per_user; /**< Max number of connections auth'd as same user */
+ BusPolicy *policy;
+ DBusUserDatabase *user_database;
+ BusLimits limits;
};
static int server_data_slot = -1;
unsigned int condition,
void *data)
{
- DBusServer *server = data;
-
- return dbus_server_handle_watch (server, watch, condition);
+ /* FIXME this can be done in dbus-mainloop.c
+ * if the code in activation.c for the babysitter
+ * watch handler is fixed.
+ */
+
+ return dbus_watch_handle (watch, condition);
}
static dbus_bool_t
*/
dbus_connection_disconnect (new_connection);
}
-
- /* on OOM, we won't have ref'd the connection so it will die. */
-}
-static void
-free_rule_func (void *data,
- void *user_data)
-{
- BusPolicyRule *rule = data;
+ dbus_connection_set_max_received_size (new_connection,
+ context->limits.max_incoming_bytes);
- bus_policy_rule_unref (rule);
-}
-
-static void
-free_rule_list_func (void *data)
-{
- DBusList **list = data;
-
- _dbus_list_foreach (list, free_rule_func, NULL);
+ dbus_connection_set_max_message_size (new_connection,
+ context->limits.max_message_size);
- _dbus_list_clear (list);
-
- dbus_free (list);
+ /* on OOM, we won't have ref'd the connection so it will die. */
}
static void
context->refcount = 1;
+ /* get our limits and timeout lengths */
+ bus_config_parser_get_limits (parser, &context->limits);
+
/* we need another ref of the server data slot for the context
* to own
*/
if (!server_data_slot_ref ())
_dbus_assert_not_reached ("second ref of server data slot failed");
-#ifdef DBUS_BUILD_TESTS
- context->activation_timeout = 6000; /* 6 seconds */
-#else
- context->activation_timeout = 15000; /* 15 seconds */
-#endif
-
- /* Making this long risks making a DOS attack easier, but too short
- * and legitimate auth will fail. If interactive auth (ask user for
- * password) is allowed, then potentially it has to be quite long.
- * Ultimately it needs to come from the configuration file.
- */
- context->auth_timeout = 3000; /* 3 seconds */
-
- context->max_incomplete_connections = 32;
- context->max_connections_per_user = 128;
-
- /* Note that max_completed_connections / max_connections_per_user
- * is the number of users that would have to work together to
- * DOS all the other users.
- */
- context->max_completed_connections = 1024;
+ context->user_database = _dbus_user_database_new ();
+ if (context->user_database == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
context->loop = _dbus_loop_new ();
if (context->loop == NULL)
BUS_SET_OOM (error);
goto failed;
}
-
- context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
- NULL,
- free_rule_list_func);
- if (context->rules_by_uid == NULL)
- {
- BUS_SET_OOM (error);
- goto failed;
- }
-
- context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
- NULL,
- free_rule_list_func);
- if (context->rules_by_gid == NULL)
- {
- BUS_SET_OOM (error);
- goto failed;
- }
+ context->policy = bus_config_parser_steal_policy (parser);
+ _dbus_assert (context->policy != NULL);
+
/* Now become a daemon if appropriate */
if (bus_config_parser_get_fork (parser))
{
}
_dbus_list_clear (&context->servers);
- if (context->rules_by_uid)
- {
- _dbus_hash_table_unref (context->rules_by_uid);
- context->rules_by_uid = NULL;
- }
-
- if (context->rules_by_gid)
+ if (context->policy)
{
- _dbus_hash_table_unref (context->rules_by_gid);
- context->rules_by_gid = NULL;
+ bus_policy_unref (context->policy);
+ context->policy = NULL;
}
-
+
if (context->loop)
{
_dbus_loop_unref (context->loop);
dbus_free (context->pidfile);
}
+ _dbus_user_database_unref (context->user_database);
+
dbus_free (context);
server_data_slot_unref ();
return context->loop;
}
-static dbus_bool_t
-list_allows_user (dbus_bool_t def,
- DBusList **list,
- unsigned long uid,
- const unsigned long *group_ids,
- int n_group_ids)
+DBusUserDatabase*
+bus_context_get_user_database (BusContext *context)
{
- DBusList *link;
- dbus_bool_t allowed;
-
- allowed = def;
-
- link = _dbus_list_get_first_link (list);
- while (link != NULL)
- {
- BusPolicyRule *rule = link->data;
- link = _dbus_list_get_next_link (list, link);
-
- if (rule->type == BUS_POLICY_RULE_USER)
- {
- if (rule->d.user.uid != uid)
- continue;
- }
- else if (rule->type == BUS_POLICY_RULE_GROUP)
- {
- 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;
- }
- else
- continue;
-
- allowed = rule->allow;
- }
-
- return allowed;
+ return context->user_database;
}
dbus_bool_t
bus_context_allow_user (BusContext *context,
unsigned long uid)
{
- dbus_bool_t allowed;
- unsigned long *group_ids;
- int n_group_ids;
-
- /* On OOM or error we always reject the user */
- if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
- {
- _dbus_verbose ("Did not get any groups for UID %lu\n",
- uid);
- return FALSE;
- }
-
- allowed = FALSE;
+ return bus_policy_allow_user (context->policy,
+ context->user_database,
+ uid);
+}
- allowed = list_allows_user (allowed,
- &context->default_rules,
- uid,
- group_ids, n_group_ids);
+BusClientPolicy*
+bus_context_create_client_policy (BusContext *context,
+ DBusConnection *connection,
+ DBusError *error)
+{
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ return bus_policy_create_client_policy (context->policy, connection,
+ error);
+}
- allowed = list_allows_user (allowed,
- &context->mandatory_rules,
- uid,
- group_ids, n_group_ids);
+int
+bus_context_get_activation_timeout (BusContext *context)
+{
+
+ return context->limits.activation_timeout;
+}
- dbus_free (group_ids);
+int
+bus_context_get_auth_timeout (BusContext *context)
+{
+ return context->limits.auth_timeout;
+}
- return allowed;
+int
+bus_context_get_max_completed_connections (BusContext *context)
+{
+ return context->limits.max_completed_connections;
}
-static dbus_bool_t
-add_list_to_policy (DBusList **list,
- BusPolicy *policy)
+int
+bus_context_get_max_incomplete_connections (BusContext *context)
{
- DBusList *link;
+ return context->limits.max_incomplete_connections;
+}
- link = _dbus_list_get_first_link (list);
- while (link != NULL)
- {
- BusPolicyRule *rule = link->data;
- link = _dbus_list_get_next_link (list, link);
+int
+bus_context_get_max_connections_per_user (BusContext *context)
+{
+ return context->limits.max_connections_per_user;
+}
- switch (rule->type)
- {
- case BUS_POLICY_RULE_USER:
- case BUS_POLICY_RULE_GROUP:
- /* These aren't per-connection policies */
- break;
-
- case BUS_POLICY_RULE_OWN:
- case BUS_POLICY_RULE_SEND:
- case BUS_POLICY_RULE_RECEIVE:
- /* These are per-connection */
- if (!bus_policy_append_rule (policy, rule))
- return FALSE;
- break;
- }
- }
-
- return TRUE;
+int
+bus_context_get_max_pending_activations (BusContext *context)
+{
+ return context->limits.max_pending_activations;
}
-BusPolicy*
-bus_context_create_connection_policy (BusContext *context,
- DBusConnection *connection)
+int
+bus_context_get_max_services_per_connection (BusContext *context)
{
- BusPolicy *policy;
- unsigned long uid;
- DBusList **list;
+ return context->limits.max_services_per_connection;
+}
- _dbus_assert (dbus_connection_get_is_authenticated (connection));
-
- policy = bus_policy_new ();
- if (policy == NULL)
- return NULL;
+dbus_bool_t
+bus_context_check_security_policy (BusContext *context,
+ DBusConnection *sender,
+ DBusConnection *recipient,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusClientPolicy *sender_policy;
+ BusClientPolicy *recipient_policy;
- if (!add_list_to_policy (&context->default_rules,
- policy))
- goto failed;
+ /* NULL sender/receiver means the bus driver */
- /* we avoid the overhead of looking up user's groups
- * if we don't have any group rules anyway
- */
- if (_dbus_hash_table_get_n_entries (context->rules_by_gid) > 0)
+ if (sender != NULL)
{
- const unsigned long *groups;
- int n_groups;
- int i;
-
- if (!bus_connection_get_groups (connection, &groups, &n_groups))
- goto failed;
-
- i = 0;
- while (i < n_groups)
+ if (bus_connection_is_active (sender))
{
- list = _dbus_hash_table_lookup_ulong (context->rules_by_gid,
- groups[i]);
-
- if (list != NULL)
+ sender_policy = bus_connection_get_policy (sender);
+ _dbus_assert (sender_policy != NULL);
+ }
+ else
+ {
+ /* Policy for inactive connections is that they can only send
+ * the hello message to the bus driver
+ */
+ if (recipient == NULL &&
+ dbus_message_has_name (message, DBUS_MESSAGE_HELLO))
{
- if (!add_list_to_policy (list, policy))
- goto failed;
+ _dbus_verbose ("security check allowing %s message\n",
+ DBUS_MESSAGE_HELLO);
+ return TRUE;
+ }
+ else
+ {
+ _dbus_verbose ("security check disallowing non-%s message\n",
+ DBUS_MESSAGE_HELLO);
+
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Client tried to send a message other than %s without being registered",
+ DBUS_MESSAGE_HELLO);
+
+ return FALSE;
}
-
- ++i;
}
}
+ else
+ sender_policy = NULL;
- if (!dbus_connection_get_unix_user (connection, &uid))
- goto failed;
-
- list = _dbus_hash_table_lookup_ulong (context->rules_by_uid,
- uid);
-
- if (!add_list_to_policy (list, policy))
- goto failed;
+ _dbus_assert ((sender != NULL && sender_policy != NULL) ||
+ (sender == NULL && sender_policy == NULL));
- if (!add_list_to_policy (&context->mandatory_rules,
- policy))
- goto failed;
+ if (recipient != NULL)
+ {
+ /* only the bus driver can send to an inactive recipient (as it
+ * owns no services, so other apps can't address it). Inactive
+ * recipients can receive any message.
+ */
+ if (bus_connection_is_active (recipient))
+ {
+ recipient_policy = bus_connection_get_policy (recipient);
+ _dbus_assert (recipient_policy != NULL);
+ }
+ else if (sender == NULL)
+ {
+ _dbus_verbose ("security check using NULL recipient policy for message from bus\n");
+ recipient_policy = NULL;
+ }
+ else
+ {
+ _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus\n");
+ recipient_policy = NULL;
+ }
+ }
+ else
+ recipient_policy = NULL;
+
+ _dbus_assert ((recipient != NULL && recipient_policy != NULL) ||
+ (recipient != NULL && sender == NULL && recipient_policy == NULL) ||
+ (recipient == NULL && recipient_policy == NULL));
+
+ if (sender_policy &&
+ !bus_client_policy_check_can_send (sender_policy,
+ context->registry, recipient,
+ message))
+ {
+ const char *dest = dbus_message_get_destination (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;
+ }
- bus_policy_optimize (policy);
-
- return policy;
-
- failed:
- bus_policy_unref (policy);
- return NULL;
-}
+ if (recipient_policy &&
+ !bus_client_policy_check_can_receive (recipient_policy,
+ context->registry, sender,
+ message))
+ {
+ const char *dest = dbus_message_get_destination (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;
+ }
-int
-bus_context_get_activation_timeout (BusContext *context)
-{
+ /* See if limits on size have been exceeded */
+ if (recipient &&
+ dbus_connection_get_outgoing_size (recipient) >
+ context->limits.max_outgoing_bytes)
+ {
+ const char *dest = dbus_message_get_destination (message);
+ dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+ "The destination service \"%s\" has a full message queue",
+ dest ? dest : DBUS_SERVICE_DBUS);
+ return FALSE;
+ }
- return context->activation_timeout;
+ return TRUE;
}