Merge branch 'fd-passing'

Conflicts:
	dbus/dbus-connection.c
	dbus/dbus-message-util.c
	dbus/dbus-sysdeps-unix.c
This commit is contained in:
Thiago Macieira 2009-07-16 16:05:16 +02:00
commit 37019e9d27
55 changed files with 2376 additions and 355 deletions

View file

@ -13,6 +13,12 @@ FILE=dbus-1.pc.in
DIE=0
if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
echo "Activating pre-commit hook."
cp -av .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod -c +x .git/hooks/pre-commit
fi
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to compile $PROJECT."

View file

@ -190,6 +190,12 @@ new_connection_callback (DBusServer *server,
dbus_connection_set_max_message_size (new_connection,
context->limits.max_message_size);
dbus_connection_set_max_received_unix_fds (new_connection,
context->limits.max_incoming_unix_fds);
dbus_connection_set_max_message_unix_fds (new_connection,
context->limits.max_message_unix_fds);
dbus_connection_set_allow_anonymous (new_connection,
context->allow_anonymous);
@ -1471,8 +1477,8 @@ bus_context_check_security_policy (BusContext *context,
/* 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_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
(dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
{
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The destination service \"%s\" has a full message queue",

View file

@ -47,8 +47,11 @@ typedef struct BusMatchRule BusMatchRule;
typedef struct
{
long max_incoming_bytes; /**< How many incoming message bytes for a single connection */
long max_incoming_unix_fds; /**< How many incoming message unix fds for a single connection */
long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a single connection */
long max_outgoing_unix_fds; /**< How many outgoing unix fds can be queued for a single connection */
long max_message_size; /**< Max size of a single message in bytes */
long max_message_unix_fds; /**< Max number of unix fds of a single message*/
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 */

View file

@ -404,6 +404,15 @@ bus_config_parser_new (const DBusString *basedir,
parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 127;
parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 127;
parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
/* We set relatively conservative values here since due to the
way SCM_RIGHTS works we need to preallocate an array for the
maximum number of file descriptors we can receive. Picking a
high value here thus translates directly to more memory
allocation. */
parser->limits.max_incoming_unix_fds = 1024*4;
parser->limits.max_outgoing_unix_fds = 1024*4;
parser->limits.max_message_unix_fds = 1024;
/* Making this long means the user has to wait longer for an error
* message if something screws up, but making it too short means
@ -1828,16 +1837,31 @@ set_limit (BusConfigParser *parser,
must_be_positive = TRUE;
parser->limits.max_incoming_bytes = value;
}
else if (strcmp (name, "max_incoming_unix_fds") == 0)
{
must_be_positive = TRUE;
parser->limits.max_incoming_unix_fds = value;
}
else if (strcmp (name, "max_outgoing_bytes") == 0)
{
must_be_positive = TRUE;
parser->limits.max_outgoing_bytes = value;
}
else if (strcmp (name, "max_outgoing_unix_fds") == 0)
{
must_be_positive = TRUE;
parser->limits.max_outgoing_unix_fds = value;
}
else if (strcmp (name, "max_message_size") == 0)
{
must_be_positive = TRUE;
parser->limits.max_message_size = value;
}
else if (strcmp (name, "max_message_unix_fds") == 0)
{
must_be_positive = TRUE;
parser->limits.max_message_unix_fds = value;
}
else if (strcmp (name, "service_start_timeout") == 0)
{
must_be_positive = TRUE;
@ -2979,8 +3003,11 @@ limits_equal (const BusLimits *a,
{
return
(a->max_incoming_bytes == b->max_incoming_bytes
|| a->max_incoming_unix_fds == b->max_incoming_unix_fds
|| a->max_outgoing_bytes == b->max_outgoing_bytes
|| a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
|| a->max_message_size == b->max_message_size
|| a->max_message_unix_fds == b->max_message_unix_fds
|| a->activation_timeout == b->activation_timeout
|| a->auth_timeout == b->auth_timeout
|| a->max_completed_connections == b->max_completed_connections

View file

@ -365,10 +365,15 @@ Available limit names are:
.nf
"max_incoming_bytes" : total size in bytes of messages
incoming from a single connection
"max_incoming_unix_fds" : total number of unix fds of messages
incoming from a single connection
"max_outgoing_bytes" : total size in bytes of messages
queued up for a single connection
"max_outgoing_unix_fds" : total number of unix fds of messages
queued up for a single connection
"max_message_size" : max size of a single message in
bytes
"max_message_unix_fds" : max unix fds of a single message
"service_start_timeout" : milliseconds (thousandths) until
a started service has to connect
"auth_timeout" : milliseconds (thousandths) a

View file

@ -330,7 +330,7 @@ new_line (BusDesktopFileParser *parser)
line = &section->lines[section->n_lines++];
memset (line, 0, sizeof (BusDesktopFileLine));
_DBUS_ZERO(*line);
return line;
}

View file

@ -24,7 +24,6 @@
#include <config.h>
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

View file

@ -35,6 +35,11 @@
#include <dbus/dbus-internals.h>
#include <string.h>
#ifdef HAVE_UNIX_FD_PASSING
#include <dbus/dbus-sysdeps-unix.h>
#include <unistd.h>
#endif
static dbus_bool_t
send_one_message (DBusConnection *connection,
BusContext *context,
@ -51,6 +56,10 @@ send_one_message (DBusConnection *connection,
message,
NULL))
return TRUE; /* silently don't send it */
if (dbus_message_contains_unix_fds(message) &&
!dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
return TRUE; /* silently don't send it */
if (!bus_transaction_send (transaction,
connection,
@ -295,6 +304,16 @@ bus_dispatch (DBusConnection *connection,
addressed_recipient,
message, &error))
goto out;
if (dbus_message_contains_unix_fds(message) &&
!dbus_connection_can_send_type(addressed_recipient, DBUS_TYPE_UNIX_FD))
{
dbus_set_error(&error,
DBUS_ERROR_NOT_SUPPORTED,
"Tried to send message with Unix file descriptors"
"to a client that doesn't support that.");
goto out;
}
/* Dispatch the message */
if (!bus_transaction_send (transaction, addressed_recipient, message))
@ -4716,4 +4735,155 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
return TRUE;
}
#ifdef HAVE_UNIX_FD_PASSING
dbus_bool_t
bus_unix_fds_passing_test(const DBusString *test_data_dir)
{
BusContext *context;
DBusConnection *foo, *bar;
DBusError error;
DBusMessage *m;
dbus_bool_t b;
int one[2], two[2], x, y, z;
char r;
dbus_error_init (&error);
context = bus_context_new_test (test_data_dir, "valid-config-files/debug-allow-all.conf");
if (context == NULL)
_dbus_assert_not_reached ("could not alloc context");
foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
if (foo == NULL)
_dbus_assert_not_reached ("could not alloc connection");
if (!bus_setup_debug_client (foo))
_dbus_assert_not_reached ("could not set up connection");
spin_connection_until_authenticated (context, foo);
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
if (!check_add_match_all (context, foo))
_dbus_assert_not_reached ("AddMatch message failed");
bar = dbus_connection_open_private ("debug-pipe:name=test-server", &error);
if (bar == NULL)
_dbus_assert_not_reached ("could not alloc connection");
if (!bus_setup_debug_client (bar))
_dbus_assert_not_reached ("could not set up connection");
spin_connection_until_authenticated (context, bar);
if (!check_hello_message (context, bar))
_dbus_assert_not_reached ("hello message failed");
if (!check_add_match_all (context, bar))
_dbus_assert_not_reached ("AddMatch message failed");
if (!(m = dbus_message_new_signal("/", "a.b.c", "d")))
_dbus_assert_not_reached ("could not alloc message");
if (!(_dbus_full_duplex_pipe(one, one+1, TRUE, &error)))
_dbus_assert_not_reached("Failed to allocate pipe #1");
if (!(_dbus_full_duplex_pipe(two, two+1, TRUE, &error)))
_dbus_assert_not_reached("Failed to allocate pipe #2");
if (!dbus_message_append_args(m,
DBUS_TYPE_UNIX_FD, one,
DBUS_TYPE_UNIX_FD, two,
DBUS_TYPE_UNIX_FD, two,
DBUS_TYPE_INVALID))
_dbus_assert_not_reached("Failed to attach fds.");
if (!_dbus_close(one[0], &error))
_dbus_assert_not_reached("Failed to close pipe #1 ");
if (!_dbus_close(two[0], &error))
_dbus_assert_not_reached("Failed to close pipe #2 ");
if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD)))
_dbus_assert_not_reached("Connection cannot do fd passing");
if (!(dbus_connection_can_send_type(bar, DBUS_TYPE_UNIX_FD)))
_dbus_assert_not_reached("Connection cannot do fd passing");
if (!dbus_connection_send (foo, m, NULL))
_dbus_assert_not_reached("Failed to send fds");
dbus_message_unref(m);
bus_test_run_clients_loop (SEND_PENDING (foo));
bus_test_run_everything (context);
block_connection_until_message_from_bus (context, foo, "unix fd reception on foo");
if (!(m = pop_message_waiting_for_memory (foo)))
_dbus_assert_not_reached("Failed to receive msg");
if (!dbus_message_is_signal(m, "a.b.c", "d"))
_dbus_assert_not_reached("bogus message received");
dbus_message_unref(m);
block_connection_until_message_from_bus (context, bar, "unix fd reception on bar");
if (!(m = pop_message_waiting_for_memory (bar)))
_dbus_assert_not_reached("Failed to receive msg");
if (!dbus_message_is_signal(m, "a.b.c", "d"))
_dbus_assert_not_reached("bogus message received");
if (!dbus_message_get_args(m,
&error,
DBUS_TYPE_UNIX_FD, &x,
DBUS_TYPE_UNIX_FD, &y,
DBUS_TYPE_UNIX_FD, &z,
DBUS_TYPE_INVALID))
_dbus_assert_not_reached("Failed to parse fds.");
dbus_message_unref(m);
if (write(x, "X", 1) != 1)
_dbus_assert_not_reached("Failed to write to pipe #1");
if (write(y, "Y", 1) != 1)
_dbus_assert_not_reached("Failed to write to pipe #2");
if (write(z, "Z", 1) != 1)
_dbus_assert_not_reached("Failed to write to pipe #2/2nd fd");
if (!_dbus_close(x, &error))
_dbus_assert_not_reached("Failed to close pipe #1/other side ");
if (!_dbus_close(y, &error))
_dbus_assert_not_reached("Failed to close pipe #2/other side ");
if (!_dbus_close(z, &error))
_dbus_assert_not_reached("Failed to close pipe #2/other size 2nd fd ");
if (read(one[1], &r, 1) != 1 || r != 'X')
_dbus_assert_not_reached("Failed to read value from pipe.");
if (read(two[1], &r, 1) != 1 || r != 'Y')
_dbus_assert_not_reached("Failed to read value from pipe.");
if (read(two[1], &r, 1) != 1 || r != 'Z')
_dbus_assert_not_reached("Failed to read value from pipe.");
if (!_dbus_close(one[1], &error))
_dbus_assert_not_reached("Failed to close pipe #1 ");
if (!_dbus_close(two[1], &error))
_dbus_assert_not_reached("Failed to close pipe #2 ");
_dbus_verbose ("Disconnecting foo\n");
kill_client_connection_unchecked (foo);
_dbus_verbose ("Disconnecting bar\n");
kill_client_connection_unchecked (bar);
bus_context_unref (context);
return TRUE;
}
#endif
#endif /* DBUS_BUILD_TESTS */

View file

@ -208,9 +208,6 @@ setup_reload_pipe (DBusLoop *loop)
exit (1);
}
_dbus_fd_set_close_on_exec (reload_pipe[0]);
_dbus_fd_set_close_on_exec (reload_pipe[1]);
watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END],
DBUS_WATCH_READABLE, TRUE,
handle_reload_watch, NULL, NULL);

View file

@ -45,8 +45,11 @@
<!-- the memory limits are 1G instead of say 4G because they can't exceed 32-bit signed int max -->
<limit name="max_incoming_bytes">1000000000</limit>
<limit name="max_incoming_unix_fds">250000000</limit>
<limit name="max_outgoing_bytes">1000000000</limit>
<limit name="max_outgoing_unix_fds">250000000</limit>
<limit name="max_message_size">1000000000</limit>
<limit name="max_message_unix_fds">4096</limit>
<limit name="service_start_timeout">120000</limit>
<limit name="auth_timeout">240000</limit>
<limit name="max_completed_connections">100000</limit>

View file

@ -27,6 +27,7 @@
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-message-private.h>
#include "selinux.h"
#ifdef DBUS_BUILD_TESTS
@ -69,6 +70,7 @@ test_post_hook (void)
if (_dbus_getenv ("DBUS_TEST_SELINUX"))
bus_selinux_shutdown ();
check_memleaks (progname);
_dbus_check_fdleaks();
}
int
@ -138,6 +140,14 @@ main (int argc, char **argv)
die ("service reload");
test_post_hook ();
#ifdef HAVE_UNIX_FD_PASSING
test_pre_hook ();
printf ("%s: Running unix fd passing test\n", argv[0]);
if (!bus_unix_fds_passing_test (&test_data_dir))
die ("unix fd passing");
test_post_hook ();
#endif
printf ("%s: Success\n", argv[0]);

View file

@ -51,7 +51,9 @@ void bus_test_run_everything (BusContext *context);
BusContext* bus_context_new_test (const DBusString *test_data_dir,
const char *filename);
#ifdef HAVE_UNIX_FD_PASSING
dbus_bool_t bus_unix_fds_passing_test (const DBusString *test_data_dir);
#endif
#endif

View file

@ -57,6 +57,7 @@ AC_SUBST(DBUS_VERSION)
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CXX
AC_USE_SYSTEM_EXTENSIONS
AC_ISC_POSIX
AC_HEADER_STDC
AC_C_INLINE
@ -349,41 +350,23 @@ if test "x$dbus_cv_va_val_copy" = "xno"; then
fi
#### Atomic integers (checks by Sebastian Wilhelmi for GLib)
AC_MSG_CHECKING([whether to use inline assembler routines for atomic integers])
have_atomic_inc_cond=0
if test x"$GCC" = xyes; then
if test "x$enable_ansi" = "xyes"; then
AC_MSG_RESULT([no])
else
case $host_cpu in
i386)
AC_MSG_RESULT([no])
;;
i?86)
case $host_os in
darwin*)
AC_MSG_RESULT([darwin])
# check at compile-time, so that it is possible to build universal
# (with multiple architectures at once on the compile line)
have_atomic_inc_cond="(defined(__i386__) || defined(__x86_64__))"
;;
*)
AC_MSG_RESULT([i486])
have_atomic_inc_cond=1
;;
esac
;;
*)
AC_MSG_RESULT([no])
;;
esac
fi
#### Atomic integers
AC_CACHE_CHECK([whether $CC knows __sync_sub_and_fetch()],
dbus_cv_sync_sub_and_fetch,
[AC_LINK_IFELSE(
AC_LANG_PROGRAM([], [[int a = 4; int b = __sync_sub_and_fetch(&a, 4);]]),
[dbus_cv_sync_sub_and_fetch=yes],
[dbus_cv_sync_sub_and_fetch=no])
])
if test "x$dbus_cv_sync_sub_and_fetch" = "xyes" ; then
have_sync=1
else
have_sync=0
fi
AC_DEFINE_UNQUOTED([DBUS_USE_ATOMIC_INT_486_COND], [$have_atomic_inc_cond],
[Always defined; expands to 1 if we should use atomic integer implementation for 486, else 0])
AC_DEFINE_UNQUOTED(DBUS_HAVE_ATOMIC_INT_COND, [$have_atomic_inc_cond],
[Always defined; expands to 1 if we have an atomic integer implementation, else 0])
AC_DEFINE_UNQUOTED([DBUS_USE_SYNC], [$have_sync], [Use the gcc __sync extension])
#### Various functions
AC_SEARCH_LIBS(socket,[socket network])
@ -456,6 +439,8 @@ AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
AC_CHECK_HEADERS(errno.h)
AC_CHECK_HEADERS(byteswap.h)
AC_CHECK_HEADERS(unistd.h)
# Add -D_POSIX_PTHREAD_SEMANTICS if on Solaris
@ -536,6 +521,9 @@ AC_CHECK_HEADERS(sys/uio.h, [AC_CHECK_FUNCS(writev)])
dnl needed on darwin for NAME_MAX
AC_CHECK_HEADERS(sys/syslimits.h)
dnl Make it easy to check if we have MSG_NOSIGNAL without actually having to include sys/socket.h
AC_CHECK_DECLS([MSG_NOSIGNAL], [], [], [[ #include <sys/socket.h> ]])
dnl check for flavours of varargs macros (test from GLib)
AC_MSG_CHECKING(for ISO C99 varargs macros in C)
AC_TRY_COMPILE([],[
@ -579,6 +567,8 @@ fi
AC_CHECK_FUNCS(getpeerucred getpeereid)
AC_CHECK_FUNCS(pipe2 accept4)
#### Abstract sockets
if test x$enable_abstract_sockets = xauto; then
@ -881,6 +871,16 @@ else
AC_MSG_RESULT(no)
fi
# Check for SCM_RIGHTS
AC_MSG_CHECKING([for SCM_RIGHTS])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/socket.h>
#include <sys/un.h>
static int x = SCM_RIGHTS;
]], [[]])],
[ AC_MSG_RESULT([supported])
AC_DEFINE([HAVE_UNIX_FD_PASSING], [1], [Supports sending UNIX file descriptors]) ],
[ AC_MSG_RESULT([not supported]) ])
#### Set up final flags
DBUS_CLIENT_CFLAGS=

