#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>
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
+ BusCheck *check;
BusLimits limits;
DBusRLimit *initial_fd_limit;
unsigned int fork : 1;
{
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
/* 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 64k as a
- * good limit, like systemd does: that's enough to avoid DoS from
- * anything short of multiple uids conspiring against us.
+ * 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.
*/
- if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error))
+ if (!_dbus_rlimit_raise_fd_limit (&error))
{
bus_context_log (context, DBUS_SYSTEM_LOG_WARNING,
"%s: %s", error.name, error.message);
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))
!_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
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);
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)
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 */
* 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,
- BusActivationEntry *activation_entry,
- 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 *src, *dest;
BusClientPolicy *sender_policy;
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);
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 (dbus_error_is_set (&error2))
{
dbus_move_error (&error2, error);
- return FALSE;
+ return BUS_RESULT_FALSE;
}
}
}
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);
+ 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error, NULL);
_dbus_verbose ("SELinux security check denying send to service\n");
}
{
_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;
}
}
}
(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), error);
- _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
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 TRUE;
+ return BUS_RESULT_TRUE;
}
void
_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;
+}