#ifdef DBUS_ENABLE_CYNARA
#include <stdlib.h>
#include <cynara-session.h>
+#include <stdio.h>
#endif
/* Trim executed commands to this length; we want to keep logs readable */
#ifdef DBUS_ENABLE_STATS
int peak_match_rules;
int peak_bus_names;
+ int peak_pending_replies;
#endif
int n_pending_unix_fds;
DBusTimeout *pending_unix_fds_timeout;
if (d->policy)
bus_client_policy_unref (d->policy);
- if (d->selinux_id)
- bus_selinux_id_unref (d->selinux_id);
-
if (d->apparmor_confinement)
bus_apparmor_confinement_unref (d->apparmor_confinement);
}
}
+static dbus_bool_t
+is_context_type_session (BusConnectionData *d)
+{
+ const char *context_type = bus_context_get_type (d->connections->context);
+ return context_type && !strcmp (context_type, "session");
+}
+
/* Used for logging */
static dbus_bool_t
cache_peer_loginfo_string (BusConnectionData *d,
DBusString loginfo_buf;
unsigned long uid;
unsigned long pid;
- char *windows_sid;
+ char *windows_sid = NULL, *security_label = NULL;
dbus_bool_t prev_added;
if (!_dbus_string_init (&loginfo_buf))
if (!_dbus_string_append_printf (&loginfo_buf, "pid=%ld comm=\"", pid))
goto oom;
/* Ignore errors here; we may not have permissions to read the
- * proc file. */
- //_dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL);
+ * proc file.
+ * Don't even try it for the session daemon, to avoid cluttering logs with security error logs for
+ * accessing the proc file.
+ */
+ if (!is_context_type_session(d))
+ {
+ _dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL);
+ }
+ else
+ {
+ if (!_dbus_string_append (&loginfo_buf, "<not-read>")) /* for session daemon just say that we didn't try */
+ goto oom;
+ }
if (!_dbus_string_append_byte (&loginfo_buf, '"'))
goto oom;
+ else
+ prev_added = TRUE;
}
if (dbus_connection_get_windows_user (connection, &windows_sid))
{
dbus_bool_t did_append;
+
+ if (prev_added)
+ {
+ if (!_dbus_string_append_byte (&loginfo_buf, ' '))
+ goto oom;
+ }
+
did_append = _dbus_string_append_printf (&loginfo_buf,
- "sid=\"%s\" ", windows_sid);
+ "sid=\"%s\"", windows_sid);
dbus_free (windows_sid);
+ windows_sid = NULL;
if (!did_append)
goto oom;
+ else
+ prev_added = TRUE;
+ }
+
+ if (_dbus_connection_get_linux_security_label (connection, &security_label))
+ {
+ dbus_bool_t did_append;
+
+ if (prev_added)
+ {
+ if (!_dbus_string_append_byte (&loginfo_buf, ' '))
+ goto oom;
+ }
+
+ did_append = _dbus_string_append_printf (&loginfo_buf,
+ "label=\"%s\"", security_label);
+ dbus_free (security_label);
+ security_label = NULL;
+ if (!did_append)
+ goto oom;
+ else
+ prev_added = TRUE;
}
if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string)))
return TRUE;
oom:
_dbus_string_free (&loginfo_buf);
+ if (security_label != NULL)
+ dbus_free (security_label);
+ if (windows_sid != NULL)
+ dbus_free (windows_sid);
+
return FALSE;
}
pending_unix_fds_timeout_cb (void *data)
{
DBusConnection *connection = data;
+ BusConnectionData *d = BUS_CONNECTION_DATA (connection);
+ int limit;
+
+ _dbus_assert (d != NULL);
+ limit = bus_context_get_pending_fd_timeout (d->connections->context);
+ bus_context_log (d->connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "Connection \"%s\" (%s) has had Unix fds pending for too long, "
+ "closing it (pending_fd_timeout=%d ms)",
+ d->name != NULL ? d->name : "(null)",
+ bus_connection_get_loginfo (connection),
+ limit);
+
dbus_connection_close (connection);
return TRUE;
}
DBusConnection *connection)
{
- BusConnectionData *d;
- dbus_bool_t retval;
+ BusConnectionData *d = NULL;
DBusError error;
-
d = dbus_new0 (BusConnectionData, 1);
if (d == NULL)
- return FALSE;
+ goto oom;
d->connections = connections;
d->connection = connection;
connection_data_slot,
d, free_connection_data))
{
+ /* We have to free d explicitly, because this is the only code
+ * path where it's non-NULL but dbus_connection_set_data() hasn't
+ * taken responsibility for freeing it. */
dbus_free (d);
- return FALSE;
+ d = NULL;
+ goto oom;
}
dbus_connection_set_route_peer_messages (connection, TRUE);
-
- retval = FALSE;
dbus_error_init (&error);
d->selinux_id = bus_selinux_init_connection_id (connection,
&error);
if (dbus_error_is_set (&error))
{
- /* This is a bit bogus because we pretend all errors
- * are OOM; this is done because we know that in bus.c
- * an OOM error disconnects the connection, which is
- * the same thing we want on any other error.
- */
+ bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "Unable to set up new connection: %s", error.message);
dbus_error_free (&error);
- goto out;
+ goto error;
}
d->apparmor_confinement = bus_apparmor_init_connection_confinement (connection,
&error);
if (dbus_error_is_set (&error))
{
- /* This is a bit bogus because we pretend all errors
- * are OOM; this is done because we know that in bus.c
- * an OOM error disconnects the connection, which is
- * the same thing we want on any other error.
- */
+ bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "Unable to set up new connection: %s", error.message);
dbus_error_free (&error);
- goto out;
+ goto error;
}
if (!dbus_connection_set_watch_functions (connection,
toggle_connection_watch,
connection,
NULL))
- goto out;
+ goto oom;
if (!dbus_connection_set_timeout_functions (connection,
add_connection_timeout,
remove_connection_timeout,
NULL,
connection, NULL))
- goto out;
+ goto oom;
/* For now we don't need to set a Windows user function because
* there are no policies in the config file controlling what
d->link_in_connection_list = _dbus_list_alloc_link (connection);
if (d->link_in_connection_list == NULL)
- goto out;
+ goto oom;
/* Setup the connection with the dispatcher */
if (!bus_dispatch_add_connection (connection))
- goto out;
+ goto oom;
if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
{
if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
{
bus_dispatch_remove_connection (connection);
- goto out;
+ goto oom;
}
}
pending_unix_fds_timeout_cb,
connection, NULL);
if (d->pending_unix_fds_timeout == NULL)
- goto out;
+ goto oom;
_dbus_timeout_disable (d->pending_unix_fds_timeout);
if (!_dbus_loop_add_timeout (bus_context_get_loop (connections->context),
d->pending_unix_fds_timeout))
- goto out;
+ goto oom;
_dbus_connection_set_pending_fds_function (connection,
(DBusPendingFdsChangeFunction) check_pending_fds_cb,
* stop accept()ing any more, to avert a DoS. See fd.o #80919 */
bus_context_check_all_watches (d->connections->context);
- retval = TRUE;
+ return TRUE;
- out:
- if (!retval)
+oom:
+ bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "No memory to set up new connection");
+ /* fall through */
+error:
+ if (d != NULL)
{
- if (d->selinux_id)
- bus_selinux_id_unref (d->selinux_id);
d->selinux_id = NULL;
if (d->apparmor_confinement)
/* "d" has now been freed */
}
- return retval;
+ return FALSE;
}
void
unsigned long pid;
if (dbus_connection_get_unix_process_id(connection, &pid))
d->cynara_session_id = cynara_session_from_pid(pid);
+
+ /* If client exits as soon as async call, cynara_session_from_pid() returns null.
+ cynara_session_from_pid checks /proc/pid to verify process */
+ if (d->cynara_session_id == NULL)
+ asprintf (&d->cynara_session_id, "/proc/%ld", pid);
}
return d->cynara_session_id;
}
return d->n_match_rules;
}
+dbus_bool_t
+bus_connection_is_service_owner_by_prefix (DBusConnection *connection,
+ const char *name_prefix)
+{
+ BusConnectionData *d;
+ DBusList *link;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ link = _dbus_list_get_first_link (&d->services_owned);
+ while (link != NULL)
+ {
+ BusService *service = link->data;
+ DBusString str;
+
+ _dbus_string_init_const (&str, bus_service_get_name (service));
+
+ if (_dbus_string_starts_with_words_c_str (&str, name_prefix, '.'))
+ return TRUE;
+
+ link = _dbus_list_get_next_link (&d->services_owned, link);
+ }
+
+ return FALSE;
+}
+
+const DBusList *
+bus_connection_get_owned_services_list (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ _dbus_assert (d != NULL);
+
+ return d->services_owned;
+}
+
void
bus_connection_add_owned_service_link (DBusConnection *connection,
DBusList *link)
dbus_bool_t
bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
+ const char **limit_name_out,
+ int *limit_out,
DBusError *error)
{
unsigned long uid;
+ int limit;
+
+ limit = bus_context_get_max_completed_connections (connections->context);
- if (connections->n_completed >=
- bus_context_get_max_completed_connections (connections->context))
+ if (connections->n_completed >= limit)
{
+ if (limit_name_out != NULL)
+ *limit_name_out = "max_completed_connections";
+
+ if (limit_out != NULL)
+ *limit_out = limit;
+
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The maximum number of active connections has been reached");
return FALSE;
if (dbus_connection_get_unix_user (requesting_completion, &uid))
{
- if (get_connections_for_uid (connections, uid) >=
- bus_context_get_max_connections_per_user (connections->context))
+ limit = bus_context_get_max_connections_per_user (connections->context);
+
+ if (get_connections_for_uid (connections, uid) >= limit)
{
+ if (limit_name_out != NULL)
+ *limit_name_out = "max_connections_per_user";
+
+ if (limit_out != NULL)
+ *limit_out = limit;
+
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The maximum number of active connections for UID %lu has been reached",
uid);
DBusList *link;
CancelPendingReplyData *cprd;
int count;
+ int limit;
_dbus_assert (will_get_reply != NULL);
_dbus_assert (will_send_reply != NULL);
if (pending->will_get_reply == will_get_reply)
++count;
}
-
- if (count >=
- bus_context_get_max_replies_per_connection (connections->context))
+
+ limit = bus_context_get_max_replies_per_connection (connections->context);
+
+ if (count >= limit)
{
+ bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING,
+ "The maximum number of pending replies for "
+ "\"%s\" (%s) has been reached "
+ "(max_replies_per_connection=%d)",
+ bus_connection_get_name (will_get_reply),
+ bus_connection_get_loginfo (will_get_reply),
+ limit);
+
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The maximum number of pending replies per connection has been reached");
return FALSE;
}
+#ifdef DBUS_ENABLE_STATS
+ {
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (will_get_reply);
+ _dbus_assert (d != NULL);
+
+ update_peak(&d->peak_pending_replies, count);
+ }
+#endif
+
pending = dbus_new0 (BusPendingReply, 1);
if (pending == NULL)
{
dbus_bool_t
bus_transaction_capture (BusTransaction *transaction,
DBusConnection *sender,
+ DBusConnection *addressed_recipient,
DBusMessage *message)
{
BusConnections *connections;
* There's little point, since there is up to 1 per process. */
_dbus_assert (mm != NULL);
- if (!bus_matchmaker_get_recipients (mm, connections, sender, NULL, message,
- &recipients))
+ if (!bus_matchmaker_get_recipients (mm, connections, sender,
+ addressed_recipient, message, &recipients))
goto out;
for (link = _dbus_list_get_first_link (&recipients);
dbus_bool_t
bus_transaction_capture_error_reply (BusTransaction *transaction,
+ DBusConnection *addressed_recipient,
const DBusError *error,
DBusMessage *in_reply_to)
{
if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
goto out;
- ret = bus_transaction_capture (transaction, NULL, reply);
+ ret = bus_transaction_capture (transaction, NULL, addressed_recipient, reply);
out:
dbus_message_unref (reply);
DBusMessage *message)
{
DBusError error = DBUS_ERROR_INIT;
- BusDeferredMessage *deferred_message;
+ BusDeferredMessage *deferred_message = NULL;
/* We have to set the sender to the driver, and have
* to check security policy since it was not done in
/* Capture it for monitors, even if the real recipient's receive policy
* does not allow it to receive this message from us (which would be odd).
*/
- if (!bus_transaction_capture (transaction, NULL, message))
+ if (!bus_transaction_capture (transaction, NULL, connection, message))
return FALSE;
/* If security policy doesn't allow the message, we would silently
*/
switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
transaction,
- NULL, connection, connection, message, &error,
+ NULL, connection, connection,
+ message, NULL, &error,
&deferred_message))
{
case BUS_RESULT_TRUE:
break;
case BUS_RESULT_FALSE:
- if (!bus_transaction_capture_error_reply (transaction, &error, message))
+ if (!bus_transaction_capture_error_reply (transaction, connection,
+ &error, message))
{
bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING,
"message from dbus-daemon rejected but not enough "
bus_connection_has_deferred_messages (DBusConnection *connection)
{
BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+ _dbus_assert (d != NULL);
+
return d->deferred_messages != NULL ? TRUE : FALSE;
}
{
BusConnectionData *d = BUS_CONNECTION_DATA(connection);
dbus_bool_t success;
+
+ _dbus_assert (d != NULL);
+
if (prepend)
success = _dbus_list_prepend(&d->deferred_messages, message);
else
return FALSE;
}
-dbus_bool_t
-bus_connection_replace_deferred_message (DBusConnection *connection,
- BusDeferredMessage *oldMessage,
- BusDeferredMessage *newMessage)
-{
- DBusList *link;
- BusConnectionData *d = BUS_CONNECTION_DATA(connection);
-
- link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
- if (link == NULL)
- return FALSE;
-
- if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
- return FALSE;
-
- bus_deferred_message_ref(newMessage);
- _dbus_list_remove_link(&d->deferred_messages, link);
- bus_deferred_message_unref(oldMessage);
- return TRUE;
-}
-
BusDeferredMessage *
bus_connection_pop_deferred_message (DBusConnection *connection)
{
BusDeferredMessage *message;
BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+ _dbus_assert (d != NULL);
+
link =_dbus_list_get_first_link(&d->deferred_messages);
if (link != NULL)
{
bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
{
BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+ _dbus_assert (d != NULL);
+
if (_dbus_list_prepend(&d->deferred_messages, message))
{
return TRUE;
DBusList *next;
BusDeferredMessage *message;
+ _dbus_assert (d != NULL);
+
link =_dbus_list_get_first_link(&d->deferred_messages);
while (link != NULL)
{
BusDeferredMessage *message)
{
BusConnectionData *d = BUS_CONNECTION_DATA(connection);
+
+ _dbus_assert (d != NULL);
+
if (_dbus_list_remove(&d->deferred_messages, message))
bus_deferred_message_unref(message);
}
return d->peak_bus_names;
}
+
+int bus_connection_get_n_pending_replies (DBusConnection *connection)
+{
+ BusConnectionData *d;
+ DBusList *link;
+ BusPendingReply *pending;
+ int count = 0;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert(d != NULL);
+
+ link = bus_expire_list_get_first_link(d->connections->pending_replies);
+ while (link != NULL)
+ {
+ pending = link->data;
+ link = bus_expire_list_get_next_link(d->connections->pending_replies,
+ link);
+ if (pending->will_get_reply == connection)
+ ++count;
+ }
+
+ return count;
+}
+
+int
+bus_connection_get_peak_pending_replies (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ return d->peak_pending_replies;
+}
#endif /* DBUS_ENABLE_STATS */
dbus_bool_t