View file

@ -122,7 +122,9 @@ typedef enum {
DBUS_AUTH_COMMAND_REJECTED,
DBUS_AUTH_COMMAND_OK,
DBUS_AUTH_COMMAND_ERROR,
DBUS_AUTH_COMMAND_UNKNOWN
DBUS_AUTH_COMMAND_UNKNOWN,
DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD,
DBUS_AUTH_COMMAND_AGREE_UNIX_FD
} DBusAuthCommand;
/**
@ -184,6 +186,9 @@ struct DBusAuth
unsigned int already_got_mechanisms : 1; /**< Client already got mech list */
unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
unsigned int unix_fd_possible : 1; /**< This side could do unix fd passing */
unsigned int unix_fd_negotiated : 1; /**< Unix fd was successfully negotiated */
};
/**
@ -223,9 +228,10 @@ static dbus_bool_t send_rejected (DBusAuth *auth);
static dbus_bool_t send_error (DBusAuth *auth,
const char *message);
static dbus_bool_t send_ok (DBusAuth *auth);
static dbus_bool_t send_begin (DBusAuth *auth,
const DBusString *args_from_ok);
static dbus_bool_t send_begin (DBusAuth *auth);
static dbus_bool_t send_cancel (DBusAuth *auth);
static dbus_bool_t send_negotiate_unix_fd (DBusAuth *auth);
static dbus_bool_t send_agree_unix_fd (DBusAuth *auth);
/**
* Client states
@ -264,6 +270,9 @@ static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *aut
static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth,
DBusAuthCommand command,
const DBusString *args);
static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd (DBusAuth *auth,
DBusAuthCommand command,
const DBusString *args);
static const DBusAuthStateData client_state_need_send_auth = {
"NeedSendAuth", NULL
@ -277,7 +286,10 @@ static const DBusAuthStateData client_state_waiting_for_ok = {
static const DBusAuthStateData client_state_waiting_for_reject = {
"WaitingForReject", handle_client_state_waiting_for_reject
};
static const DBusAuthStateData client_state_waiting_for_agree_unix_fd = {
"WaitingForAgreeUnixFD", handle_client_state_waiting_for_agree_unix_fd
};
/**
* Common terminal states. Terminal states have handler == NULL.
*/
@ -1522,9 +1534,21 @@ send_ok (DBusAuth *auth)
}
static dbus_bool_t
send_begin (DBusAuth *auth,
const DBusString *args_from_ok)
send_begin (DBusAuth *auth)
{
if (!_dbus_string_append (&auth->outgoing,
"BEGIN\r\n"))
return FALSE;
goto_state (auth, &common_state_authenticated);
return TRUE;
}
static dbus_bool_t
process_ok(DBusAuth *auth,
const DBusString *args_from_ok) {
int end_of_hex;
/* "args_from_ok" should be the GUID, whitespace already pulled off the front */
@ -1549,20 +1573,19 @@ send_begin (DBusAuth *auth,
return TRUE;
}
if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
_dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
{
_dbus_verbose ("Got GUID '%s' from the server\n",
_dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
goto_state (auth, &common_state_authenticated);
return TRUE;
}
else
{
if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
_dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
return FALSE;
}
}
_dbus_verbose ("Got GUID '%s' from the server\n",
_dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
if (auth->unix_fd_possible)
return send_negotiate_unix_fd(auth);
_dbus_verbose("Not negotiating unix fd passing, since not possible\n");
return send_begin (auth);
}
static dbus_bool_t
@ -1621,6 +1644,33 @@ process_data (DBusAuth *auth,
return TRUE;
}
static dbus_bool_t
send_negotiate_unix_fd (DBusAuth *auth)
{
if (!_dbus_string_append (&auth->outgoing,
"NEGOTIATE_UNIX_FD\r\n"))
return FALSE;
goto_state (auth, &client_state_waiting_for_agree_unix_fd);
return TRUE;
}
static dbus_bool_t
send_agree_unix_fd (DBusAuth *auth)
{
_dbus_assert(auth->unix_fd_possible);
auth->unix_fd_negotiated = TRUE;
_dbus_verbose("Agreed to UNIX FD passing\n");
if (!_dbus_string_append (&auth->outgoing,
"AGREE_UNIX_FD\r\n"))
return FALSE;
goto_state (auth, &server_state_waiting_for_begin);
return TRUE;
}
static dbus_bool_t
handle_auth (DBusAuth *auth, const DBusString *args)
{
@ -1712,9 +1762,13 @@ handle_server_state_waiting_for_auth (DBusAuth *auth,
case DBUS_AUTH_COMMAND_ERROR:
return send_rejected (auth);
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
return send_error (auth, "Need to authenticate first");
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@ -1741,9 +1795,13 @@ handle_server_state_waiting_for_data (DBusAuth *auth,
goto_state (auth, &common_state_need_disconnect);
return TRUE;
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
return send_error (auth, "Need to authenticate first");
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@ -1766,9 +1824,16 @@ handle_server_state_waiting_for_begin (DBusAuth *auth,
goto_state (auth, &common_state_authenticated);
return TRUE;
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
if (auth->unix_fd_possible)
return send_agree_unix_fd(auth);
else
return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
@ -1933,7 +1998,7 @@ handle_client_state_waiting_for_data (DBusAuth *auth,
return process_rejected (auth, args);
case DBUS_AUTH_COMMAND_OK:
return send_begin (auth, args);
return process_ok(auth, args);
case DBUS_AUTH_COMMAND_ERROR:
return send_cancel (auth);
@ -1942,6 +2007,8 @@ handle_client_state_waiting_for_data (DBusAuth *auth,
case DBUS_AUTH_COMMAND_CANCEL:
case DBUS_AUTH_COMMAND_BEGIN:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@ -1958,7 +2025,7 @@ handle_client_state_waiting_for_ok (DBusAuth *auth,
return process_rejected (auth, args);
case DBUS_AUTH_COMMAND_OK:
return send_begin (auth, args);
return process_ok(auth, args);
case DBUS_AUTH_COMMAND_DATA:
case DBUS_AUTH_COMMAND_ERROR:
@ -1968,6 +2035,8 @@ handle_client_state_waiting_for_ok (DBusAuth *auth,
case DBUS_AUTH_COMMAND_CANCEL:
case DBUS_AUTH_COMMAND_BEGIN:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
@ -1990,12 +2059,46 @@ handle_client_state_waiting_for_reject (DBusAuth *auth,
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_ERROR:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
default:
goto_state (auth, &common_state_need_disconnect);
return TRUE;
}
}
static dbus_bool_t
handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth,
DBusAuthCommand command,
const DBusString *args)
{
switch (command)
{
case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
_dbus_assert(auth->unix_fd_possible);
auth->unix_fd_negotiated = TRUE;
_dbus_verbose("Sucessfully negotiated UNIX FD passing\n");
return send_begin (auth);
case DBUS_AUTH_COMMAND_ERROR:
_dbus_assert(auth->unix_fd_possible);
auth->unix_fd_negotiated = FALSE;
_dbus_verbose("Failed to negotiate UNIX FD passing\n");
return send_begin (auth);
case DBUS_AUTH_COMMAND_OK:
case DBUS_AUTH_COMMAND_DATA:
case DBUS_AUTH_COMMAND_REJECTED:
case DBUS_AUTH_COMMAND_AUTH:
case DBUS_AUTH_COMMAND_CANCEL:
case DBUS_AUTH_COMMAND_BEGIN:
case DBUS_AUTH_COMMAND_UNKNOWN:
case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
default:
return send_error (auth, "Unknown command");
}
}
/**
* Mapping from command name to enum
*/
@ -2005,13 +2108,15 @@ typedef struct {
} DBusAuthCommandName;
static const DBusAuthCommandName auth_command_names[] = {
{ "AUTH", DBUS_AUTH_COMMAND_AUTH },
{ "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
{ "DATA", DBUS_AUTH_COMMAND_DATA },
{ "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
{ "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
{ "OK", DBUS_AUTH_COMMAND_OK },
{ "ERROR", DBUS_AUTH_COMMAND_ERROR }
{ "AUTH", DBUS_AUTH_COMMAND_AUTH },
{ "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
{ "DATA", DBUS_AUTH_COMMAND_DATA },
{ "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
{ "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
{ "OK", DBUS_AUTH_COMMAND_OK },
{ "ERROR", DBUS_AUTH_COMMAND_ERROR },
{ "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
{ "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
};
static DBusAuthCommand
@ -2685,6 +2790,31 @@ _dbus_auth_set_context (DBusAuth *auth,
&auth->context, 0, _dbus_string_get_length (context));
}
/**
* Sets whether unix fd passing is potentially on the transport and
* hence shall be negotiated.
*
* @param auth the auth conversation
* @param b TRUE when unix fd passing shall be negotiated, otherwise FALSE
*/
void
_dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
{
auth->unix_fd_possible = b;
}
/**
* Queries whether unix fd passing was sucessfully negotiated.
*
* @param auth the auth conversion
* @returns #TRUE when unix fd passing was negotiated.
*/
dbus_bool_t
_dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
{
return auth->unix_fd_negotiated;
}
/** @} */
/* tests in dbus-auth-util.c */

View file

@ -75,6 +75,8 @@ dbus_bool_t _dbus_auth_set_context (DBusAuth *auth,
const DBusString *context);
const char* _dbus_auth_get_guid_from_server(DBusAuth *auth);
void _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b);
dbus_bool_t _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth);
DBUS_END_DECLS

View file

@ -33,6 +33,7 @@
#include "dbus-list.h"
#include "dbus-hash.h"
#include "dbus-message-internal.h"
#include "dbus-message-private.h"
#include "dbus-threads.h"
#include "dbus-protocol.h"
#include "dbus-dataslot.h"
@ -41,6 +42,7 @@
#include "dbus-object-tree.h"
#include "dbus-threads-internal.h"
#include "dbus-bus.h"
#include "dbus-marshal-basic.h"
#ifdef DBUS_DISABLE_CHECKS
#define TOOK_LOCK_CHECK(connection)
@ -223,7 +225,11 @@ struct DBusPreallocatedSend
DBusList *counter_link; /**< Preallocated link in the resource counter */
};
#ifdef HAVE_DECL_MSG_NOSIGNAL
static dbus_bool_t _dbus_modify_sigpipe = FALSE;
#else
static dbus_bool_t _dbus_modify_sigpipe = TRUE;
#endif
/**
* Implementation details of DBusConnection. All fields are private.
@ -621,8 +627,8 @@ _dbus_connection_message_sent (DBusConnection *connection,
connection, connection->n_outgoing);
/* Save this link in the link cache also */
_dbus_message_remove_size_counter (message, connection->outgoing_counter,
&link);
_dbus_message_remove_counter (message, connection->outgoing_counter,
&link);
_dbus_list_prepend_link (&connection->link_cache, link);
dbus_message_unref (message);
@ -1929,8 +1935,8 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con
_dbus_list_prepend_link (&connection->outgoing_messages,
preallocated->queue_link);
_dbus_message_add_size_counter_link (message,
preallocated->counter_link);
_dbus_message_add_counter_link (message,
preallocated->counter_link);
dbus_free (preallocated);
preallocated = NULL;
@ -2575,9 +2581,9 @@ free_outgoing_message (void *element,
DBusMessage *message = element;
DBusConnection *connection = data;
_dbus_message_remove_size_counter (message,
connection->outgoing_counter,
NULL);
_dbus_message_remove_counter (message,
connection->outgoing_counter,
NULL);
dbus_message_unref (message);
}
@ -2970,14 +2976,58 @@ dbus_connection_get_server_id (DBusConnection *connection)
char *id;
_dbus_return_val_if_fail (connection != NULL, NULL);
CONNECTION_LOCK (connection);
id = _dbus_strdup (_dbus_transport_get_server_id (connection->transport));
CONNECTION_UNLOCK (connection);
return id;
}
/**
* Tests whether a certain type can be send via the connection. This
* will always return TRUE for all types, with the exception of
* DBUS_TYPE_UNIX_FD. The function will return TRUE for
* DBUS_TYPE_UNIX_FD only on systems that know Unix file descriptors
* and can send them via the chosen transport and when the remote side
* supports this.
*
* This function can be used to do runtime checking for types that
* might be unknown to the specific D-Bus client implementation
* version, i.e. it will return FALSE for all types this
* implementation does not know.
*
* @param connection the connection
* @param type the type to check
* @returns TRUE if the type may be send via the connection
*/
dbus_bool_t
dbus_connection_can_send_type(DBusConnection *connection,
int type)
{
_dbus_return_val_if_fail (connection != NULL, FALSE);
if (!_dbus_type_is_valid(type))
return FALSE;
if (type != DBUS_TYPE_UNIX_FD)
return TRUE;
#ifdef HAVE_UNIX_FD_PASSING
{
dbus_bool_t b;
CONNECTION_LOCK(connection);
b = _dbus_transport_can_pass_unix_fd(connection->transport);
CONNECTION_UNLOCK(connection);
return b;
}
#endif
return FALSE;
}
/**
* Set whether _exit() should be called when the connection receives a
* disconnect signal. The call to _exit() comes after any handlers for
@ -3078,8 +3128,23 @@ dbus_connection_send_preallocated (DBusConnection *connection,
_dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL ||
(dbus_message_get_interface (message) != NULL &&
dbus_message_get_member (message) != NULL));
CONNECTION_LOCK (connection);
#ifdef HAVE_UNIX_FD_PASSING
if (!_dbus_transport_can_pass_unix_fd(connection->transport) &&
message->n_unix_fds > 0)
{
/* Refuse to send fds on a connection that cannot handle
them. Unfortunately we cannot return a proper error here, so
the best we can is just return. */
CONNECTION_UNLOCK (connection);
return;
}
#endif
_dbus_connection_send_preallocated_and_unlock (connection,
preallocated,
message, client_serial);
@ -3143,6 +3208,20 @@ dbus_connection_send (DBusConnection *connection,
CONNECTION_LOCK (connection);
#ifdef HAVE_UNIX_FD_PASSING
if (!_dbus_transport_can_pass_unix_fd(connection->transport) &&
message->n_unix_fds > 0)
{
/* Refuse to send fds on a connection that cannot handle
them. Unfortunately we cannot return a proper error here, so
the best we can is just return. */
CONNECTION_UNLOCK (connection);
return FALSE;
}
#endif
return _dbus_connection_send_and_unlock (connection,
message,
serial);
@ -3197,12 +3276,16 @@ reply_handler_timeout (void *data)
* you want a very short or very long timeout. If INT_MAX is passed for
* the timeout, no timeout will be set and the call will block forever.
*
* @warning if the connection is disconnected, the #DBusPendingCall
* will be set to #NULL, so be careful with this.
*
* @warning if the connection is disconnected or you try to send Unix
* file descriptors on a connection that does not support them, the
* #DBusPendingCall will be set to #NULL, so be careful with this.
*
* @param connection the connection
* @param message the message to send
* @param pending_return return location for a #DBusPendingCall object, or #NULL if connection is disconnected
* @param pending_return return location for a #DBusPendingCall
* object, or #NULL if connection is disconnected or when you try to
* send Unix file descriptors on a connection that does not support
* them.
* @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout
* @returns #FALSE if no memory, #TRUE otherwise.
*
@ -3226,6 +3309,21 @@ dbus_connection_send_with_reply (DBusConnection *connection,
CONNECTION_LOCK (connection);
#ifdef HAVE_UNIX_FD_PASSING
if (!_dbus_transport_can_pass_unix_fd(connection->transport) &&
message->n_unix_fds > 0)
{
/* Refuse to send fds on a connection that cannot handle
them. Unfortunately we cannot return a proper error here, so
the best we can do is return TRUE but leave *pending_return
as NULL. */
CONNECTION_UNLOCK (connection);
return TRUE;
}
#endif
if (!_dbus_connection_get_is_connected_unlocked (connection))
{
CONNECTION_UNLOCK (connection);
@ -3334,12 +3432,26 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
{
DBusMessage *reply;
DBusPendingCall *pending;
_dbus_return_val_if_fail (connection != NULL, NULL);
_dbus_return_val_if_fail (message != NULL, NULL);
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL);
_dbus_return_val_if_error_is_set (error, NULL);
#ifdef HAVE_UNIX_FD_PASSING
CONNECTION_LOCK (connection);
if (!_dbus_transport_can_pass_unix_fd(connection->transport) &&
message->n_unix_fds > 0)
{
CONNECTION_UNLOCK (connection);
dbus_set_error(error, DBUS_ERROR_FAILED, "Cannot send file descriptors on this connection.");
return NULL;
}
CONNECTION_UNLOCK (connection);
#endif
if (!dbus_connection_send_with_reply (connection, message,
&pending, timeout_milliseconds))
{
@ -5860,6 +5972,45 @@ dbus_connection_get_max_message_size (DBusConnection *connection)
return res;
}
/**
* Specifies the maximum number of unix fds a message on this
* connection is allowed to receive. Messages with more unix fds will
* result in disconnecting the connection.
*
* @param connection a #DBusConnection
* @param size maximum message unix fds the connection can receive
*/
void
dbus_connection_set_max_message_unix_fds (DBusConnection *connection,
long n)
{
_dbus_return_if_fail (connection != NULL);
CONNECTION_LOCK (connection);
_dbus_transport_set_max_message_unix_fds (connection->transport,
n);
CONNECTION_UNLOCK (connection);
}
/**
* Gets the value set by dbus_connection_set_max_message_unix_fds().
*
* @param connection the connection
* @returns the max numer of unix fds of a single message
*/
long
dbus_connection_get_max_message_unix_fds (DBusConnection *connection)
{
long res;
_dbus_return_val_if_fail (connection != NULL, 0);
CONNECTION_LOCK (connection);
res = _dbus_transport_get_max_message_unix_fds (connection->transport);
CONNECTION_UNLOCK (connection);
return res;
}
/**
* Sets the maximum total number of bytes that can be used for all messages
* received on this connection. Messages count toward the maximum until
@ -5916,6 +6067,48 @@ dbus_connection_get_max_received_size (DBusConnection *connection)
return res;
}
/**
* Sets the maximum total number of unix fds that can be used for all messages
* received on this connection. Messages count toward the maximum until
* they are finalized. When the maximum is reached, the connection will
* not read more data until some messages are finalized.
*
* The semantics are analogous to those of dbus_connection_set_max_received_size().
*
* @param connection the connection
* @param size the maximum size in bytes of all outstanding messages
*/
void
dbus_connection_set_max_received_unix_fds (DBusConnection *connection,
long n)
{
_dbus_return_if_fail (connection != NULL);
CONNECTION_LOCK (connection);
_dbus_transport_set_max_received_unix_fds (connection->transport,
n);
CONNECTION_UNLOCK (connection);
}
/**
* Gets the value set by dbus_connection_set_max_received_unix_fds().
*
* @param connection the connection
* @returns the max unix fds of all live messages
*/
long
dbus_connection_get_max_received_unix_fds (DBusConnection *connection)
{
long res;
_dbus_return_val_if_fail (connection != NULL, 0);
CONNECTION_LOCK (connection);
res = _dbus_transport_get_max_received_unix_fds (connection->transport);
CONNECTION_UNLOCK (connection);
return res;
}
/**
* Gets the approximate size in bytes of all messages in the outgoing
* message queue. The size is approximate in that you shouldn't use
@ -5932,9 +6125,29 @@ dbus_connection_get_outgoing_size (DBusConnection *connection)
long res;
_dbus_return_val_if_fail (connection != NULL, 0);
CONNECTION_LOCK (connection);
res = _dbus_counter_get_value (connection->outgoing_counter);
res = _dbus_counter_get_size_value (connection->outgoing_counter);
CONNECTION_UNLOCK (connection);
return res;
}
/**
* Gets the approximate number of uni fds of all messages in the
* outgoing message queue.
*
* @param connection the connection
* @returns the number of unix fds that have been queued up but not sent
*/
long
dbus_connection_get_outgoing_unix_fds (DBusConnection *connection)
{
long res;
_dbus_return_val_if_fail (connection != NULL, 0);
CONNECTION_LOCK (connection);
res = _dbus_counter_get_unix_fd_value (connection->outgoing_counter);
CONNECTION_UNLOCK (connection);
return res;
}

View file

@ -180,6 +180,8 @@ dbus_bool_t dbus_connection_get_is_connected (DBusConnection
dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection);
dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection *connection);
char* dbus_connection_get_server_id (DBusConnection *connection);
dbus_bool_t dbus_connection_can_send_type (DBusConnection *connection,
int type);
void dbus_connection_set_exit_on_disconnect (DBusConnection *connection,
dbus_bool_t exit_on_disconnect);
void dbus_connection_flush (DBusConnection *connection);
@ -279,7 +281,16 @@ long dbus_connection_get_max_message_size (DBusConnection *connection);
void dbus_connection_set_max_received_size (DBusConnection *connection,
long size);
long dbus_connection_get_max_received_size (DBusConnection *connection);
void dbus_connection_set_max_message_unix_fds (DBusConnection *connection,
long n);
long dbus_connection_get_max_message_unix_fds (DBusConnection *connection);
void dbus_connection_set_max_received_unix_fds(DBusConnection *connection,
long n);
long dbus_connection_get_max_received_unix_fds(DBusConnection *connection);
long dbus_connection_get_outgoing_size (DBusConnection *connection);
long dbus_connection_get_outgoing_unix_fds (DBusConnection *connection);
DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection *connection);
void dbus_connection_free_preallocated_send (DBusConnection *connection,

View file

@ -294,18 +294,23 @@ _DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
_DBUS_DECLARE_GLOBAL_LOCK (server_slots);
_DBUS_DECLARE_GLOBAL_LOCK (message_slots);
/* 5-10 */
_DBUS_DECLARE_GLOBAL_LOCK (atomic);
_DBUS_DECLARE_GLOBAL_LOCK (bus);
_DBUS_DECLARE_GLOBAL_LOCK (bus_datas);
_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
_DBUS_DECLARE_GLOBAL_LOCK (system_users);
/* 10-15 */
_DBUS_DECLARE_GLOBAL_LOCK (message_cache);
/* 10-14 */
_DBUS_DECLARE_GLOBAL_LOCK (shared_connections);
_DBUS_DECLARE_GLOBAL_LOCK (win_fds);
_DBUS_DECLARE_GLOBAL_LOCK (sid_atom_cache);
_DBUS_DECLARE_GLOBAL_LOCK (machine_uuid);
#if !DBUS_USE_SYNC
_DBUS_DECLARE_GLOBAL_LOCK (atomic);
#define _DBUS_N_GLOBAL_LOCKS (15)
#else
#define _DBUS_N_GLOBAL_LOCKS (14)
#endif
dbus_bool_t _dbus_threads_init_debug (void);

View file

@ -414,6 +414,7 @@ _dbus_marshal_set_basic (DBusString *str,
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
pos = _DBUS_ALIGN_VALUE (pos, 4);
set_4_octets (str, pos, vp->u32, byte_order);
if (old_end_pos)
@ -540,6 +541,7 @@ _dbus_marshal_read_basic (const DBusString *str,
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_UNIX_FD:
{
volatile dbus_uint32_t *vp = value;
pos = _DBUS_ALIGN_VALUE (pos, 4);
@ -839,6 +841,7 @@ _dbus_marshal_write_basic (DBusString *str,
break;
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
return marshal_4_octets (str, insert_at, vp->u32,
byte_order, pos_after);
break;
@ -1066,6 +1069,7 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after);
break;
case DBUS_TYPE_INT64:
@ -1114,6 +1118,7 @@ _dbus_marshal_skip_basic (const DBusString *str,
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
*pos = _DBUS_ALIGN_VALUE (*pos, 4);
*pos += 4;
break;
@ -1202,6 +1207,7 @@ _dbus_type_get_alignment (int typecode)
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
/* this stuff is 4 since it starts with a length */
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
@ -1256,6 +1262,7 @@ _dbus_type_is_valid (int typecode)
case DBUS_TYPE_STRUCT:
case DBUS_TYPE_DICT_ENTRY:
case DBUS_TYPE_VARIANT:
case DBUS_TYPE_UNIX_FD:
return TRUE;
default:
@ -1316,6 +1323,8 @@ _dbus_type_to_string (int typecode)
return "begin_dict_entry";
case DBUS_DICT_ENTRY_END_CHAR:
return "end_dict_entry";
case DBUS_TYPE_UNIX_FD:
return "unix_fd";
default:
return "unknown";
}

View file

@ -26,21 +26,27 @@
#define DBUS_MARSHAL_BASIC_H
#include <config.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#include <dbus/dbus-protocol.h>
#include <dbus/dbus-types.h>
#include <dbus/dbus-arch-deps.h>
#include <dbus/dbus-string.h>
#ifndef PACKAGE
#error "config.h not included here"
#endif
#ifdef WORDS_BIGENDIAN
#define DBUS_COMPILER_BYTE_ORDER DBUS_BIG_ENDIAN
#else
#define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN
#endif
#ifdef HAVE_BYTESWAP_H
#define DBUS_UINT16_SWAP_LE_BE_CONSTANT(val) bswap_16(val)
#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) bswap_32(val)
#else /* HAVE_BYTESWAP_H */
#define DBUS_UINT16_SWAP_LE_BE_CONSTANT(val) ((dbus_uint16_t) ( \
(dbus_uint16_t) ((dbus_uint16_t) (val) >> 8) | \
(dbus_uint16_t) ((dbus_uint16_t) (val) << 8)))
@ -51,8 +57,14 @@
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >> 8) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24)))
#endif /* HAVE_BYTESWAP_H */
#ifdef DBUS_HAVE_INT64
#ifdef HAVE_BYTESWAP_H
#define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val) bswap_64(val)
#else /* HAVE_BYTESWAP_H */
#define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val) ((dbus_uint64_t) ( \
(((dbus_uint64_t) (val) & \
(dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000000000ff)) << 56) | \
@ -72,6 +84,8 @@
(dbus_uint64_t) DBUS_UINT64_CONSTANT (0xff00000000000000)) >> 56)))
#endif /* DBUS_HAVE_INT64 */
#endif /* HAVE_BYTESWAP_H */
#define DBUS_UINT16_SWAP_LE_BE(val) (DBUS_UINT16_SWAP_LE_BE_CONSTANT (val))
#define DBUS_INT16_SWAP_LE_BE(val) ((dbus_int16_t)DBUS_UINT16_SWAP_LE_BE_CONSTANT (val))

View file

@ -191,6 +191,11 @@ byteswap_body_helper (DBusTypeReader *reader,
}
break;
case DBUS_TYPE_UNIX_FD:
/* fds can only be passed on a local machine, so byte order must always match */
_dbus_assert_not_reached("attempted to byteswap unix fds which makes no sense");
break;
default:
_dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
break;

View file

@ -28,10 +28,6 @@
#include <dbus/dbus-protocol.h>
#include <dbus/dbus-marshal-recursive.h>
#ifndef PACKAGE
#error "config.h not included here"
#endif
void _dbus_marshal_byteswap (const DBusString *signature,
int signature_start,
int old_byte_order,

View file

@ -81,7 +81,8 @@ _dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = {
{ DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32 },
{ DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING },
{ DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING },
{ DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE }
{ DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE },
{ DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32 }
};
/** Macro to look up the correct type for a field */
@ -888,6 +889,10 @@ load_and_validate_field (DBusHeader *header,
}
break;
case DBUS_HEADER_FIELD_UNIX_FDS:
/* Every value makes sense */
break;
case DBUS_HEADER_FIELD_SIGNATURE:
/* SIGNATURE validated generically due to its type */
string_validation_func = NULL;

View file

@ -28,10 +28,6 @@
#include <dbus/dbus-marshal-basic.h>
#include <dbus/dbus-marshal-validate.h>
#ifndef PACKAGE
#error "config.h not included here"
#endif
typedef struct DBusHeader DBusHeader;
typedef struct DBusHeaderField DBusHeaderField;

View file

@ -28,10 +28,6 @@
#include <dbus/dbus-protocol.h>
#include <dbus/dbus-list.h>
#ifndef PACKAGE
#error "config.h not included here"
#endif
typedef struct DBusTypeReader DBusTypeReader;
typedef struct DBusTypeWriter DBusTypeWriter;
typedef struct DBusTypeReaderClass DBusTypeReaderClass;

View file

@ -100,6 +100,7 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
@ -319,12 +320,13 @@ validate_body_helper (DBusTypeReader *reader,
case DBUS_TYPE_BYTE:
++p;
break;
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_UNIX_FD:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:

View file

@ -26,10 +26,6 @@
#include <config.h>
#ifndef PACKAGE
#error "config.h not included here"
#endif
/**
* @addtogroup DBusMarshal
*
@ -117,6 +113,7 @@ typedef enum
DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS = 53,
DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY = 54,
DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE = 55,
DBUS_INVALID_MISSING_UNIX_FDS = 56,
DBUS_VALIDITY_LAST
} DBusValidity;

View file

@ -451,7 +451,7 @@ _dbus_md5_final (DBusMD5Context *context,
/* some kind of security paranoia, though it seems pointless
* to me given the nonzeroed stuff flying around
*/
memset ((void*)context, '\0', sizeof (DBusMD5Context));
_DBUS_ZERO(*context);
return TRUE;
}

View file

@ -43,8 +43,8 @@ void* dbus_realloc (void *memory,
size_t bytes);
void dbus_free (void *memory);
#define dbus_new(type, count) ((type*)dbus_malloc (sizeof (type) * (count)));
#define dbus_new0(type, count) ((type*)dbus_malloc0 (sizeof (type) * (count)));
#define dbus_new(type, count) ((type*)dbus_malloc (sizeof (type) * (count)))
#define dbus_new0(type, count) ((type*)dbus_malloc0 (sizeof (type) * (count)))
void dbus_free_string_array (char **str_array);

View file

@ -949,6 +949,7 @@ static const int typecodes[] = {
DBUS_STRUCT_END_CHAR,
DBUS_DICT_ENTRY_BEGIN_CHAR,
DBUS_DICT_ENTRY_END_CHAR,
DBUS_TYPE_UNIX_FD,
255 /* random invalid typecode */
};

View file

@ -34,14 +34,17 @@ typedef struct DBusMessageLoader DBusMessageLoader;
void _dbus_message_get_network_data (DBusMessage *message,
const DBusString **header,
const DBusString **body);
void _dbus_message_get_unix_fds (DBusMessage *message,
const int **fds,
unsigned *n_fds);
void _dbus_message_lock (DBusMessage *message);
void _dbus_message_unlock (DBusMessage *message);
dbus_bool_t _dbus_message_add_size_counter (DBusMessage *message,
dbus_bool_t _dbus_message_add_counter (DBusMessage *message,
DBusCounter *counter);
void _dbus_message_add_size_counter_link (DBusMessage *message,
void _dbus_message_add_counter_link (DBusMessage *message,
DBusList *link);
void _dbus_message_remove_size_counter (DBusMessage *message,
void _dbus_message_remove_counter (DBusMessage *message,
DBusCounter *counter,
DBusList **link_return);
@ -54,6 +57,14 @@ void _dbus_message_loader_get_buffer (DBusMessageLoader
void _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
DBusString *buffer,
int bytes_read);
dbus_bool_t _dbus_message_loader_get_unix_fds (DBusMessageLoader *loader,
int **fds,
unsigned *max_n_fds);
void _dbus_message_loader_return_unix_fds (DBusMessageLoader *loader,
int *fds,
unsigned n_fds);
dbus_bool_t _dbus_message_loader_queue_messages (DBusMessageLoader *loader);
DBusMessage* _dbus_message_loader_peek_message (DBusMessageLoader *loader);
DBusMessage* _dbus_message_loader_pop_message (DBusMessageLoader *loader);
@ -67,6 +78,10 @@ void _dbus_message_loader_set_max_message_size (DBusMessageLoader
long size);
long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader);
void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader,
long n);
long _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader *loader);
DBUS_END_DECLS
#endif /* DBUS_MESSAGE_INTERNAL_H */

View file

@ -23,6 +23,8 @@
#ifndef DBUS_MESSAGE_PRIVATE_H
#define DBUS_MESSAGE_PRIVATE_H
#include <config.h>
#include <dbus/dbus-message.h>
#include <dbus/dbus-message-internal.h>
#include <dbus/dbus-string.h>
@ -66,12 +68,21 @@ struct DBusMessageLoader
DBusList *messages; /**< Complete messages. */
long max_message_size; /**< Maximum size of a message */
long max_message_unix_fds; /**< Maximum unix fds in a message */
unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
DBusValidity corruption_reason; /**< why we were corrupted */
unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
DBusValidity corruption_reason; /**< why we were corrupted */
unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
#ifdef HAVE_UNIX_FD_PASSING
unsigned int unix_fds_outstanding : 1; /**< Someone is using the unix fd array to read */
int *unix_fds; /**< File descriptors that have been read from the transport but not yet been handed to any message. Array will be allocated at first use. */
unsigned n_unix_fds_allocated; /**< Number of file descriptors this array has space for */
unsigned n_unix_fds; /**< Number of valid file descriptors in array */
#endif
};
@ -100,8 +111,8 @@ struct DBusMessage
#ifndef DBUS_DISABLE_CHECKS
unsigned int in_cache : 1; /**< Has been "freed" since it's in the cache (this is a debug feature) */
#endif
DBusList *size_counters; /**< 0-N DBusCounter used to track message size. */
DBusList *counters; /**< 0-N DBusCounter used to track message size/unix fds. */
long size_counter_delta; /**< Size we incremented the size counters by. */
dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */
@ -111,6 +122,17 @@ struct DBusMessage
#ifndef DBUS_DISABLE_CHECKS
int generation; /**< _dbus_current_generation when message was created */
#endif
#ifdef HAVE_UNIX_FD_PASSING
int *unix_fds;
/**< Unix file descriptors associated with this message. These are
closed when the message is destroyed, hence make sure to dup()
them when adding or removing them here. */
unsigned n_unix_fds; /**< Number of valid fds in the array */
unsigned n_unix_fds_allocated; /**< Allocated size of the array */
long unix_fd_counter_delta; /**< Size we incremented the unix fd counter by */
#endif
};
dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
@ -118,6 +140,9 @@ dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
int first_arg_type,
va_list var_args);
void _dbus_check_fdleaks(void);
/** @} */
DBUS_END_DECLS

View file

@ -27,6 +27,17 @@
#include "dbus-message-private.h"
#include "dbus-marshal-recursive.h"
#include "dbus-string.h"
#ifdef HAVE_UNIX_FD_PASSING
#include "dbus-sysdeps-unix.h"
#endif
#ifdef __linux__
/* Necessary for the Linux-specific fd leak checking code only */
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#endif
/**
* @addtogroup DBusMessage
@ -126,6 +137,50 @@ check_memleaks (void)
}
}
void
_dbus_check_fdleaks(void)
{
#ifdef __linux__
DIR *d;
/* This works on Linux only */
if ((d = opendir("/proc/self/fd")))
{
struct dirent *de;
while ((de = readdir(d)))
{
long l;
char *e = NULL;
int fd;
if (de->d_name[0] == '.')
continue;
errno = 0;
l = strtol(de->d_name, &e, 10);
_dbus_assert(errno == 0 && e && !*e);
fd = (int) l;
if (fd < 3)
continue;
if (fd == dirfd(d))
continue;
_dbus_warn("file descriptor %i leaked in %s.\n", fd, __FILE__);
_dbus_assert_not_reached("fdleaks");
}
closedir(d);
}
#endif
}
static dbus_bool_t
check_have_valid_message (DBusMessageLoader *loader)
{
@ -895,7 +950,7 @@ verify_test_message (DBusMessage *message)
dbus_bool_t
_dbus_message_test (const char *test_data_dir)
{
DBusMessage *message;
DBusMessage *message, *message_without_unix_fds;
DBusMessageLoader *loader;
int i;
const char *data;
@ -940,6 +995,9 @@ _dbus_message_test (const char *test_data_dir)
unsigned char v2_BYTE;
dbus_bool_t v_BOOLEAN;
DBusMessageIter iter, array_iter, struct_iter;
#ifdef HAVE_UNIX_FD_PASSING
int v_UNIX_FD;
#endif
message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
"/org/freedesktop/TestPath",
@ -1058,6 +1116,9 @@ _dbus_message_test (const char *test_data_dir)
v_BOOLEAN = TRUE;
v_BYTE = 42;
v2_BYTE = 24;
#ifdef HAVE_UNIX_FD_PASSING
v_UNIX_FD = 1;
#endif
dbus_message_append_args (message,
DBUS_TYPE_INT16, &v_INT16,
@ -1091,6 +1152,7 @@ _dbus_message_test (const char *test_data_dir)
_DBUS_N_ELEMENTS (our_boolean_array),
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING,
_DBUS_N_ELEMENTS (our_string_array),
DBUS_TYPE_INVALID);
i = 0;
@ -1125,7 +1187,16 @@ _dbus_message_test (const char *test_data_dir)
sig[i++] = DBUS_TYPE_BOOLEAN;
sig[i++] = DBUS_TYPE_ARRAY;
sig[i++] = DBUS_TYPE_STRING;
sig[i++] = DBUS_TYPE_INVALID;
message_without_unix_fds = dbus_message_copy(message);
_dbus_assert(message_without_unix_fds);
#ifdef HAVE_UNIX_FD_PASSING
dbus_message_append_args (message,
DBUS_TYPE_UNIX_FD, &v_UNIX_FD,
DBUS_TYPE_INVALID);
sig[i++] = DBUS_TYPE_UNIX_FD;
#endif
sig[i++] = DBUS_TYPE_INVALID;
_dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig));
@ -1202,6 +1273,20 @@ _dbus_message_test (const char *test_data_dir)
_dbus_message_loader_return_buffer (loader, buffer, 1);
}
#ifdef HAVE_UNIX_FD_PASSING
{
int *unix_fds;
unsigned n_unix_fds;
/* Write unix fd */
_dbus_message_loader_get_unix_fds(loader, &unix_fds, &n_unix_fds);
_dbus_assert(n_unix_fds > 0);
_dbus_assert(message->n_unix_fds == 1);
unix_fds[0] = _dbus_dup(message->unix_fds[0], NULL);
_dbus_assert(unix_fds[0] >= 0);
_dbus_message_loader_return_unix_fds(loader, unix_fds, 1);
}
#endif
dbus_message_unref (message);
/* Now pop back the message */
@ -1218,7 +1303,14 @@ _dbus_message_test (const char *test_data_dir)
if (dbus_message_get_reply_serial (message) != 5678)
_dbus_assert_not_reached ("reply serial fields differ");
verify_test_message (message);
dbus_message_unref (message);
/* ovveride the serial, since it was reset by dbus_message_copy() */
dbus_message_set_serial(message_without_unix_fds, 8901);
dbus_message_lock (message_without_unix_fds);
verify_test_message (message_without_unix_fds);
{
/* Marshal and demarshal the message. */
@ -1229,7 +1321,7 @@ _dbus_message_test (const char *test_data_dir)
int len = 0;
char garbage_header[DBUS_MINIMUM_HEADER_SIZE] = "xxx";
if (!dbus_message_marshal (message, &marshalled, &len))
if (!dbus_message_marshal (message_without_unix_fds, &marshalled, &len))
_dbus_assert_not_reached ("failed to marshal message");
_dbus_assert (len != 0);
@ -1268,10 +1360,11 @@ _dbus_message_test (const char *test_data_dir)
_dbus_assert (dbus_message_demarshal_bytes_needed (garbage_header, DBUS_MINIMUM_HEADER_SIZE) == -1);
}
dbus_message_unref (message);
dbus_message_unref (message_without_unix_fds);
_dbus_message_loader_unref (loader);
check_memleaks ();
_dbus_check_fdleaks();
/* Check that we can abandon a container */
message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
@ -1333,9 +1426,10 @@ _dbus_message_test (const char *test_data_dir)
print_validities_seen (FALSE);
print_validities_seen (TRUE);
}
check_memleaks ();
_dbus_check_fdleaks();
/* Now load every message in test_data_dir if we have one */
if (test_data_dir == NULL)
return TRUE;

