#include "bus.h"
#include <stdio.h>
+#include <stdlib.h>
#include "activation.h"
#include "connection.h"
#include "config-parser.h"
#include "signals.h"
#include "selinux.h"
+#include "apparmor.h"
+#include "audit.h"
#include "dir-watch.h"
+#include "check.h"
+#include <dbus/dbus-auth.h>
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-credentials.h>
#include <dbus/dbus-internals.h>
+#include <dbus/dbus-server-protected.h>
#ifdef DBUS_CYGWIN
#include <signal.h>
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
+ BusCheck *check;
BusLimits limits;
+ DBusRLimit *initial_fd_limit;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
unsigned int allow_anonymous : 1;
unsigned int systemd_activation : 1;
+ dbus_bool_t watches_enabled;
};
static dbus_int32_t server_data_slot = -1;
BusContext *context;
BusServerData *bd;
- if (!dbus_server_allocate_data_slot (&server_data_slot))
- return NULL;
+ /* this data slot was allocated by the BusContext */
+ _dbus_assert (server_data_slot >= 0);
bd = BUS_SERVER_DATA (server);
- if (bd == NULL)
- {
- dbus_server_free_data_slot (&server_data_slot);
- return NULL;
- }
- context = bd->context;
+ /* every DBusServer in the dbus-daemon has gone through setup_server() */
+ _dbus_assert (bd != NULL);
- dbus_server_free_data_slot (&server_data_slot);
+ context = bd->context;
return context;
}
{
BusContext *context = data;
+ /* If this fails it logs a warning, so we don't need to do that */
if (!bus_connections_setup_connection (context->connections, new_connection))
{
- _dbus_verbose ("No memory to setup new connection\n");
-
/* if we don't do this, it will get unref'd without
* being disconnected... kind of strange really
* that we have to do this, people won't get it right
DBusList **auth_mechanisms_list;
int len;
dbus_bool_t retval;
+ DBusLogFlags log_flags = DBUS_LOG_FLAGS_STDERR;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
auth_mechanisms = NULL;
pidfile = NULL;
- _dbus_init_system_log (TRUE);
+ if (flags & BUS_CONTEXT_FLAG_SYSLOG_ALWAYS)
+ {
+ context->syslog = TRUE;
+ log_flags |= DBUS_LOG_FLAGS_SYSTEM_LOG;
+
+ if (flags & BUS_CONTEXT_FLAG_SYSLOG_ONLY)
+ log_flags &= ~DBUS_LOG_FLAGS_STDERR;
+ }
+ else if (flags & BUS_CONTEXT_FLAG_SYSLOG_NEVER)
+ {
+ context->syslog = FALSE;
+ }
+ else
+ {
+ context->syslog = bus_config_parser_get_syslog (parser);
+
+ if (context->syslog)
+ log_flags |= DBUS_LOG_FLAGS_SYSTEM_LOG;
+ }
+
+ _dbus_init_system_log ("dbus-daemon", log_flags);
if (flags & BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION)
context->systemd_activation = TRUE;
link = _dbus_list_get_first_link (auth_mechanisms_list);
while (link != NULL)
{
+ DBusString name;
+ _dbus_string_init_const (&name, link->data);
+ if (!_dbus_auth_is_supported_mechanism (&name))
+ {
+ DBusString list;
+ if (!_dbus_string_init (&list))
+ goto oom;
+
+ if (!_dbus_auth_dump_supported_mechanisms (&list))
+ {
+ _dbus_string_free (&list);
+ goto oom;
+ }
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Unsupported auth mechanism \"%s\" in bus config file detected. Supported mechanisms are \"%s\".",
+ (char*)link->data,
+ _dbus_string_get_const_data (&list));
+ _dbus_string_free (&list);
+ goto failed;
+ }
auth_mechanisms[i] = _dbus_strdup (link->data);
if (auth_mechanisms[i] == NULL)
goto oom;
}
context->fork = bus_config_parser_get_fork (parser);
- context->syslog = bus_config_parser_get_syslog (parser);
context->keep_umask = bus_config_parser_get_keep_umask (parser);
context->allow_anonymous = bus_config_parser_get_allow_anonymous (parser);
return retval;
}
-static dbus_bool_t
-list_concat_new (DBusList **a,
- DBusList **b,
- DBusList **result)
+static void
+raise_file_descriptor_limit (BusContext *context)
{
- DBusList *link;
+#ifdef DBUS_UNIX
+ DBusError error = DBUS_ERROR_INIT;
- *result = NULL;
+ /* we only do this once */
+ if (context->initial_fd_limit != NULL)
+ return;
- for (link = _dbus_list_get_first_link (a); link; link = _dbus_list_get_next_link (a, link))
- {
- if (!_dbus_list_append (result, link->data))
- goto oom;
- }
- for (link = _dbus_list_get_first_link (b); link; link = _dbus_list_get_next_link (b, link))
+ context->initial_fd_limit = _dbus_rlimit_save_fd_limit (&error);
+
+ if (context->initial_fd_limit == NULL)
{
- if (!_dbus_list_append (result, link->data))
- goto oom;
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "%s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ return;
}
- return TRUE;
-oom:
- _dbus_list_clear (result);
- return FALSE;
-}
-
-static void
-raise_file_descriptor_limit (BusContext *context)
-{
-
- /* I just picked this out of thin air; we need some extra
- * descriptors for things like any internal pipes we create,
- * inotify, connections to SELinux, etc.
+ /* We used to compute a suitable rlimit based on the configured number
+ * of connections, but that breaks down as soon as we allow fd-passing,
+ * because each connection is allowed to pass 64 fds to us, and if
+ * they all did, we'd hit kernel limits. We now hard-code a good
+ * limit that is enough to avoid DoS from anything short of multiple
+ * uids conspiring against us, much like systemd does.
*/
- unsigned int arbitrary_extra_fds = 32;
- unsigned int limit;
-
- limit = context->limits.max_completed_connections +
- context->limits.max_incomplete_connections
- + arbitrary_extra_fds;
-
- _dbus_request_file_descriptor_limit (limit);
+ if (!_dbus_rlimit_raise_fd_limit (&error))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
+ "%s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ return;
+ }
+#endif
}
static dbus_bool_t
DBusHashTable *service_context_table;
DBusList *watched_dirs = NULL;
- raise_file_descriptor_limit (context);
-
service_context_table = bus_config_parser_steal_service_context_table (parser);
if (!bus_registry_set_service_context_table (context->registry,
service_context_table))
/* We need to monitor both the configuration directories and directories
* containing .service files.
*/
- if (!list_concat_new (bus_config_parser_get_conf_dirs (parser),
- bus_config_parser_get_service_dirs (parser),
- &watched_dirs))
+ if (!bus_config_parser_get_watched_dirs (parser, &watched_dirs))
{
BUS_SET_OOM (error);
return FALSE;
}
context->refcount = 1;
- _dbus_generate_uuid (&context->uuid);
+ if (!_dbus_generate_uuid (&context->uuid, error))
+ goto failed;
if (!_dbus_string_copy_data (config_file, &context->config_file))
{
goto failed;
}
+ context->watches_enabled = TRUE;
+
context->registry = bus_registry_new (context);
if (context->registry == NULL)
{
!_dbus_pipe_is_stdout_or_stderr (print_pid_pipe))
_dbus_pipe_close (print_pid_pipe, NULL);
+ /* Raise the file descriptor limits before dropping the privileges
+ * required to do so.
+ */
+ raise_file_descriptor_limit (context);
+
+ /* Here we change our credentials if required,
+ * as soon as we've set up our sockets and pidfile.
+ * This must be done before initializing LSMs, so that the netlink
+ * monitoring thread started by avc_init() will not lose CAP_AUDIT_WRITE
+ * when the main thread calls setuid().
+ * https://bugs.freedesktop.org/show_bug.cgi?id=92832
+ */
+ if (context->user != NULL)
+ {
+ if (!_dbus_change_to_daemon_user (context->user, error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
+ }
+
+ /* Auditing should be initialized before LSMs, so that the LSMs are able
+ * to log audit-events that happen during their initialization.
+ */
+ bus_audit_init (context);
+
if (!bus_selinux_full_init ())
{
- bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but D-Bus initialization failed; check system log\n");
+ bus_context_log (context, DBUS_SYSTEM_LOG_ERROR,
+ "SELinux enabled but D-Bus initialization failed; "
+ "check system log");
+ exit (1);
}
- if (!process_config_postinit (context, parser, error))
+ if (!bus_apparmor_full_init (error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed;
}
- if (parser != NULL)
+ if (bus_apparmor_enabled ())
{
- bus_config_parser_unref (parser);
- parser = NULL;
+ /* Only print AppArmor mediation message when syslog support is enabled */
+ if (context->syslog)
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "AppArmor D-Bus mediation is enabled\n");
}
- /* Here we change our credentials if required,
- * as soon as we've set up our sockets and pidfile
+ /* When SELinux is used, this must happen after bus_selinux_full_init()
+ * so that it has access to the access vector cache, which is required
+ * to process <associate/> elements.
+ * http://lists.freedesktop.org/archives/dbus/2008-October/010491.html
*/
- if (context->user != NULL)
+ if (!process_config_postinit (context, parser, error))
{
- if (!_dbus_change_to_daemon_user (context->user, error))
- {
- _DBUS_ASSERT_ERROR_IS_SET (error);
- goto failed;
- }
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
-#ifdef HAVE_SELINUX
- /* FIXME - why not just put this in full_init() below? */
- bus_selinux_audit_init ();
-#endif
+ if (parser != NULL)
+ {
+ bus_config_parser_unref (parser);
+ parser = NULL;
}
+ context->check = bus_check_new(context, error);
+ if (context->check == NULL)
+ goto failed;
+
dbus_server_free_data_slot (&server_data_slot);
return context;
bus_context_shutdown (context);
+ if (context->check)
+ {
+ bus_check_unref(context->check);
+ context->check = NULL;
+ }
+
if (context->connections)
{
bus_connections_unref (context->connections);
dbus_free (context->pidfile);
}
+
+ if (context->initial_fd_limit)
+ _dbus_rlimit_free (context->initial_fd_limit);
+
dbus_free (context);
dbus_server_free_data_slot (&server_data_slot);
return context->loop;
}
+BusCheck*
+bus_context_get_check (BusContext *context)
+{
+ return context->check;
+}
+
dbus_bool_t
bus_context_allow_unix_user (BusContext *context,
unsigned long uid)
}
int
+bus_context_get_pending_fd_timeout (BusContext *context)
+{
+ return context->limits.pending_fd_timeout;
+}
+
+int
bus_context_get_max_completed_connections (BusContext *context)
{
return context->limits.max_completed_connections;
return context->limits.reply_timeout;
}
-void
-bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (3, 4);
+DBusRLimit *
+bus_context_get_initial_fd_limit (BusContext *context)
+{
+ return context->initial_fd_limit;
+}
+
+dbus_bool_t
+bus_context_get_using_syslog (BusContext *context)
+{
+ return context->syslog;
+}
void
bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...)
{
va_list args;
- if (!context->syslog)
- {
- /* we're not syslogging; just output to stderr */
- va_start (args, msg);
- vfprintf (stderr, msg, args);
- fprintf (stderr, "\n");
- va_end (args);
- return;
- }
-
va_start (args, msg);
if (context->log_prefix)
if (!_dbus_string_append_printf_valist (&full_msg, msg, args))
goto oom_out;
- _dbus_system_log (severity, "%s", _dbus_string_get_const_data (&full_msg));
+ _dbus_log (severity, "%s", _dbus_string_get_const_data (&full_msg));
oom_out:
_dbus_string_free (&full_msg);
}
else
- _dbus_system_logv (severity, msg, args);
+ _dbus_logv (severity, msg, args);
out:
va_end (args);
return (maybe_null ? maybe_null : if_null);
}
+void
+bus_context_log_literal (BusContext *context,
+ DBusSystemLogSeverity severity,
+ const char *msg)
+{
+ _dbus_log (severity, "%s%s", nonnull (context->log_prefix, ""), msg);
+}
+
+void
+bus_context_log_and_set_error (BusContext *context,
+ DBusSystemLogSeverity severity,
+ DBusError *error,
+ const char *name,
+ const char *msg,
+ ...)
+{
+ DBusError stack_error = DBUS_ERROR_INIT;
+ va_list args;
+
+ va_start (args, msg);
+ _dbus_set_error_valist (&stack_error, name, msg, args);
+ va_end (args);
+
+ /* If we hit OOM while setting the error, this will syslog "out of memory"
+ * which is itself an indication that something is seriously wrong */
+ bus_context_log_literal (context, DBUS_SYSTEM_LOG_SECURITY,
+ stack_error.message);
+
+ dbus_move_error (&stack_error, error);
+}
+
/*
* Log something about a message, usually that it was rejected.
*/
DBusConnection *proposed_recipient,
dbus_bool_t requested_reply,
dbus_bool_t log,
- DBusError *error)
+ const char *privilege,
+ DBusError *error,
+ const char *rule)
{
DBusError stack_error = DBUS_ERROR_INIT;
const char *sender_name;
dbus_set_error (&stack_error, error_name,
"%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
"interface=\"%s\" member=\"%s\" error name=\"%s\" "
- "requested_reply=\"%d\" destination=\"%s\" (%s)",
+ "requested_reply=\"%d\" destination=\"%s\" "
+ "privilege=\"%s\" (%s) "
+ "rule(%s)",
complaint,
matched_rules,
dbus_message_type_to_string (dbus_message_get_type (message)),
nonnull (dbus_message_get_error_name (message), "(unset)"),
requested_reply,
nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
- proposed_recipient_loginfo);
+ nonnull (privilege, "(n/a)"),
+ proposed_recipient_loginfo,
+ rule);
/* If we hit OOM while setting the error, this will syslog "out of memory"
* which is itself an indication that something is seriously wrong */
if (log)
- bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, "%s",
+ bus_context_log_literal (context, DBUS_SYSTEM_LOG_SECURITY,
stack_error.message);
dbus_move_error (&stack_error, error);
*
* sender is the sender of the message.
*
- * NULL for proposed_recipient or sender definitely means the bus driver.
+ * NULL for sender definitely means the bus driver.
+ *
+ * NULL for proposed_recipient may mean the bus driver, or may mean
+ * we are checking whether service-activation is allowed as a first
+ * pass before all details of the activated service are known.
*
* NULL for addressed_recipient may mean the bus driver, or may mean
* no destination was specified in the message (e.g. a signal).
*/
-dbus_bool_t
-bus_context_check_security_policy (BusContext *context,
- BusTransaction *transaction,
- DBusConnection *sender,
- DBusConnection *addressed_recipient,
- DBusConnection *proposed_recipient,
- DBusMessage *message,
- DBusError *error)
+BusResult
+bus_context_check_security_policy (BusContext *context,
+ BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ DBusMessage *message,
+ BusActivationEntry *activation_entry,
+ DBusError *error,
+ BusDeferredMessage **deferred_message)
{
- const char *dest;
+ const char *src, *dest;
BusClientPolicy *sender_policy;
BusClientPolicy *recipient_policy;
dbus_int32_t toggles;
dbus_bool_t log;
int type;
dbus_bool_t requested_reply;
+ const char *privilege;
+ char *out_rule = NULL;
+ BusResult can_send_result = BUS_RESULT_TRUE;
type = dbus_message_get_type (message);
+ src = dbus_message_get_sender (message);
dest = dbus_message_get_destination (message);
/* dispatch.c was supposed to ensure these invariants */
(sender == NULL && !bus_connection_is_active (proposed_recipient)));
_dbus_assert (type == DBUS_MESSAGE_TYPE_SIGNAL ||
addressed_recipient != NULL ||
+ activation_entry != NULL ||
strcmp (dest, DBUS_SERVICE_DBUS) == 0);
switch (type)
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"Message bus will not accept messages of unknown type\n");
- return FALSE;
+ return BUS_RESULT_FALSE;
}
requested_reply = FALSE;
if (sender != NULL)
{
- /* First verify the SELinux access controls. If allowed then
- * go on with the standard checks.
- */
- if (!bus_selinux_allows_send (sender, proposed_recipient,
- dbus_message_type_to_string (dbus_message_get_type (message)),
- dbus_message_get_interface (message),
- dbus_message_get_member (message),
- dbus_message_get_error_name (message),
- dest ? dest : DBUS_SERVICE_DBUS, error))
- {
- if (error != NULL && !dbus_error_is_set (error))
- {
- /* don't syslog this, just set the error: avc_has_perm should
- * have already written to either the audit log or syslog */
- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
- "An SELinux policy prevents this sender from sending this "
- "message to this recipient",
- 0, message, sender, proposed_recipient, FALSE, FALSE, error);
- _dbus_verbose ("SELinux security check denying send to service\n");
- }
-
- return FALSE;
- }
-
if (bus_connection_is_active (sender))
{
sender_policy = bus_connection_get_policy (sender);
if (dbus_error_is_set (&error2))
{
dbus_move_error (&error2, error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
}
}
}
else
{
+ sender_policy = NULL;
+ }
+
+ /* First verify the SELinux access controls. If allowed then
+ * go on with the standard checks.
+ */
+ if (!bus_selinux_allows_send (sender, proposed_recipient,
+ dbus_message_type_to_string (dbus_message_get_type (message)),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS,
+ activation_entry,
+ error))
+ {
+ if (error != NULL && !dbus_error_is_set (error))
+ {
+ /* don't syslog this, just set the error: avc_has_perm should
+ * have already written to either the audit log or syslog */
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "An SELinux policy prevents this sender from sending this "
+ "message to this recipient",
+ 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error, NULL);
+ _dbus_verbose ("SELinux security check denying send to service\n");
+ }
+
+ return FALSE;
+ }
+
+ /* next verify AppArmor access controls. If allowed then
+ * go on with the standard checks.
+ */
+ if (!bus_apparmor_allows_send (sender, proposed_recipient,
+ requested_reply,
+ bus_context_get_type (context),
+ dbus_message_get_type (message),
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS,
+ src ? src : DBUS_SERVICE_DBUS,
+ activation_entry,
+ error))
+ return FALSE;
+
+ if (!bus_connection_is_active (sender))
+ {
/* Policy for inactive connections is that they can only send
* the hello message to the bus driver
*/
{
_dbus_verbose ("security check allowing %s message\n",
"Hello");
- return TRUE;
+ return BUS_RESULT_TRUE;
}
else
{
"Client tried to send a message other than %s without being registered",
"Hello");
- return FALSE;
+ return BUS_RESULT_FALSE;
}
}
}
}
else
{
- _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus\n");
+ _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus");
recipient_policy = NULL;
}
}
(proposed_recipient == NULL && recipient_policy == NULL));
log = FALSE;
- if (sender_policy &&
- !bus_client_policy_check_can_send (sender_policy,
- context->registry,
- requested_reply,
- proposed_recipient,
- message, &toggles, &log))
- {
- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
- "Rejected send message", toggles,
- message, sender, proposed_recipient, requested_reply,
- (addressed_recipient == proposed_recipient), error);
- _dbus_verbose ("security policy disallowing message due to sender policy\n");
- return FALSE;
- }
+ if (sender_policy) {
+ can_send_result = bus_client_policy_check_can_send (sender,
+ sender_policy,
+ context->registry,
+ requested_reply,
+ addressed_recipient,
+ proposed_recipient,
+ message, &toggles, &log, &privilege,
+ deferred_message, &out_rule);
+ if (can_send_result == BUS_RESULT_FALSE)
+ {
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "Rejected send message", toggles,
+ message, sender, proposed_recipient, requested_reply,
+ (addressed_recipient == proposed_recipient) || (type == DBUS_MESSAGE_TYPE_SIGNAL),
+ privilege,
+ error, out_rule);
+ _dbus_verbose ("security policy disallowing message due to sender policy\n");
+ if (out_rule)
+ free (out_rule);
+ return BUS_RESULT_FALSE;
+ }
+ }
if (log)
{
complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
"Would reject message", toggles,
message, sender, proposed_recipient, requested_reply,
- TRUE, NULL);
+ TRUE, privilege, NULL, NULL);
}
- if (recipient_policy &&
- !bus_client_policy_check_can_receive (recipient_policy,
- context->registry,
- requested_reply,
- sender,
- addressed_recipient, proposed_recipient,
- message, &toggles))
- {
- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
- "Rejected receive message", toggles,
- message, sender, proposed_recipient, requested_reply,
- (addressed_recipient == proposed_recipient), NULL);
- _dbus_verbose ("security policy disallowing message due to recipient policy\n");
- return FALSE;
- }
+ if (recipient_policy) {
+ switch (bus_client_policy_check_can_receive (recipient_policy,
+ context->registry,
+ requested_reply,
+ sender,
+ addressed_recipient, proposed_recipient,
+ message, &toggles, &privilege, deferred_message, &out_rule))
+ {
+ case BUS_RESULT_TRUE:
+ break;
+ case BUS_RESULT_FALSE:
+ complain_about_message(context, DBUS_ERROR_ACCESS_DENIED,
+ "Rejected receive message", toggles, message, sender,
+ proposed_recipient, requested_reply,
+ (addressed_recipient == proposed_recipient) || (type == DBUS_MESSAGE_TYPE_SIGNAL),
+ privilege, error, out_rule);
+ _dbus_verbose(
+ "security policy disallowing message due to recipient policy\n");
+ if (out_rule)
+ free (out_rule);
+ if (deferred_message && *deferred_message)
+ bus_deferred_message_set_response (*deferred_message, BUS_RESULT_FALSE);
+ return BUS_RESULT_FALSE;
+ case BUS_RESULT_LATER:
+ return BUS_RESULT_LATER;
+ }
+ }
+
+ if (can_send_result == BUS_RESULT_LATER)
+ return BUS_RESULT_LATER;
/* See if limits on size have been exceeded */
- if (proposed_recipient &&
- ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
- (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
- {
- complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
- "Rejected: destination has a full message queue",
- 0, message, sender, proposed_recipient, requested_reply, TRUE,
- error);
- _dbus_verbose ("security policy disallowing message due to full message queue\n");
- return FALSE;
- }
+ if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
+ requested_reply, error))
+ return BUS_RESULT_FALSE;
/* Record that we will allow a reply here in the future (don't
* bother if the recipient is the bus or this is an eavesdropping
* connection). Only the addressed recipient may reply.
+ *
+ * This isn't done for activation attempts because they have no addressed
+ * or proposed recipient; when we check whether to actually deliver the
+ * message, later, we'll record the reply expectation at that point.
*/
if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
sender &&
message, error))
{
_dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
- return FALSE;
+ return BUS_RESULT_FALSE;
}
_dbus_verbose ("security policy allowing message\n");
+ return BUS_RESULT_TRUE;
+}
+
+void
+bus_context_check_all_watches (BusContext *context)
+{
+ DBusList *link;
+ dbus_bool_t enabled = TRUE;
+
+ if (bus_connections_get_n_incomplete (context->connections) >=
+ bus_context_get_max_incomplete_connections (context))
+ {
+ enabled = FALSE;
+ }
+
+ if (context->watches_enabled == enabled)
+ return;
+
+ context->watches_enabled = enabled;
+
+ for (link = _dbus_list_get_first_link (&context->servers);
+ link != NULL;
+ link = _dbus_list_get_next_link (&context->servers, link))
+ {
+ /* A BusContext might contains several DBusServer (if there are
+ * several <listen> configuration items) and a DBusServer might
+ * contain several DBusWatch in its DBusWatchList (if getaddrinfo
+ * returns several addresses on a dual IPv4-IPv6 stack or if
+ * systemd passes several fds).
+ * We want to enable/disable them all.
+ */
+ DBusServer *server = link->data;
+ _dbus_server_toggle_all_watches (server, enabled);
+ }
+}
+
+void
+bus_context_complain_about_message (BusContext *context,
+ const char *error_name,
+ const char *complaint,
+ int matched_rules,
+ DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ dbus_bool_t log,
+ const char *privilege,
+ DBusError *error)
+{
+ complain_about_message(context, error_name, complaint, matched_rules, message, sender,
+ proposed_recipient, requested_reply, log, privilege, error, NULL);
+}
+
+dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
+ DBusConnection *recipient,
+ DBusConnection *sender,
+ DBusMessage *message,
+ dbus_bool_t requested_reply,
+ DBusError *error)
+
+{
+ if (recipient &&
+ ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
+ (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
+ {
+ complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
+ "Rejected: destination has a full message queue",
+ 0, message, sender, recipient, requested_reply, TRUE, NULL,
+ error, NULL);
+ _dbus_verbose ("security policy disallowing message due to full message queue\n");
+ return FALSE;
+ }
return TRUE;
}