View file

@ -33,6 +33,10 @@
#include "dbus-memory.h"
#include "dbus-list.h"
#include "dbus-threads-internal.h"
#ifdef HAVE_UNIX_FD_PASSING
#include "dbus-sysdeps-unix.h"
#endif
#include <string.h>
static void dbus_message_finalize (DBusMessage *message);
@ -159,6 +163,30 @@ _dbus_message_get_network_data (DBusMessage *message,
*body = &message->body;
}
/**
* Gets the unix fds to be sent over the network for this message.
* This function is guaranteed to always return the same data once a
* message is locked (with dbus_message_lock()).
*
* @param message the message.
* @param fds return location of unix fd array
* @param n_fds return number of entries in array
*/
void _dbus_message_get_unix_fds(DBusMessage *message,
const int **fds,
unsigned *n_fds)
{
_dbus_assert (message->locked);
#ifdef HAVE_UNIX_FD_PASSING
*fds = message->unix_fds;
*n_fds = message->n_unix_fds;
#else
*fds = NULL;
*n_fds = 0;
#endif
}
/**
* Sets the serial number of a message.
* This can only be done once on a message.
@ -181,20 +209,19 @@ dbus_message_set_serial (DBusMessage *message,
}
/**
* Adds a counter to be incremented immediately with the
* size of this message, and decremented by the size
* of this message when this message if finalized.
* The link contains a counter with its refcount already
* incremented, but the counter itself not incremented.
* Ownership of link and counter refcount is passed to
* the message.
* Adds a counter to be incremented immediately with the size/unix fds
* of this message, and decremented by the size/unix fds of this
* message when this message if finalized. The link contains a
* counter with its refcount already incremented, but the counter
* itself not incremented. Ownership of link and counter refcount is
* passed to the message.
*
* @param message the message
* @param link link with counter as data
*/
void
_dbus_message_add_size_counter_link (DBusMessage *message,
DBusList *link)
_dbus_message_add_counter_link (DBusMessage *message,
DBusList *link)
{
/* right now we don't recompute the delta when message
* size changes, and that's OK for current purposes
@ -202,35 +229,43 @@ _dbus_message_add_size_counter_link (DBusMessage *message,
* Do recompute it whenever there are no outstanding counters,
* since it's basically free.
*/
if (message->size_counters == NULL)
if (message->counters == NULL)
{
message->size_counter_delta =
_dbus_string_get_length (&message->header.data) +
_dbus_string_get_length (&message->body);
#ifdef HAVE_UNIX_FD_PASSING
message->unix_fd_counter_delta = message->n_unix_fds;
#endif
#if 0
_dbus_verbose ("message has size %ld\n",
message->size_counter_delta);
#endif
}
_dbus_list_append_link (&message->size_counters, link);
_dbus_list_append_link (&message->counters, link);
_dbus_counter_adjust (link->data, message->size_counter_delta);
_dbus_counter_adjust_size (link->data, message->size_counter_delta);
#ifdef HAVE_UNIX_FD_PASSING
_dbus_counter_adjust_unix_fd (link->data, message->unix_fd_counter_delta);
#endif
}
/**
* Adds a counter to be incremented immediately with the
* size of this message, and decremented by the size
* of this message when this message if finalized.
* Adds a counter to be incremented immediately with the size/unix fds
* of this message, and decremented by the size/unix fds of this
* message when this message if finalized.
*
* @param message the message
* @param counter the counter
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_message_add_size_counter (DBusMessage *message,
DBusCounter *counter)
_dbus_message_add_counter (DBusMessage *message,
DBusCounter *counter)
{
DBusList *link;
@ -239,38 +274,42 @@ _dbus_message_add_size_counter (DBusMessage *message,
return FALSE;
_dbus_counter_ref (counter);
_dbus_message_add_size_counter_link (message, link);
_dbus_message_add_counter_link (message, link);
return TRUE;
}
/**
* Removes a counter tracking the size of this message, and decrements
* the counter by the size of this message.
* Removes a counter tracking the size/unix fds of this message, and
* decrements the counter by the size/unix fds of this message.
*
* @param message the message
* @param link_return return the link used
* @param counter the counter
*/
void
_dbus_message_remove_size_counter (DBusMessage *message,
DBusCounter *counter,
DBusList **link_return)
_dbus_message_remove_counter (DBusMessage *message,
DBusCounter *counter,
DBusList **link_return)
{
DBusList *link;
link = _dbus_list_find_last (&message->size_counters,
link = _dbus_list_find_last (&message->counters,
counter);
_dbus_assert (link != NULL);
_dbus_list_unlink (&message->size_counters,
_dbus_list_unlink (&message->counters,
link);
if (link_return)
*link_return = link;
else
_dbus_list_free_link (link);
_dbus_counter_adjust (counter, - message->size_counter_delta);
_dbus_counter_adjust_size (counter, - message->size_counter_delta);
#ifdef HAVE_UNIX_FD_PASSING
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
_dbus_counter_unref (counter);
}
@ -487,21 +526,51 @@ dbus_message_get_cached (void)
_dbus_assert (message != NULL);
_dbus_assert (message->refcount.value == 0);
_dbus_assert (message->size_counters == NULL);
_dbus_assert (message->counters == NULL);
_DBUS_UNLOCK (message_cache);
return message;
}
#ifdef HAVE_UNIX_FD_PASSING
static void
free_size_counter (void *element,
void *data)
close_unix_fds(int *fds, unsigned *n_fds)
{
DBusError e;
int i;
if (*n_fds <= 0)
return;
dbus_error_init(&e);
for (i = 0; i < *n_fds; i++)
{
if (!_dbus_close(fds[i], &e))
{
_dbus_warn("Failed to close file descriptor: %s\n", e.message);
dbus_error_free(&e);
}
}
*n_fds = 0;
/* We don't free the array here, in case we can recycle it later */
}
#endif
static void
free_counter (void *element,
void *data)
{
DBusCounter *counter = element;
DBusMessage *message = data;
_dbus_counter_adjust (counter, - message->size_counter_delta);
_dbus_counter_adjust_size (counter, - message->size_counter_delta);
#ifdef HAVE_UNIX_FD_PASSING
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
_dbus_counter_unref (counter);
}
@ -524,9 +593,13 @@ dbus_message_cache_or_finalize (DBusMessage *message)
*/
_dbus_data_slot_list_clear (&message->slot_list);
_dbus_list_foreach (&message->size_counters,
free_size_counter, message);
_dbus_list_clear (&message->size_counters);
_dbus_list_foreach (&message->counters,
free_counter, message);
_dbus_list_clear (&message->counters);
#ifdef HAVE_UNIX_FD_PASSING
close_unix_fds(message->unix_fds, &message->n_unix_fds);
#endif
was_cached = FALSE;
@ -634,6 +707,8 @@ _dbus_message_iter_check (DBusMessageRealIter *iter)
* dbus_message_get_args() is the place to go for complete
* documentation.
*
* @todo This may leak memory and file descriptors if parsing fails. See #21259
*
* @see dbus_message_get_args
* @param iter the message iter
* @param error error to be filled in
@ -673,7 +748,38 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
goto out;
}
if (dbus_type_is_basic (spec_type))
if (spec_type == DBUS_TYPE_UNIX_FD)
{
#ifdef HAVE_UNIX_FD_PASSING
DBusBasicValue idx;
int *pfd, nfd;
pfd = va_arg (var_args, int*);
_dbus_assert(pfd);
_dbus_type_reader_read_basic(&real->u.reader, &idx);
if (idx.u32 >= real->message->n_unix_fds)
{
dbus_set_error (error, DBUS_ERROR_INCONSISTENT_MESSAGE,
"Message refers to file descriptor at index %i,"
"but has only %i descriptors attached.\n",
idx.u32,
real->message->n_unix_fds);
goto out;
}
if ((nfd = _dbus_dup(real->message->unix_fds[idx.u32], error)) < 0)
goto out;
*pfd = nfd;
#else
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
"Platform does not support file desciptor passing.\n");
goto out;
#endif
}
else if (dbus_type_is_basic (spec_type))
{
DBusBasicValue *ptr;
@ -707,7 +813,8 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
goto out;
}
if (dbus_type_is_fixed (spec_element_type))
if (dbus_type_is_fixed (spec_element_type) &&
element_type != DBUS_TYPE_UNIX_FD)
{
ptr = va_arg (var_args, const DBusBasicValue**);
n_elements_p = va_arg (var_args, int*);
@ -936,13 +1043,18 @@ dbus_message_finalize (DBusMessage *message)
/* This calls application callbacks! */
_dbus_data_slot_list_free (&message->slot_list);
_dbus_list_foreach (&message->size_counters,
free_size_counter, message);
_dbus_list_clear (&message->size_counters);
_dbus_list_foreach (&message->counters,
free_counter, message);
_dbus_list_clear (&message->counters);
_dbus_header_free (&message->header);
_dbus_string_free (&message->body);
#ifdef HAVE_UNIX_FD_PASSING
close_unix_fds(message->unix_fds, &message->n_unix_fds);
dbus_free(message->unix_fds);
#endif
_dbus_assert (message->refcount.value == 0);
dbus_free (message);
@ -969,6 +1081,11 @@ dbus_message_new_empty_header (void)
#ifndef DBUS_DISABLE_CHECKS
message->generation = _dbus_current_generation;
#endif
#ifdef HAVE_UNIX_FD_PASSING
message->unix_fds = NULL;
message->n_unix_fds_allocated = 0;
#endif
}
message->refcount.value = 1;
@ -977,10 +1094,15 @@ dbus_message_new_empty_header (void)
#ifndef DBUS_DISABLE_CHECKS
message->in_cache = FALSE;
#endif
message->size_counters = NULL;
message->counters = NULL;
message->size_counter_delta = 0;
message->changed_stamp = 0;
#ifdef HAVE_UNIX_FD_PASSING
message->n_unix_fds = 0;
message->unix_fd_counter_delta = 0;
#endif
if (!from_cache)
_dbus_data_slot_list_init (&message->slot_list);
@ -1308,8 +1430,10 @@ dbus_message_new_error_printf (DBusMessage *reply_to,
* outgoing message queue and thus not modifiable) the new message
* will not be locked.
*
* @todo This function can't be used in programs that try to recover from OOM errors.
*
* @param message the message
* @returns the new message.or #NULL if not enough memory
* @returns the new message.or #NULL if not enough memory or Unix file descriptors (in case the message to copy includes Unix file descriptors) can be allocated.
*/
DBusMessage *
dbus_message_copy (const DBusMessage *message)
@ -1347,11 +1471,36 @@ dbus_message_copy (const DBusMessage *message)
&retval->body, 0))
goto failed_copy;
#ifdef HAVE_UNIX_FD_PASSING
retval->unix_fds = dbus_new(int, message->n_unix_fds);
if (retval->unix_fds == NULL && message->n_unix_fds > 0)
goto failed_copy;
retval->n_unix_fds_allocated = message->n_unix_fds;
for (retval->n_unix_fds = 0;
retval->n_unix_fds < message->n_unix_fds;
retval->n_unix_fds++)
{
retval->unix_fds[retval->n_unix_fds] = _dbus_dup(message->unix_fds[retval->n_unix_fds], NULL);
if (retval->unix_fds[retval->n_unix_fds] < 0)
goto failed_copy;
}
#endif
return retval;
failed_copy:
_dbus_header_free (&retval->header);
_dbus_string_free (&retval->body);
#ifdef HAVE_UNIX_FD_PASSING
close_unix_fds(retval->unix_fds, &retval->n_unix_fds);
dbus_free(retval->unix_fds);
#endif
dbus_free (retval);
return NULL;
@ -1429,9 +1578,10 @@ dbus_message_get_type (DBusMessage *message)
* Appends fields to a message given a variable argument list. The
* variable argument list should contain the type of each argument
* followed by the value to append. Appendable types are basic types,
* and arrays of fixed-length basic types. To append variable-length
* basic types, or any more complex value, you have to use an iterator
* rather than this function.
* and arrays of fixed-length basic types (except arrays of Unix file
* descriptors). To append variable-length basic types, or any more
* complex value, you have to use an iterator rather than this
* function.
*
* To append a basic type, specify its type code followed by the
* address of the value. For example:
@ -1446,18 +1596,22 @@ dbus_message_get_type (DBusMessage *message)
* DBUS_TYPE_INVALID);
* @endcode
*
* To append an array of fixed-length basic types, pass in the
* DBUS_TYPE_ARRAY typecode, the element typecode, the address of
* the array pointer, and a 32-bit integer giving the number of
* elements in the array. So for example:
* @code
* const dbus_int32_t array[] = { 1, 2, 3 };
* const dbus_int32_t *v_ARRAY = array;
* dbus_message_append_args (message,
* DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3,
* DBUS_TYPE_INVALID);
* To append an array of fixed-length basic types (except Unix file
* descriptors), pass in the DBUS_TYPE_ARRAY typecode, the element
* typecode, the address of the array pointer, and a 32-bit integer
* giving the number of elements in the array. So for example: @code
* const dbus_int32_t array[] = { 1, 2, 3 }; const dbus_int32_t
* *v_ARRAY = array; dbus_message_append_args (message,
* DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3, DBUS_TYPE_INVALID);
* @endcode
*
* This function does not support arrays of Unix file descriptors. If
* you need those you need to manually recurse into the array.
*
* For Unix file descriptors this function will internally duplicate
* the descriptor you passed in. Hence you may close the descriptor
* immediately after this call.
*
* @warning in C, given "int array[]", "&array == array" (the
* comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree).
* So if you're using an array instead of a pointer you have to create
@ -1555,8 +1709,9 @@ dbus_message_append_args_valist (DBusMessage *message,
buf,
&array))
goto failed;
if (dbus_type_is_fixed (element_type))
if (dbus_type_is_fixed (element_type) &&
element_type != DBUS_TYPE_UNIX_FD)
{
const DBusBasicValue **value;
int n_elements;
@ -1639,7 +1794,16 @@ dbus_message_append_args_valist (DBusMessage *message,
* signature are supported; but these are returned as allocated memory
* and must be freed with dbus_free_string_array(), while the other
* types are returned as const references. To get a string array
* pass in "char ***array_location" and "int *n_elements"
* pass in "char ***array_location" and "int *n_elements".
*
* Similar to dbus_message_get_fixed_array() this function does not
* support arrays of type DBUS_TYPE_UNIX_FD. If you need to parse
* messages with arrays of Unix file descriptors you need to recurse
* into the array manually.
*
* Unix file descriptors that are read with this function will have
* the FD_CLOEXEC flag set. If you need them without this flag set,
* make sure to unset it with fcntl().
*
* The variable argument list should contain the type of the argument
* followed by a pointer to where the value should be stored. The list
@ -1864,10 +2028,10 @@ dbus_message_iter_get_element_type (DBusMessageIter *iter)
* you won't be able to recurse further. There's no array of int32 to
* recurse into.
*
* If a container is an array of fixed-length types, it is much more
* efficient to use dbus_message_iter_get_fixed_array() to get the
* whole array in one shot, rather than individually walking over the
* array elements.
* If a container is an array of fixed-length types (except Unix file
* descriptors), it is much more efficient to use
* dbus_message_iter_get_fixed_array() to get the whole array in one
* shot, rather than individually walking over the array elements.
*
* Be sure you have somehow checked that
* dbus_message_iter_get_arg_type() matches the type you are expecting
@ -1937,17 +2101,24 @@ dbus_message_iter_get_signature (DBusMessageIter *iter)
* and for string a "const char**". The returned value is
* by reference and should not be freed.
*
* This call duplicates Unix file descriptors when reading them. It is
* your job to close them when you don't need them anymore.
*
* Unix file descriptors that are read with this function will have
* the FD_CLOEXEC flag set. If you need them without this flag set,
* make sure to unset it with fcntl().
*
* Be sure you have somehow checked that
* dbus_message_iter_get_arg_type() matches the type you are
* expecting, or you'll crash when you try to use an integer as a
* string or something.
*
* To read any container type (array, struct, dict) you will need
* to recurse into the container with dbus_message_iter_recurse().
* If the container is an array of fixed-length values, you can
* get all the array elements at once with
* dbus_message_iter_get_fixed_array(). Otherwise, you have to
* iterate over the container's contents one value at a time.
* To read any container type (array, struct, dict) you will need to
* recurse into the container with dbus_message_iter_recurse(). If
* the container is an array of fixed-length values (except Unix file
* descriptors), you can get all the array elements at once with
* dbus_message_iter_get_fixed_array(). Otherwise, you have to iterate
* over the container's contents one value at a time.
*
* All basic-typed values are guaranteed to fit in 8 bytes. So you can
* write code like this:
@ -1977,8 +2148,30 @@ dbus_message_iter_get_basic (DBusMessageIter *iter,
_dbus_return_if_fail (_dbus_message_iter_check (real));
_dbus_return_if_fail (value != NULL);
_dbus_type_reader_read_basic (&real->u.reader,
value);
if (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_UNIX_FD)
{
#ifdef HAVE_UNIX_FD_PASSING
DBusBasicValue idx;
_dbus_type_reader_read_basic(&real->u.reader, &idx);
if (idx.u32 >= real->message->n_unix_fds) {
/* Hmm, we cannot really signal an error here, so let's make
sure to return an invalid fd. */
*((int*) value) = -1;
return;
}
*((int*) value) = _dbus_dup(real->message->unix_fds[idx.u32], NULL);
#else
*((int*) value) = -1;
#endif
}
else
{
_dbus_type_reader_read_basic (&real->u.reader,
value);
}
}
/**
@ -2015,6 +2208,10 @@ dbus_message_iter_get_array_len (DBusMessageIter *iter)
* such as integers, bool, double. The returned block will be from the
* current position in the array until the end of the array.
*
* There is one exception here: although DBUS_TYPE_UNIX_FD is
* considered a 'fixed' type arrays of this type may not be read with
* this function.
*
* The message iter should be "in" the array (that is, you recurse into the
* array, and then you call dbus_message_iter_get_fixed_array() on the
* "sub-iterator" created by dbus_message_iter_recurse()).
@ -2051,7 +2248,7 @@ dbus_message_iter_get_fixed_array (DBusMessageIter *iter,
_dbus_return_if_fail (_dbus_message_iter_check (real));
_dbus_return_if_fail (value != NULL);
_dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) ||
dbus_type_is_fixed (subtype));
(dbus_type_is_fixed (subtype) && subtype != DBUS_TYPE_UNIX_FD));
_dbus_type_reader_read_fixed_multi (&real->u.reader,
value, n_elements);
@ -2250,6 +2447,40 @@ _dbus_message_iter_append_check (DBusMessageRealIter *iter)
}
#endif /* DBUS_DISABLE_CHECKS */
#ifdef HAVE_UNIX_FD_PASSING
static int *
expand_fd_array(DBusMessage *m,
unsigned n)
{
_dbus_assert(m);
/* This makes space for adding n new fds to the array and returns a
pointer to the place were the first fd should be put. */
if (m->n_unix_fds + n > m->n_unix_fds_allocated)
{
unsigned k;
int *p;
/* Make twice as much space as necessary */
k = (m->n_unix_fds + n) * 2;
/* Allocate at least four */
if (k < 4)
k = 4;
p = dbus_realloc(m->unix_fds, k * sizeof(int));
if (p == NULL)
return NULL;
m->unix_fds = p;
m->n_unix_fds_allocated = k;
}
return m->unix_fds + m->n_unix_fds;
}
#endif
/**
* Appends a basic-typed value to the message. The basic types are the
* non-container types such as integer and string.
@ -2257,6 +2488,10 @@ _dbus_message_iter_append_check (DBusMessageRealIter *iter)
* The "value" argument should be the address of a basic-typed value.
* So for string, const char**. For integer, dbus_int32_t*.
*
* For Unix file descriptors this function will internally duplicate
* the descriptor you passed in. Hence you may close the descriptor
* immediately after this call.
*
* @todo If this fails due to lack of memory, the message is hosed and
* you have to start over building the whole message.
*
@ -2281,7 +2516,50 @@ dbus_message_iter_append_basic (DBusMessageIter *iter,
if (!_dbus_message_iter_open_signature (real))
return FALSE;
ret = _dbus_type_writer_write_basic (&real->u.writer, type, value);
if (type == DBUS_TYPE_UNIX_FD)
{
#ifdef HAVE_UNIX_FD_PASSING
int *fds;
dbus_uint32_t u;
/* First step, include the fd in the fd list of this message */
if (!(fds = expand_fd_array(real->message, 1)))
return FALSE;
*fds = _dbus_dup(*(int*) value, NULL);
if (*fds < 0)
return FALSE;
u = real->message->n_unix_fds;
/* Second step, write the index to the fd */
if (!(ret = _dbus_type_writer_write_basic (&real->u.writer, DBUS_TYPE_UNIX_FD, &u))) {
_dbus_close(*fds, NULL);
return FALSE;
}
real->message->n_unix_fds += 1;
u += 1;
/* Final step, update the header accordingly */
ret = _dbus_header_set_field_basic (&real->message->header,
DBUS_HEADER_FIELD_UNIX_FDS,
DBUS_TYPE_UINT32,
&u);
/* If any of these operations fail the message is
hosed. However, no memory or fds should be leaked since what
has been added to message has been added to the message, and
can hence be accounted for when the message is being
freed. */
#else
ret = FALSE;
#endif
}
else
{
ret = _dbus_type_writer_write_basic (&real->u.writer, type, value);
}
if (!_dbus_message_iter_close_signature (real))
ret = FALSE;
@ -2292,10 +2570,10 @@ dbus_message_iter_append_basic (DBusMessageIter *iter,
/**
* Appends a block of fixed-length values to an array. The
* fixed-length types are all basic types that are not string-like. So
* int32, double, bool, etc. You must call
* dbus_message_iter_open_container() to open an array of values
* before calling this function. You may call this function multiple
* times (and intermixed with calls to
* int32, double, bool, etc. (Unix file descriptors however are not
* supported.) You must call dbus_message_iter_open_container() to
* open an array of values before calling this function. You may call
* this function multiple times (and intermixed with calls to
* dbus_message_iter_append_basic()) for the same array.
*
* The "value" argument should be the address of the array. So for
@ -2318,6 +2596,10 @@ dbus_message_iter_append_basic (DBusMessageIter *iter,
* @todo If this fails due to lack of memory, the message is hosed and
* you have to start over building the whole message.
*
* For Unix file descriptors this function will internally duplicate
* the descriptor you passed in. Hence you may close the descriptor
* immediately after this call.
*
* @param iter the append iterator
* @param element_type the type of the array elements
* @param value the address of the array
@ -2335,7 +2617,7 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter,
_dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE);
_dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE);
_dbus_return_val_if_fail (dbus_type_is_fixed (element_type), FALSE);
_dbus_return_val_if_fail (dbus_type_is_fixed (element_type) && element_type != DBUS_TYPE_UNIX_FD, FALSE);
_dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE);
_dbus_return_val_if_fail (value != NULL, FALSE);
_dbus_return_val_if_fail (n_elements >= 0, FALSE);
@ -3337,6 +3619,20 @@ dbus_set_error_from_message (DBusError *error,
return TRUE;
}
/**
* Checks whether a message contains unix fds
*
* @param message the message
* @returns #TRUE if the message contains unix fds
*/
dbus_bool_t
dbus_message_contains_unix_fds(DBusMessage *message)
{
_dbus_assert(message);
return message->n_unix_fds > 0;
}
/** @} */
/**
@ -3380,6 +3676,12 @@ _dbus_message_loader_new (void)
/* this can be configured by the app, but defaults to the protocol max */
loader->max_message_size = DBUS_MAXIMUM_MESSAGE_LENGTH;
/* We set a very relatively conservative default here since due to how
SCM_RIGHTS works we need to preallocate an fd array of the maximum
number of unix fds we want to receive in advance. A
try-and-reallocate loop is not possible. */
loader->max_message_unix_fds = 1024;
if (!_dbus_string_init (&loader->data))
{
dbus_free (loader);
@ -3390,6 +3692,12 @@ _dbus_message_loader_new (void)
_dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
_dbus_string_set_length (&loader->data, 0);
#ifdef HAVE_UNIX_FD_PASSING
loader->unix_fds = NULL;
loader->n_unix_fds = loader->n_unix_fds_allocated = 0;
loader->unix_fds_outstanding = FALSE;
#endif
return loader;
}
@ -3419,6 +3727,10 @@ _dbus_message_loader_unref (DBusMessageLoader *loader)
loader->refcount -= 1;
if (loader->refcount == 0)
{
#ifdef HAVE_UNIX_FD_PASSING
close_unix_fds(loader->unix_fds, &loader->n_unix_fds);
dbus_free(loader->unix_fds);
#endif
_dbus_list_foreach (&loader->messages,
(DBusForeachFunction) dbus_message_unref,
NULL);
@ -3478,6 +3790,81 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
loader->buffer_outstanding = FALSE;
}
/**
* Gets the buffer to use for reading unix fds from the network.
*
* This works similar to _dbus_message_loader_get_buffer()
*
* @param loader the message loader.
* @param fds the array to read fds into
* @param max_n_fds how many fds to read at most
* @return TRUE on success, FALSE on OOM
*/
dbus_bool_t
_dbus_message_loader_get_unix_fds(DBusMessageLoader *loader,
int **fds,
unsigned *max_n_fds)
{
#ifdef HAVE_UNIX_FD_PASSING
_dbus_assert (!loader->unix_fds_outstanding);
/* Allocate space where we can put the fds we read. We allocate
space for max_message_unix_fds since this is an
upper limit how many fds can be received within a single
message. Since SCM_RIGHTS doesn't allow a reallocate+retry logic
we are allocating the maximum possible array size right from the
beginning. This sucks a bit, however unless SCM_RIGHTS is fixed
there is no better way. */
if (loader->n_unix_fds_allocated < loader->max_message_unix_fds)
{
int *a = dbus_realloc(loader->unix_fds,
loader->max_message_unix_fds * sizeof(loader->unix_fds[0]));
if (!a)
return FALSE;
loader->unix_fds = a;
loader->n_unix_fds_allocated = loader->max_message_unix_fds;
}
*fds = loader->unix_fds + loader->n_unix_fds;
*max_n_fds = loader->n_unix_fds_allocated - loader->n_unix_fds;
loader->unix_fds_outstanding = TRUE;
return TRUE;
#else
_dbus_assert_not_reached("Platform doesn't support unix fd passing");
#endif
}
/**
* Returns a buffer obtained from _dbus_message_loader_get_unix_fds().
*
* This works similar to _dbus_message_loader_return_buffer()
*
* @param loader the message loader.
* @param fds the array fds were read into
* @param max_n_fds how many fds were read
*/
void
_dbus_message_loader_return_unix_fds(DBusMessageLoader *loader,
int *fds,
unsigned n_fds)
{
#ifdef HAVE_UNIX_FD_PASSING
_dbus_assert(loader->unix_fds_outstanding);
_dbus_assert(loader->unix_fds + loader->n_unix_fds == fds);
_dbus_assert(loader->n_unix_fds + n_fds <= loader->n_unix_fds_allocated);
loader->n_unix_fds += n_fds;
loader->unix_fds_outstanding = FALSE;
#else
_dbus_assert_not_reached("Platform doesn't support unix fd passing");
#endif
}
/*
* FIXME when we move the header out of the buffer, that memmoves all
* buffered messages. Kind of crappy.
@ -3517,6 +3904,7 @@ load_message (DBusMessageLoader *loader,
const DBusString *type_str;
int type_pos;
DBusValidationMode mode;
dbus_uint32_t n_unix_fds = 0;
mode = DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED;
@ -3586,6 +3974,59 @@ load_message (DBusMessageLoader *loader,
}
}
/* 3. COPY OVER UNIX FDS */
_dbus_header_get_field_basic(&message->header,
DBUS_HEADER_FIELD_UNIX_FDS,
DBUS_TYPE_UINT32,
&n_unix_fds);
#ifdef HAVE_UNIX_FD_PASSING
if (n_unix_fds > loader->n_unix_fds)
{
_dbus_verbose("Message contains references to more unix fds than were sent %u != %u\n",
n_unix_fds, loader->n_unix_fds);
loader->corrupted = TRUE;
loader->corruption_reason = DBUS_INVALID_MISSING_UNIX_FDS;
goto failed;
}
/* If this was a recycled message there might still be
some memory allocated for the fds */
dbus_free(message->unix_fds);
if (n_unix_fds > 0)
{
message->unix_fds = _dbus_memdup(loader->unix_fds, n_unix_fds * sizeof(message->unix_fds[0]));
if (message->unix_fds == NULL)
{
_dbus_verbose ("Failed to allocate file descriptor array\n");
oom = TRUE;
goto failed;
}
message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds;
loader->n_unix_fds -= n_unix_fds;
memmove(loader->unix_fds + n_unix_fds, loader->unix_fds, loader->n_unix_fds);
}
else
message->unix_fds = NULL;
#else
if (n_unix_fds > 0)
{
_dbus_verbose ("Hmm, message claims to come with file descriptors "
"but that's not supported on our platform, disconnecting.\n");
loader->corrupted = TRUE;
loader->corruption_reason = DBUS_INVALID_MISSING_UNIX_FDS;
goto failed;
}
#endif
/* 3. COPY OVER BODY AND QUEUE MESSAGE */
if (!_dbus_list_append (&loader->messages, message))
@ -3815,6 +4256,37 @@ _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader)
return loader->max_message_size;
}
/**
* Sets the maximum unix fds per message we allow.
*
* @param loader the loader
* @param size the max number of unix fds in a message
*/
void
_dbus_message_loader_set_max_message_unix_fds (DBusMessageLoader *loader,
long n)
{
if (n > DBUS_MAXIMUM_MESSAGE_UNIX_FDS)
{
_dbus_verbose ("clamping requested max message unix_fds %ld to %d\n",
n, DBUS_MAXIMUM_MESSAGE_UNIX_FDS);
n = DBUS_MAXIMUM_MESSAGE_UNIX_FDS;
}
loader->max_message_unix_fds = n;
}
/**
* Gets the maximum allowed number of unix fds per message
*
* @param loader the loader
* @returns max unix fds
*/
long
_dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader *loader)
{
return loader->max_message_unix_fds;
}
static DBusDataSlotAllocator slot_allocator;
_DBUS_DEFINE_GLOBAL_LOCK (message_slots);

View file

@ -159,6 +159,7 @@ dbus_bool_t dbus_message_get_args_valist (DBusMessage *message,
int first_arg_type,
va_list var_args);
dbus_bool_t dbus_message_contains_unix_fds (DBusMessage *message);
dbus_bool_t dbus_message_iter_init (DBusMessage *message,
DBusMessageIter *iter);

View file

@ -110,6 +110,10 @@ extern "C" {
#define DBUS_TYPE_SIGNATURE ((int) 'g')
/** #DBUS_TYPE_SIGNATURE as a string literal instead of a int literal */
#define DBUS_TYPE_SIGNATURE_AS_STRING "g"
/** Type code marking a unix file descriptor */
#define DBUS_TYPE_UNIX_FD ((int) 'h')
/** #DBUS_TYPE_UNIX_FD as a string literal instead of a int literal */
#define DBUS_TYPE_UNIX_FD_AS_STRING "h"
/* Compound types */
/** Type code marking a D-Bus array type */
@ -207,6 +211,14 @@ extern "C" {
/** Number of bits you need in an unsigned to store the max message size */
#define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27
/** The maximum total number of unix fds in a message. Similar
* rationale as DBUS_MAXIMUM_MESSAGE_LENGTH. However we divide by four
* given that one fd is an int and hence at least 32 bits.
*/
#define DBUS_MAXIMUM_MESSAGE_UNIX_FDS (DBUS_MAXIMUM_MESSAGE_LENGTH/4)
/** Number of bits you need in an unsigned to store the max message unix fds */
#define DBUS_MAXIMUM_MESSAGE_UNIX_FDS_BITS (DBUS_MAXIMUM_MESSAGE_LENGTH_BITS-2)
/** Depth of recursion in the type tree. This is automatically limited
* to DBUS_MAXIMUM_SIGNATURE_LENGTH since you could only have an array
* of array of array of ... that fit in the max signature. But that's
@ -276,6 +288,12 @@ extern "C" {
* Header field code for the type signature of a message.
*/
#define DBUS_HEADER_FIELD_SIGNATURE 8
/**
* Header field code for the number of unix file descriptors associated
* with this message.
*/
#define DBUS_HEADER_FIELD_UNIX_FDS 9
/**
* Value of the highest-numbered header field code, can be used to determine
@ -283,7 +301,7 @@ extern "C" {
* that unknown codes must be ignored, so check for that before
* indexing the array.
*/
#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SIGNATURE
#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_UNIX_FDS
/** Header format is defined as a signature:
* byte byte order
@ -415,6 +433,9 @@ extern "C" {
#define DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN "org.freedesktop.DBus.Error.AdtAuditDataUnknown"
/** There's already an object with the requested object path. */
#define DBUS_ERROR_OBJECT_PATH_IN_USE "org.freedesktop.DBus.Error.ObjectPathInUse"
/** The message meta data does not match the payload. e.g. expected
number of file descriptors were not sent over the socket this message was received on. */
#define DBUS_ERROR_INCONSISTENT_MESSAGE "org.freedesktop.DBus.Error.InconsistentMessage"
/* XML introspection format */

View file

@ -29,7 +29,7 @@
* @brief DBusCounter and other stuff related to resource limits
*
* Types and functions related to tracking resource limits,
* such as the maximum amount of memory a connection can use
* such as the maximum amount of memory/unix fds a connection can use
* for messages, etc.
*/
@ -53,9 +53,12 @@ struct DBusCounter
{
int refcount; /**< reference count */
long value; /**< current counter value */
long size_value; /**< current size counter value */
long unix_fd_value; /**< current unix fd counter value */
long notify_size_guard_value; /**< call notify function when crossing this size value */
long notify_unix_fd_guard_value; /**< call notify function when crossing this unix fd value */
long notify_guard_value; /**< call notify function when crossing this value */
DBusCounterNotifyFunction notify_function; /**< notify function */
void *notify_data; /**< data for notify function */
};
@ -83,9 +86,11 @@ _dbus_counter_new (void)
return NULL;
counter->refcount = 1;
counter->value = 0;
counter->size_value = 0;
counter->unix_fd_value = 0;
counter->notify_guard_value = 0;
counter->notify_size_guard_value = 0;
counter->notify_unix_fd_guard_value = 0;
counter->notify_function = NULL;
counter->notify_data = NULL;
@ -129,64 +134,109 @@ _dbus_counter_unref (DBusCounter *counter)
}
/**
* Adjusts the value of the counter by the given
* Adjusts the value of the size counter by the given
* delta which may be positive or negative.
* Calls the notify function from _dbus_counter_set_notify()
* if that function has been specified.
*
* @param counter the counter
* @param delta value to add to the counter's current value
* @param delta value to add to the size counter's current value
*/
void
_dbus_counter_adjust (DBusCounter *counter,
long delta)
_dbus_counter_adjust_size (DBusCounter *counter,
long delta)
{
long old = counter->value;
counter->value += delta;
long old = counter->size_value;
counter->size_value += delta;
#if 0
_dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
old, delta, counter->value);
old, delta, counter->size_value);
#endif
if (counter->notify_function != NULL &&
((old < counter->notify_guard_value &&
counter->value >= counter->notify_guard_value) ||
(old >= counter->notify_guard_value &&
counter->value < counter->notify_guard_value)))
((old < counter->notify_size_guard_value &&
counter->size_value >= counter->notify_size_guard_value) ||
(old >= counter->notify_size_guard_value &&
counter->size_value < counter->notify_size_guard_value)))
(* counter->notify_function) (counter, counter->notify_data);
}
/**
* Gets the current value of the counter.
* Adjusts the value of the unix fd counter by the given
* delta which may be positive or negative.
* Calls the notify function from _dbus_counter_set_notify()
* if that function has been specified.
*
* @param counter the counter
* @returns its current value
* @param delta value to add to the unix fds counter's current value
*/
void
_dbus_counter_adjust_unix_fd (DBusCounter *counter,
long delta)
{
long old = counter->unix_fd_value;
counter->unix_fd_value += delta;
#if 0
_dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
old, delta, counter->unix_fd_value);
#endif
if (counter->notify_function != NULL &&
((old < counter->notify_unix_fd_guard_value &&
counter->unix_fd_value >= counter->notify_unix_fd_guard_value) ||
(old >= counter->notify_unix_fd_guard_value &&
counter->unix_fd_value < counter->notify_unix_fd_guard_value)))
(* counter->notify_function) (counter, counter->notify_data);
}
/**
* Gets the current value of the size counter.
*
* @param counter the counter
* @returns its current size value
*/
long
_dbus_counter_get_value (DBusCounter *counter)
_dbus_counter_get_size_value (DBusCounter *counter)
{
return counter->value;
return counter->size_value;
}
/**
* Gets the current value of the unix fd counter.
*
* @param counter the counter
* @returns its current unix fd value
*/
long
_dbus_counter_get_unix_fd_value (DBusCounter *counter)
{
return counter->unix_fd_value;
}
/**
* Sets the notify function for this counter; the notify function is
* called whenever the counter's value crosses the guard value in
* called whenever the counter's values cross the guard values in
* either direction (moving up, or moving down).
*
* @param counter the counter
* @param guard_value the value we're notified if the counter crosses
* @param size_guard_value the value we're notified if the size counter crosses
* @param unix_fd_guard_value the value we're notified if the unix fd counter crosses
* @param function function to call in order to notify
* @param user_data data to pass to the function
*/
void
_dbus_counter_set_notify (DBusCounter *counter,
long guard_value,
long size_guard_value,
long unix_fd_guard_value,
DBusCounterNotifyFunction function,
void *user_data)
{
counter->notify_guard_value = guard_value;
counter->notify_size_guard_value = size_guard_value;
counter->notify_unix_fd_guard_value = unix_fd_guard_value;
counter->notify_function = function;
counter->notify_data = user_data;
}

View file

@ -37,14 +37,19 @@ typedef void (* DBusCounterNotifyFunction) (DBusCounter *counter,
DBusCounter* _dbus_counter_new (void);
DBusCounter* _dbus_counter_ref (DBusCounter *counter);
void _dbus_counter_unref (DBusCounter *counter);
void _dbus_counter_adjust (DBusCounter *counter,
long delta);
long _dbus_counter_get_value (DBusCounter *counter);
void _dbus_counter_set_notify (DBusCounter *counter,
long guard_value,
DBusCounterNotifyFunction function,
void *user_data);
void _dbus_counter_adjust_size (DBusCounter *counter,
long delta);
void _dbus_counter_adjust_unix_fd (DBusCounter *counter,
long delta);
long _dbus_counter_get_size_value (DBusCounter *counter);
long _dbus_counter_get_unix_fd_value (DBusCounter *counter);
void _dbus_counter_set_notify (DBusCounter *counter,
long size_guard_value,
long unix_fd_guard_value,
DBusCounterNotifyFunction function,
void *user_data);
DBUS_END_DECLS

View file

@ -253,9 +253,6 @@ _dbus_transport_debug_pipe_new (const char *server_name,
return NULL;
}
_dbus_fd_set_close_on_exec (client_fd);
_dbus_fd_set_close_on_exec (server_fd);
client_transport = _dbus_transport_new_for_socket (client_fd,
NULL, &address);
if (client_transport == NULL)

View file

@ -195,8 +195,6 @@ socket_handle_watch (DBusWatch *watch,
}
else
{
_dbus_fd_set_close_on_exec (client_fd);
if (!handle_new_client_fd_and_unlock (server, client_fd))
_dbus_verbose ("Rejected client connection due to lack of memory\n");
}
@ -413,9 +411,6 @@ _dbus_server_new_for_tcp_socket (const char *host,
goto failed_1;
}
for (i = 0 ; i < nlisten_fds ; i++)
_dbus_fd_set_close_on_exec (listen_fds[i]);
_dbus_string_init_const (&host_str, host);
if (!_dbus_string_append (&address, "tcp:host=") ||
!_dbus_address_append_escaped (&address, &host_str) ||

View file

@ -201,8 +201,7 @@ _dbus_server_new_for_domain_socket (const char *path,
}
listen_fd = _dbus_listen_unix_socket (path, abstract, error);
_dbus_fd_set_close_on_exec (listen_fd);
if (listen_fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);

View file

@ -465,7 +465,7 @@ _dbus_sha_final (DBusSHAContext *context,
/* some kind of security paranoia, though it seems pointless
* to me given the nonzeroed stuff flying around
*/
memset ((void*)context, '\0', sizeof (DBusSHAContext));
_DBUS_ZERO(*context);
return TRUE;
}

View file

@ -355,6 +355,7 @@ dbus_type_is_fixed (int typecode)
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_UNIX_FD:
return TRUE;
default:
return FALSE;

View file

@ -21,6 +21,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <config.h>
#include "dbus-spawn.h"
#include "dbus-sysdeps-unix.h"
#include "dbus-internals.h"
@ -805,9 +808,25 @@ static dbus_bool_t
make_pipe (int p[2],
DBusError *error)
{
int retval;
#ifdef HAVE_PIPE2
dbus_bool_t cloexec_done;
retval = pipe2 (p, O_CLOEXEC);
cloexec_done = retval >= 0;
/* Check if kernel seems to be too old to know pipe2(). We assume
that if pipe2 is available, O_CLOEXEC is too. */
if (retval < 0 && errno == ENOSYS)
#endif
{
retval = pipe(p);
}
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (pipe (p) < 0)
if (retval < 0)
{
dbus_set_error (error,
DBUS_ERROR_SPAWN_FAILED,
@ -816,6 +835,14 @@ make_pipe (int p[2],
return FALSE;
}
#ifdef HAVE_PIPE2
if (!cloexec_done)
#endif
{
_dbus_fd_set_close_on_exec (p[0]);
_dbus_fd_set_close_on_exec (p[1]);
}
return TRUE;
}
@ -1117,15 +1144,9 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
if (!make_pipe (child_err_report_pipe, error))
goto cleanup_and_fail;
_dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
_dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);
if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
goto cleanup_and_fail;
_dbus_fd_set_close_on_exec (babysitter_pipe[0]);
_dbus_fd_set_close_on_exec (babysitter_pipe[1]);
/* Setting up the babysitter is only useful in the parent,
* but we don't want to run out of memory and fail
* after we've already forked, since then we'd leak

View file

@ -22,7 +22,7 @@
*
*/
#define _GNU_SOURCE
#include <config.h>
#include "dbus-internals.h"
#include "dbus-sysdeps.h"
@ -94,9 +94,28 @@ _dbus_open_socket (int *fd_p,
int protocol,
DBusError *error)
{
*fd_p = socket (domain, type, protocol);
#ifdef SOCK_CLOEXEC
dbus_bool_t cloexec_done;
*fd_p = socket (domain, type | SOCK_CLOEXEC, protocol);
cloexec_done = *fd_p >= 0;
/* Check if kernel seems to be too old to know SOCK_CLOEXEC */
if (*fd_p < 0 && errno == EINVAL)
#endif
{
*fd_p = socket (domain, type, protocol);
}
if (*fd_p >= 0)
{
#ifdef SOCK_CLOEXEC
if (!cloexec_done)
#endif
{
_dbus_fd_set_close_on_exec(*fd_p);
}
_dbus_verbose ("socket fd %d opened\n", *fd_p);
return TRUE;
}
@ -120,6 +139,9 @@ _dbus_open_tcp_socket (int *fd,
/**
* Opens a UNIX domain socket (as in the socket() call).
* Does not bind the socket.
*
* This will set FD_CLOEXEC for the socket returned
*
* @param fd return location for socket descriptor
* @param error return location for an error
* @returns #FALSE if error is set
@ -179,7 +201,259 @@ _dbus_write_socket (int fd,
int start,
int len)
{
#ifdef MSG_NOSIGNAL
const char *data;
int bytes_written;
data = _dbus_string_get_const_data_len (buffer, start, len);
again:
bytes_written = send (fd, data, len, MSG_NOSIGNAL);
if (bytes_written < 0 && errno == EINTR)
goto again;
return bytes_written;
#else
return _dbus_write (fd, buffer, start, len);
#endif
}
/**
* Like _dbus_read_socket() but also tries to read unix fds from the
* socket. When there are more fds to read than space in the array
* passed this function will fail with ENOSPC.
*
* @param fd the socket
* @param buffer string to append data to
* @param count max amount of data to read
* @param fds array to place read file descriptors in
* @param n_fds on input space in fds array, on output how many fds actually got read
* @returns number of bytes appended to string
*/
int
_dbus_read_socket_with_unix_fds (int fd,
DBusString *buffer,
int count,
int *fds,
int *n_fds) {
#ifndef HAVE_UNIX_FD_PASSING
int r;
if ((r = _dbus_read_socket(fd, buffer, count)) < 0)
return r;
*n_fds = 0;
return r;
#else
int bytes_read;
int start;
struct msghdr m;
struct iovec iov;
_dbus_assert (count >= 0);
_dbus_assert (*n_fds >= 0);
start = _dbus_string_get_length (buffer);
if (!_dbus_string_lengthen (buffer, count))
{
errno = ENOMEM;
return -1;
}
_DBUS_ZERO(iov);
iov.iov_base = _dbus_string_get_data_len (buffer, start, count);
iov.iov_len = count;
_DBUS_ZERO(m);
m.msg_iov = &iov;
m.msg_iovlen = 1;
/* Hmm, we have no clue how long the control data will actually be
that is queued for us. The least we can do is assume that the
caller knows. Hence let's make space for the number of fds that
we shall read at max plus the cmsg header. */
m.msg_controllen = CMSG_SPACE(*n_fds * sizeof(int));
/* It's probably safe to assume that systems with SCM_RIGHTS also
know alloca() */
m.msg_control = alloca(m.msg_controllen);
memset(m.msg_control, 0, m.msg_controllen);
again:
bytes_read = recvmsg(fd, &m, 0
#ifdef MSG_CMSG_CLOEXEC
|MSG_CMSG_CLOEXEC
#endif
);
if (bytes_read < 0)
{
if (errno == EINTR)
goto again;
else
{
/* put length back (note that this doesn't actually realloc anything) */
_dbus_string_set_length (buffer, start);
return -1;
}
}
else
{
struct cmsghdr *cm;
dbus_bool_t found = FALSE;
if (m.msg_flags & MSG_CTRUNC)
{
/* Hmm, apparently the control data was truncated. The bad
thing is that we might have completely lost a couple of fds
without chance to recover them. Hence let's treat this as a
serious error. */
errno = ENOSPC;
_dbus_string_set_length (buffer, start);
return -1;
}
for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS)
{
unsigned i;
_dbus_assert(cm->cmsg_len <= CMSG_LEN(*n_fds * sizeof(int)));
*n_fds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int);
memcpy(fds, CMSG_DATA(cm), *n_fds * sizeof(int));
found = TRUE;
/* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually
worked, hence we need to go through this list and set
CLOEXEC everywhere in any case */
for (i = 0; i < *n_fds; i++)
_dbus_fd_set_close_on_exec(fds[i]);
break;
}
if (!found)
*n_fds = 0;
/* put length back (doesn't actually realloc) */
_dbus_string_set_length (buffer, start + bytes_read);
#if 0
if (bytes_read > 0)
_dbus_verbose_bytes_of_string (buffer, start, bytes_read);
#endif
return bytes_read;
}
#endif
}
int
_dbus_write_socket_with_unix_fds(int fd,
const DBusString *buffer,
int start,
int len,
const int *fds,
int n_fds) {
#ifndef HAVE_UNIX_FD_PASSING
if (n_fds > 0) {
errno = ENOTSUP;
return -1;
}
return _dbus_write_socket(fd, buffer, start, len);
#else
return _dbus_write_socket_with_unix_fds_two(fd, buffer, start, len, NULL, 0, 0, fds, n_fds);
#endif
}
int
_dbus_write_socket_with_unix_fds_two(int fd,
const DBusString *buffer1,
int start1,
int len1,
const DBusString *buffer2,
int start2,
int len2,
const int *fds,
int n_fds) {
#ifndef HAVE_UNIX_FD_PASSING
if (n_fds > 0) {
errno = ENOTSUP;
return -1;
}
return _dbus_write_socket_two(fd,
buffer1, start1, len1,
buffer2, start2, len2);
#else
struct msghdr m;
struct cmsghdr *cm;
struct iovec iov[2];
int bytes_written;
_dbus_assert (len1 >= 0);
_dbus_assert (len2 >= 0);
_dbus_assert (n_fds >= 0);
_DBUS_ZERO(iov);
iov[0].iov_base = (char*) _dbus_string_get_const_data_len (buffer1, start1, len1);
iov[0].iov_len = len1;
if (buffer2)
{
iov[1].iov_base = (char*) _dbus_string_get_const_data_len (buffer2, start2, len2);
iov[1].iov_len = len2;
}
_DBUS_ZERO(m);
m.msg_iov = iov;
m.msg_iovlen = buffer2 ? 2 : 1;
if (n_fds > 0)
{
m.msg_controllen = CMSG_SPACE(n_fds * sizeof(int));
m.msg_control = alloca(m.msg_controllen);
memset(m.msg_control, 0, m.msg_controllen);
cm = CMSG_FIRSTHDR(&m);
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_RIGHTS;
cm->cmsg_len = CMSG_LEN(n_fds * sizeof(int));
memcpy(CMSG_DATA(cm), fds, n_fds * sizeof(int));
}
again:
bytes_written = sendmsg (fd, &m, 0
#ifdef MSG_NOSIGNAL
|MSG_NOSIGNAL
#endif
);
if (bytes_written < 0 && errno == EINTR)
goto again;
#if 0
if (bytes_written > 0)
_dbus_verbose_bytes_of_string (buffer, start, bytes_written);
#endif
return bytes_written;
#endif
}
/**
@ -255,8 +529,52 @@ _dbus_write_socket_two (int fd,
int start2,
int len2)
{
#ifdef MSG_NOSIGNAL
struct iovec vectors[2];
const char *data1;
const char *data2;
int bytes_written;
struct msghdr m;
_dbus_assert (buffer1 != NULL);
_dbus_assert (start1 >= 0);
_dbus_assert (start2 >= 0);
_dbus_assert (len1 >= 0);
_dbus_assert (len2 >= 0);
data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
if (buffer2 != NULL)
data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
else
{
data2 = NULL;
start2 = 0;
len2 = 0;
}
vectors[0].iov_base = (char*) data1;
vectors[0].iov_len = len1;
vectors[1].iov_base = (char*) data2;
vectors[1].iov_len = len2;
_DBUS_ZERO(m);
m.msg_iov = vectors;
m.msg_iovlen = data2 ? 2 : 1;
again:
bytes_written = sendmsg (fd, &m, MSG_NOSIGNAL);
if (bytes_written < 0 && errno == EINTR)
goto again;
return bytes_written;
#else
return _dbus_write_two (fd, buffer1, start1, len1,
buffer2, start2, len2);
#endif
}
@ -474,6 +792,8 @@ _dbus_write_two (int fd,
* requested (it's possible only on Linux; see "man 7 unix" on Linux).
* On non-Linux abstract socket usage always fails.
*
* This will set FD_CLOEXEC for the socket returned.
*
* @param path the path to UNIX domain socket
* @param abstract #TRUE to use abstract namespace
* @param error return location for error code
@ -610,6 +930,8 @@ _dbus_set_local_creds (int fd, dbus_bool_t on)
* see "man 7 unix" on Linux).
* On non-Linux abstract socket usage always fails.
*
* This will set FD_CLOEXEC for the socket returned
*
* @param path the socket name
* @param abstract #TRUE to use abstract namespace
* @param error return location for errors
@ -746,6 +1068,8 @@ _dbus_listen_unix_socket (const char *path,
* and port. The connection fd is returned, and is set up as
* nonblocking.
*
* This will set FD_CLOEXEC for the socket returned
*
* @param host the host name to connect to
* @param port the port to connect to
* @param family the address family to listen on, NULL for all
@ -853,6 +1177,8 @@ _dbus_connect_tcp_socket (const char *host,
* a random free port is used and returned in the port parameter.
* If inaddr_any is specified, the hostname is ignored.
*
* This will set FD_CLOEXEC for the socket returned
*
* @param host the host name to listen on
* @param port the port to listen on, if zero a free port will be used
* @param family the address family to listen on, NULL for all
@ -1056,13 +1382,13 @@ write_credentials_byte (int server_fd,
iov.iov_base = buf;
iov.iov_len = 1;
memset (&msg, 0, sizeof (msg));
_DBUS_ZERO(msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t) &cmsg;
msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
memset (&cmsg, 0, sizeof (cmsg));
_DBUS_ZERO(cmsg);
cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_CREDS;
@ -1172,12 +1498,12 @@ _dbus_read_credentials_socket (int client_fd,
iov.iov_base = &buf;
iov.iov_len = 1;
memset (&msg, 0, sizeof (msg));
_DBUS_ZERO(msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
memset (&cmsg, 0, sizeof (cmsg));
_DBUS_ZERO(cmsg);
msg.msg_control = (caddr_t) &cmsg;
msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
#endif
@ -1377,6 +1703,8 @@ _dbus_send_credentials_socket (int server_fd,
* Accepts a connection on a listening socket.
* Handles EINTR for you.
*
* This will enable FD_CLOEXEC for the returned socket.
*
* @param listen_fd the listen file descriptor
* @returns the connection fd of the client, or -1 on error
*/
@ -1386,12 +1714,25 @@ _dbus_accept (int listen_fd)
int client_fd;
struct sockaddr addr;
socklen_t addrlen;
#ifdef HAVE_ACCEPT4
dbus_bool_t cloexec_done;
#endif
addrlen = sizeof (addr);
retry:
client_fd = accept (listen_fd, &addr, &addrlen);
#ifdef HAVE_ACCEPT4
/* We assume that if accept4 is available SOCK_CLOEXEC is too */
client_fd = accept4 (listen_fd, &addr, &addrlen, SOCK_CLOEXEC);
cloexec_done = client_fd >= 0;
if (client_fd < 0 && errno == ENOSYS)
#endif
{
client_fd = accept (listen_fd, &addr, &addrlen);
}
if (client_fd < 0)
{
if (errno == EINTR)
@ -1399,7 +1740,14 @@ _dbus_accept (int listen_fd)
}
_dbus_verbose ("client fd %d accepted\n", client_fd);
#ifdef HAVE_ACCEPT4
if (!cloexec_done)
#endif
{
_dbus_fd_set_close_on_exec(client_fd);
}
return client_fd;
}
@ -1864,23 +2212,8 @@ _dbus_parse_uid (const DBusString *uid_str,
return TRUE;
}
#if !DBUS_USE_SYNC
_DBUS_DEFINE_GLOBAL_LOCK (atomic);
#if DBUS_USE_ATOMIC_INT_486_COND
/* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
/* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
static inline dbus_int32_t
atomic_exchange_and_add (DBusAtomic *atomic,
volatile dbus_int32_t val)
{
register dbus_int32_t result;
__asm__ __volatile__ ("lock; xaddl %0,%1"
: "=r" (result), "=m" (atomic->value)
: "0" (val), "m" (atomic->value));
return result;
}
#endif
/**
@ -1888,14 +2221,12 @@ atomic_exchange_and_add (DBusAtomic *atomic,
*
* @param atomic pointer to the integer to increment
* @returns the value before incrementing
*
* @todo implement arch-specific faster atomic ops
*/
dbus_int32_t
_dbus_atomic_inc (DBusAtomic *atomic)
{
#if DBUS_USE_ATOMIC_INT_486_COND
return atomic_exchange_and_add (atomic, 1);
#if DBUS_USE_SYNC
return __sync_add_and_fetch(&atomic->value, 1)-1;
#else
dbus_int32_t res;
_DBUS_LOCK (atomic);
@ -1911,14 +2242,12 @@ _dbus_atomic_inc (DBusAtomic *atomic)
*
* @param atomic pointer to the integer to decrement
* @returns the value before decrementing
*
* @todo implement arch-specific faster atomic ops
*/
dbus_int32_t
_dbus_atomic_dec (DBusAtomic *atomic)
{
#if DBUS_USE_ATOMIC_INT_486_COND
return atomic_exchange_and_add (atomic, -1);
#if DBUS_USE_SYNC
return __sync_sub_and_fetch(&atomic->value, 1)+1;
#else
dbus_int32_t res;
@ -2682,6 +3011,48 @@ _dbus_close (int fd,
return TRUE;
}
/**
* Duplicates a file descriptor. Makes sure the fd returned is >= 3
* (i.e. avoids stdin/stdout/stderr). Sets O_CLOEXEC.
*
* @param fd the file descriptor to duplicate
* @returns duplicated file descriptor
* */
int
_dbus_dup(int fd,
DBusError *error)
{
int new_fd;
#ifdef F_DUPFD_CLOEXEC
dbus_bool_t cloexec_done;
new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
cloexec_done = new_fd >= 0;
if (new_fd < 0 && errno == EINVAL)
#endif
{
new_fd = fcntl(fd, F_DUPFD, 3);
}
if (new_fd < 0) {
dbus_set_error (error, _dbus_error_from_errno (errno),
"Could not duplicate fd %d", fd);
return -1;
}
#ifndef F_DUPFD_CLOEXEC
if (!cloexec_done)
#endif
{
_dbus_fd_set_close_on_exec(new_fd);
}
return new_fd;
}
/**
* Sets a file descriptor to be nonblocking.
*
@ -2761,6 +3132,8 @@ _dbus_print_backtrace (void)
* Creates a full-duplex pipe (as in socketpair()).
* Sets both ends of the pipe nonblocking.
*
* Marks both file descriptors as close-on-exec
*
* @todo libdbus only uses this for the debug-pipe server, so in
* principle it could be in dbus-sysdeps-util.c, except that
* dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
@ -2780,16 +3153,37 @@ _dbus_full_duplex_pipe (int *fd1,
{
#ifdef HAVE_SOCKETPAIR
int fds[2];
int retval;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0)
#ifdef SOCK_CLOEXEC
dbus_bool_t cloexec_done;
retval = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds);
cloexec_done = retval >= 0;
if (retval < 0 && errno == EINVAL)
#endif
{
retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
}
if (retval < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Could not create full-duplex pipe");
return FALSE;
}
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
#ifdef SOCK_CLOEXEC
if (!cloexec_done)
#endif
{
_dbus_fd_set_close_on_exec (fds[0]);
_dbus_fd_set_close_on_exec (fds[1]);
}
if (!blocking &&
(!_dbus_set_fd_nonblocking (fds[0], NULL) ||
!_dbus_set_fd_nonblocking (fds[1], NULL)))
@ -3487,4 +3881,36 @@ _dbus_get_is_errno_eagain_or_ewouldblock (void)
return errno == EAGAIN || errno == EWOULDBLOCK;
}
/**
* Checks whether file descriptors may be passed via the socket
*
* @param fd the socket
* @return TRUE when fd passing over this socket is supported
*
*/
dbus_bool_t
_dbus_socket_can_pass_unix_fd(int fd) {
#ifdef SCM_RIGHTS
union {
struct sockaddr sa;
struct sockaddr_storage storage;
struct sockaddr_un un;
} sa_buf;
socklen_t sa_len = sizeof(sa_buf);
_DBUS_ZERO(sa_buf);
if (getsockname(fd, &sa_buf.sa, &sa_len) < 0)
return FALSE;
return sa_buf.sa.sa_family == AF_UNIX;
#else
return FALSE;
#endif
}
/* tests in dbus-sysdeps-util.c */

View file

@ -44,7 +44,9 @@ DBUS_BEGIN_DECLS
dbus_bool_t
_dbus_close (int fd,
DBusError *error);
int
int _dbus_dup (int fd,
DBusError *error);
int
_dbus_read (int fd,
DBusString *buffer,
int count);

View file

@ -2616,7 +2616,7 @@ static void dump_backtrace_for_thread(HANDLE hThread)
DPRINTF("Backtrace:\n");
memset(&context, 0, sizeof(context));
_DBUS_ZERO(context);
context.ContextFlags = CONTEXT_FULL;
SuspendThread(hThread);
@ -2628,7 +2628,7 @@ static void dump_backtrace_for_thread(HANDLE hThread)
return;
}
memset(&sf, 0, sizeof(sf));
_DBUS_ZERO(sf);
#ifdef __i386__
sf.AddrFrame.Offset = context.Ebp;

View file

@ -153,6 +153,28 @@ int _dbus_write_socket_two (int fd,
const DBusString *buffer2,
int start2,
int len2);
int _dbus_read_socket_with_unix_fds (int fd,
DBusString *buffer,
int count,
int *fds,
int *n_fds);
int _dbus_write_socket_with_unix_fds (int fd,
const DBusString *buffer,
int start,
int len,
const int *fds,
int n_fds);
int _dbus_write_socket_with_unix_fds_two (int fd,
const DBusString *buffer1,
int start1,
int len1,
const DBusString *buffer2,
int start2,
int len2,
const int *fds,
int n_fds);
int _dbus_connect_tcp_socket (const char *host,
const char *port,
const char *family,
@ -192,6 +214,8 @@ dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid)
dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString *directory,
DBusCredentials *credentials);
dbus_bool_t _dbus_socket_can_pass_unix_fd(int fd);
/** Opaque type representing an atomically-modifiable integer
* that can be used from multiple threads.
*/

View file

@ -424,7 +424,9 @@ init_locks (void)
LOCK_ADDR (pending_call_slots),
LOCK_ADDR (server_slots),
LOCK_ADDR (message_slots),
#if !DBUS_USE_SYNC
LOCK_ADDR (atomic),
#endif
LOCK_ADDR (bus),
LOCK_ADDR (bus_datas),
LOCK_ADDR (shutdown_funcs),

View file

@ -23,6 +23,8 @@
#ifndef DBUS_TRANSPORT_PROTECTED_H
#define DBUS_TRANSPORT_PROTECTED_H
#include <config.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-errors.h>
#include <dbus/dbus-transport.h>
@ -92,9 +94,9 @@ struct DBusTransport
DBusCredentials *credentials; /**< Credentials of other end read from the socket */
long max_live_messages_size; /**< Max total size of received messages. */
long max_live_messages_unix_fds; /**< Max total unix fds of received messages. */
DBusCounter *live_messages_size; /**< Counter for size of all live messages. */
DBusCounter *live_messages; /**< Counter for size/unix fds of all live messages. */
char *address; /**< Address of the server we are connecting to (#NULL for the server side of a transport) */
@ -138,6 +140,9 @@ DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry
DBusTransport **transport_p,
DBusError *error);
#define DBUS_TRANSPORT_CAN_SEND_UNIX_FD(x) \
_dbus_auth_get_unix_fd_negotiated((x)->auth)
DBUS_END_DECLS
#endif /* DBUS_TRANSPORT_PROTECTED_H */

View file

@ -28,7 +28,6 @@
#include "dbus-watch.h"
#include "dbus-credentials.h"
/**
* @defgroup DBusTransportSocket DBusTransport implementations for sockets
* @ingroup DBusInternals
@ -192,7 +191,8 @@ check_read_watch (DBusTransport *transport)
if (_dbus_transport_get_is_authenticated (transport))
need_read_watch =
_dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
(_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
(_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
else
{
if (transport->receive_credentials_pending)
@ -551,6 +551,9 @@ do_writing (DBusTransport *transport)
if (_dbus_auth_needs_encoding (transport->auth))
{
/* Does fd passing even make sense with encoded data? */
_dbus_assert(!DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport));
if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0)
{
if (!_dbus_auth_encode_data (transport->auth,
@ -588,27 +591,53 @@ do_writing (DBusTransport *transport)
#if 0
_dbus_verbose ("message is %d bytes\n",
total_bytes_to_write);
total_bytes_to_write);
#endif
if (socket_transport->message_bytes_written < header_len)
#ifdef HAVE_UNIX_FD_PASSING
if (socket_transport->message_bytes_written <= 0 && DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
{
/* Send the fds along with the first byte of the message */
const int *unix_fds;
unsigned n;
_dbus_message_get_unix_fds(message, &unix_fds, &n);
bytes_written =
_dbus_write_socket_two (socket_transport->fd,
header,
socket_transport->message_bytes_written,
header_len - socket_transport->message_bytes_written,
body,
0, body_len);
_dbus_write_socket_with_unix_fds_two (socket_transport->fd,
header,
socket_transport->message_bytes_written,
header_len - socket_transport->message_bytes_written,
body,
0, body_len,
unix_fds,
n);
if (bytes_written > 0 && n > 0)
_dbus_verbose("Wrote %i unix fds\n", n);
}
else
#endif
{
bytes_written =
_dbus_write_socket (socket_transport->fd,
body,
(socket_transport->message_bytes_written - header_len),
body_len -
(socket_transport->message_bytes_written - header_len));
if (socket_transport->message_bytes_written < header_len)
{
bytes_written =
_dbus_write_socket_two (socket_transport->fd,
header,
socket_transport->message_bytes_written,
header_len - socket_transport->message_bytes_written,
body,
0, body_len);
}
else
{
bytes_written =
_dbus_write_socket (socket_transport->fd,
body,
(socket_transport->message_bytes_written - header_len),
body_len -
(socket_transport->message_bytes_written - header_len));
}
}
}
@ -704,6 +733,9 @@ do_reading (DBusTransport *transport)
if (_dbus_auth_needs_decoding (transport->auth))
{
/* Does fd passing even make sense with encoded data? */
_dbus_assert(!DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport));
if (_dbus_string_get_length (&socket_transport->encoded_incoming) > 0)
bytes_read = _dbus_string_get_length (&socket_transport->encoded_incoming);
else
@ -748,10 +780,37 @@ do_reading (DBusTransport *transport)
{
_dbus_message_loader_get_buffer (transport->loader,
&buffer);
bytes_read = _dbus_read_socket (socket_transport->fd,
buffer, socket_transport->max_bytes_read_per_iteration);
#ifdef HAVE_UNIX_FD_PASSING
if (DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
{
int *fds, n_fds;
if (!_dbus_message_loader_get_unix_fds(transport->loader, &fds, &n_fds))
{
_dbus_verbose ("Out of memory reading file descriptors\n");
_dbus_message_loader_return_buffer (transport->loader, buffer, 0);
oom = TRUE;
goto out;
}
bytes_read = _dbus_read_socket_with_unix_fds(socket_transport->fd,
buffer,
socket_transport->max_bytes_read_per_iteration,
fds, &n_fds);
if (bytes_read >= 0 && n_fds > 0)
_dbus_verbose("Read %i unix fds\n", n_fds);
_dbus_message_loader_return_unix_fds(transport->loader, fds, bytes_read < 0 ? 0 : n_fds);
}
else
#endif
{
bytes_read = _dbus_read_socket (socket_transport->fd,
buffer, socket_transport->max_bytes_read_per_iteration);
}
_dbus_message_loader_return_buffer (transport->loader,
buffer,
bytes_read < 0 ? 0 : bytes_read);
@ -1204,7 +1263,11 @@ _dbus_transport_new_for_socket (int fd,
&socket_vtable,
server_guid, address))
goto failed_4;
#ifdef HAVE_UNIX_FD_PASSING
_dbus_auth_set_unix_fd_possible(socket_transport->base.auth, _dbus_socket_can_pass_unix_fd(fd));
#endif
socket_transport->fd = fd;
socket_transport->message_bytes_written = 0;
@ -1282,8 +1345,6 @@ _dbus_transport_new_for_tcp_socket (const char *host,
return NULL;
}
_dbus_fd_set_close_on_exec (fd);
_dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
host, port);

View file

@ -85,8 +85,6 @@ _dbus_transport_new_for_domain_socket (const char *path,
goto failed_0;
}
_dbus_fd_set_close_on_exec (fd);
_dbus_verbose ("Successfully connected to unix socket %s\n",
path);

View file

@ -29,6 +29,8 @@
#include "dbus-auth.h"
#include "dbus-address.h"
#include "dbus-credentials.h"
#include "dbus-message-private.h"
#include "dbus-marshal-header.h"
#ifdef DBUS_BUILD_TESTS
#include "dbus-server-debug-pipe.h"
#endif
@ -55,7 +57,7 @@
*/
static void
live_messages_size_notify (DBusCounter *counter,
live_messages_notify (DBusCounter *counter,
void *user_data)
{
DBusTransport *transport = user_data;
@ -63,8 +65,10 @@ live_messages_size_notify (DBusCounter *counter,
_dbus_transport_ref (transport);
#if 0
_dbus_verbose ("Counter value is now %d\n",
(int) _dbus_counter_get_value (counter));
_dbus_verbose ("Size counter value is now %d\n",
(int) _dbus_counter_get_size_value (counter));
_dbus_verbose ("Unix FD counter value is now %d\n",
(int) _dbus_counter_get_unix_fd_value (counter));
#endif
/* disable or re-enable the read watch for the transport if
@ -155,7 +159,7 @@ _dbus_transport_init_base (DBusTransport *transport,
transport->vtable = vtable;
transport->loader = loader;
transport->auth = auth;
transport->live_messages_size = counter;
transport->live_messages = counter;
transport->authenticated = FALSE;
transport->disconnected = FALSE;
transport->is_server = (server_guid != NULL);
@ -178,17 +182,22 @@ _dbus_transport_init_base (DBusTransport *transport,
*/
transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
/* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
should be more than enough */
transport->max_live_messages_unix_fds = 4096;
/* credentials read from socket if any */
transport->credentials = creds;
_dbus_counter_set_notify (transport->live_messages_size,
_dbus_counter_set_notify (transport->live_messages,
transport->max_live_messages_size,
live_messages_size_notify,
transport->max_live_messages_unix_fds,
live_messages_notify,
transport);
if (transport->address)
_dbus_verbose ("Initialized transport on address %s\n", transport->address);
return TRUE;
}
@ -212,9 +221,9 @@ _dbus_transport_finalize_base (DBusTransport *transport)
_dbus_message_loader_unref (transport->loader);
_dbus_auth_unref (transport->auth);
_dbus_counter_set_notify (transport->live_messages_size,
0, NULL, NULL);
_dbus_counter_unref (transport->live_messages_size);
_dbus_counter_set_notify (transport->live_messages,
0, 0, NULL, NULL);
_dbus_counter_unref (transport->live_messages);
dbus_free (transport->address);
dbus_free (transport->expected_guid);
if (transport->credentials)
@ -802,6 +811,18 @@ _dbus_transport_get_is_anonymous (DBusTransport *transport)
return FALSE;
}
/**
* Returns TRUE if the transport supports sending unix fds.
*
* @param transport the transport
* @returns #TRUE if TRUE it is possible to send unix fds across the transport.
*/
dbus_bool_t
_dbus_transport_can_pass_unix_fd(DBusTransport *transport)
{
return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
}
/**
* Gets the address of a transport. It will be
* #NULL for a server-side transport.
@ -1059,7 +1080,8 @@ recover_unused_bytes (DBusTransport *transport)
DBusDispatchStatus
_dbus_transport_get_dispatch_status (DBusTransport *transport)
{
if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
_dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
return DBUS_DISPATCH_COMPLETE; /* complete for now */
if (!_dbus_transport_get_is_authenticated (transport))
@ -1116,7 +1138,7 @@ _dbus_transport_queue_messages (DBusTransport *transport)
_dbus_verbose ("queueing received message %p\n", message);
if (!_dbus_message_add_size_counter (message, transport->live_messages_size))
if (!_dbus_message_add_counter (message, transport->live_messages))
{
_dbus_message_loader_putback_message_link (transport->loader,
link);
@ -1153,6 +1175,19 @@ _dbus_transport_set_max_message_size (DBusTransport *transport,
_dbus_message_loader_set_max_message_size (transport->loader, size);
}
/**
* See dbus_connection_set_max_message_unix_fds().
*
* @param transport the transport
* @param n the max number of unix fds of a single message
*/
void
_dbus_transport_set_max_message_unix_fds (DBusTransport *transport,
long n)
{
_dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
}
/**
* See dbus_connection_get_max_message_size().
*
@ -1165,6 +1200,18 @@ _dbus_transport_get_max_message_size (DBusTransport *transport)
return _dbus_message_loader_get_max_message_size (transport->loader);
}
/**
* See dbus_connection_get_max_message_unix_fds().
*
* @param transport the transport
* @returns max message unix fds
*/
long
_dbus_transport_get_max_message_unix_fds (DBusTransport *transport)
{
return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
}
/**
* See dbus_connection_set_max_received_size().
*
@ -1176,12 +1223,30 @@ _dbus_transport_set_max_received_size (DBusTransport *transport,
long size)
{
transport->max_live_messages_size = size;
_dbus_counter_set_notify (transport->live_messages_size,
_dbus_counter_set_notify (transport->live_messages,
transport->max_live_messages_size,
live_messages_size_notify,
transport->max_live_messages_unix_fds,
live_messages_notify,
transport);
}
/**
* See dbus_connection_set_max_received_unix_fds().
*
* @param transport the transport
* @param n the max unix fds of all incoming messages
*/
void
_dbus_transport_set_max_received_unix_fds (DBusTransport *transport,
long n)
{
transport->max_live_messages_unix_fds = n;
_dbus_counter_set_notify (transport->live_messages,
transport->max_live_messages_size,
transport->max_live_messages_unix_fds,
live_messages_notify,
transport);
}
/**
* See dbus_connection_get_max_received_size().
@ -1195,6 +1260,18 @@ _dbus_transport_get_max_received_size (DBusTransport *transport)
return transport->max_live_messages_size;
}
/**
* See dbus_connection_set_max_received_unix_fds().
*
* @param transport the transport
* @returns max unix fds for all live messages
*/
long
_dbus_transport_get_max_received_unix_fds (DBusTransport *transport)
{
return transport->max_live_messages_unix_fds;
}
/**
* See dbus_connection_get_unix_user().
*

View file

@ -40,6 +40,8 @@ void _dbus_transport_disconnect (DBusTransport
dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport);
dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport);
dbus_bool_t _dbus_transport_get_is_anonymous (DBusTransport *transport);
dbus_bool_t _dbus_transport_can_pass_unix_fd (DBusTransport *transport);
const char* _dbus_transport_get_address (DBusTransport *transport);
const char* _dbus_transport_get_server_id (DBusTransport *transport);
dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport,
@ -52,12 +54,21 @@ void _dbus_transport_do_iteration (DBusTransport
int timeout_milliseconds);
DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport);
dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport);
void _dbus_transport_set_max_message_size (DBusTransport *transport,
long size);
long _dbus_transport_get_max_message_size (DBusTransport *transport);
void _dbus_transport_set_max_received_size (DBusTransport *transport,
long size);
long _dbus_transport_get_max_received_size (DBusTransport *transport);
void _dbus_transport_set_max_message_unix_fds (DBusTransport *transport,
long n);
long _dbus_transport_get_max_message_unix_fds (DBusTransport *transport);
void _dbus_transport_set_max_received_unix_fds(DBusTransport *transport,
long n);
long _dbus_transport_get_max_received_unix_fds(DBusTransport *transport);
dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport,
int *fd_p);
dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport,

View file

@ -415,6 +415,10 @@
<entry><literal>DICT_ENTRY</literal></entry>
<entry>101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') </entry>
<entry>Entry in a dict or map (array of key-value pairs)</entry>
</row><row>
<entry><literal>UNIX_FD</literal></entry>
<entry>104 (ASCII 'h')</entry>
<entry>Unix file descriptor</entry>
</row>
</tbody>
</tgroup>
@ -579,6 +583,15 @@
<entry>
8
</entry>
</row><row>
<entry><literal>UNIX_FD</literal></entry>
<entry>32-bit unsigned integer in the message's byte
order. The actual file descriptors need to be
transferred out-of-band via some platform specific
mechanism. On the wire, values of this type store the index to the
file descriptor in the array of file descriptors that
accompany the message.</entry>
<entry>4</entry>
</row>
</tbody>
</tgroup>
@ -999,6 +1012,22 @@
If omitted, it is assumed to be the
empty signature "" (i.e. the body must be 0-length).</entry>
</row>
<row>
<entry><literal>UNIX_FDS</literal></entry>
<entry>9</entry>
<entry><literal>UINT32</literal></entry>
<entry>optional</entry>
<entry>The number of Unix file descriptors that
accompany the message. If omitted, it is assumed
that no Unix file descriptors accompany the
message. The actual file descriptors need to be
transferred via platform specific mechanism
out-of-band. They must be sent at the same time as
part of the message itself. They may not be sent
before the first byte of the message itself is
transferred or after the last byte of the message
itself.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
@ -1410,6 +1439,7 @@
<listitem><para>BEGIN</para></listitem>
<listitem><para>DATA &lt;data in hex encoding&gt;</para></listitem>
<listitem><para>ERROR [human-readable error explanation]</para></listitem>
<listitem><para>NEGOTIATE_UNIX_FD</para></listitem>
</itemizedlist>
From server to client are as follows:
@ -1419,6 +1449,7 @@
<listitem><para>OK &lt;GUID in hex&gt;</para></listitem>
<listitem><para>DATA &lt;data in hex encoding&gt;</para></listitem>
<listitem><para>ERROR</para></listitem>
<listitem><para>AGREE_UNIX_FD</para></listitem>
</itemizedlist>
</para>
<para>
@ -1479,16 +1510,17 @@
If authentication succeeds after exchanging DATA commands,
an OK command must be sent to the client.
</para>
<para>
The first octet received by the client after the \r\n of the OK
command must be the first octet of the authenticated/encrypted
stream of D-Bus messages.
</para>
<para>
The first octet received by the server after the \r\n of the BEGIN
command from the client must be the first octet of the
authenticated/encrypted stream of D-Bus messages.
</para>
<para>
If BEGIN is received by the server, the first octet received
by the client after the \r\n of the OK command must be the
first octet of the authenticated/encrypted stream of D-Bus
messages.
</para>
</sect2>
<sect2 id="auth-command-cancel">
<title>CANCEL Command</title>
@ -1542,20 +1574,24 @@
<sect2 id="auth-command-ok">
<title>OK Command</title>
<para>
The OK command indicates that the client has been authenticated,
and that further communication will be a stream of D-Bus messages
(optionally encrypted, as negotiated) rather than this protocol.
The OK command indicates that the client has been
authenticated. The client may now proceed with negotiating
Unix file descriptor passing. To do that it shall send
NEGOTIATE_UNIX_FD to the server.
</para>
<para>
The first octet received by the client after the \r\n of the OK
command must be the first octet of the authenticated/encrypted
stream of D-Bus messages.
Otherwise, the client must respond to the OK command by
sending a BEGIN command, followed by its stream of messages,
or by disconnecting. The server must not accept additional
commands using this protocol after the BEGIN command has been
received. Further communication will be a stream of D-Bus
messages (optionally encrypted, as negotiated) rather than
this protocol.
</para>
<para>
The client must respond to the OK command by sending a BEGIN
command, followed by its stream of messages, or by disconnecting.
The server must not accept additional commands using this protocol
after the OK command has been sent.
If a client sends BEGIN the first octet received by the client
after the \r\n of the OK command must be the first octet of
the authenticated/encrypted stream of D-Bus messages.
</para>
<para>
The OK command has one argument, which is the GUID of the server.
@ -1589,6 +1625,56 @@
negotiate extensions or changes to the D-Bus protocol in the future.
</para>
</sect2>
<sect2 id="auth-command-negotiate-unix-fd">
<title>NEGOTIATE_UNIX_FD Command</title>
<para>
The NEGOTIATE_UNIX_FD command indicates that the client
supports Unix file descriptor passing. This command may only
be sent after the connection is authenticated, i.e. after OK
was received by the client. This command may only be sent on
transports that support Unix file descriptor passing.
</para>
<para>
On receiving NEGOTIATE_UNIX_FD the server must respond with
either AGREE_UNIX_FD or ERROR. It shall respond the former if
the transport chosen supports Unix file descriptor passing and
the server supports this feature. It shall respond the latter
if the transport does not support Unix file descriptor
passing, the server does not support this feature, or the
server decides not to enable file descriptor passing due to
security or other reasons.
</para>
</sect2>
<sect2 id="auth-command-agree-unix-fd">
<title>AGREE_UNIX_FD Command</title>
<para>
The AGREE_UNIX_FD command indicates that the server supports
Unix file descriptor passing. This command may only be sent
after the connection is authenticated, and the client sent
NEGOTIATE_UNIX_FD to enable Unix file descriptor passing. This
command may only be sent on transports that support Unix file
descriptor passing.
</para>
<para>
On receiving AGREE_UNIX_FD the client must respond with BEGIN,
followed by its stream of messages, or by disconnecting. The
server must not accept additional commands using this protocol
after the BEGIN command has been received. Further
communication will be a stream of D-Bus messages (optionally
encrypted, as negotiated) rather than this protocol.
</para>
</sect2>
<sect2 id="auth-command-future">
<title>Future Extensions</title>
<para>
Future extensions to the authentication and negotiation
protocol are possible. For that new commands may be
introduced. If a client or server receives an unknown command
it shall respond with ERROR and not consider this fatal. New
commands may be introduced both before, and after
authentication, i.e. both before and after the OK command.
</para>
</sect2>
<sect2 id="auth-examples">
<title>Authentication examples</title>
@ -1669,6 +1755,30 @@
C: BEGIN
</programlisting>
</figure>
<figure>
<title>Example of successful magic cookie authentication with successful negotiation of Unix FD passing</title>
<programlisting>
(MAGIC_COOKIE is a made up mechanism)
C: AUTH MAGIC_COOKIE 3138363935333137393635383634
S: OK 1234deadbeef
C: NEGOTIATE_UNIX_FD
S: AGREE_UNIX_FD
C: BEGIN
</programlisting>
</figure>
<figure>
<title>Example of successful magic cookie authentication with unsuccessful negotiation of Unix FD passing</title>
<programlisting>
(MAGIC_COOKIE is a made up mechanism)
C: AUTH MAGIC_COOKIE 3138363935333137393635383634
S: OK 1234deadbeef
C: NEGOTIATE_UNIX_FD
S: ERROR
C: BEGIN
</programlisting>
</figure>
</para>
</sect2>
<sect2 id="auth-states">
@ -4078,4 +4188,3 @@
</glossary>
</article>