2004-04-09 Jon Trowbridge <trow@ximian.com>

* bus/config-parser.c (bus_config_parser_new): Added a 'parent'
	    argument.  If non-null, the newly-constructed BusConfigParser will
	    be initialized with the parent's BusLimits instead of the default
	    values.
	    (include_file): When including a config file, pass in
	    the current parser as the parent and then copy the BusLimits
	    from the included BusConfigParser pack to the current parser.
	    (process_test_valid_subdir): Renamed from process_test_subdir.
	    (process_test_equiv_subdir): Added.  Walks through a directory,
	    descending into each subdirectory and loading the config files
	    it finds there.  If any subdirectory contains two config files
	    that don't produce identical BusConfigParser structs, fail.
	    For now, the BusConfigParser's BusPolicies are not compared.
	    (bus_config_parser_test): Call both process_test_valid_subdir and
	    process_test_equiv_subdir.

	    * bus/config-loader-libxml.c (bus_config_load): Take a parent
	    argument and pass it along to the call to bus_config_parser_new.
	    Also made a few small changes to allow this code to compile.

	    * bus/config-loader-expat.c (bus_config_load): Take a parent
	    argument and pass it along to the call to bus_config_parser_new.

	    * bus/bus.c (bus_context_new): Load the config file
	    with a NULL parent argument.
This commit is contained in:
Jon Trowbridge 2004-04-09 19:50:29 +00:00
parent 8056390e00
commit e039be5838
12 changed files with 534 additions and 59 deletions

View file

@ -1,3 +1,31 @@
2004-04-09 Jon Trowbridge <trow@ximian.com>
* bus/config-parser.c (bus_config_parser_new): Added a 'parent'
argument. If non-null, the newly-constructed BusConfigParser will
be initialized with the parent's BusLimits instead of the default
values.
(include_file): When including a config file, pass in
the current parser as the parent and then copy the BusLimits
from the included BusConfigParser pack to the current parser.
(process_test_valid_subdir): Renamed from process_test_subdir.
(process_test_equiv_subdir): Added. Walks through a directory,
descending into each subdirectory and loading the config files
it finds there. If any subdirectory contains two config files
that don't produce identical BusConfigParser structs, fail.
For now, the BusConfigParser's BusPolicies are not compared.
(bus_config_parser_test): Call both process_test_valid_subdir and
process_test_equiv_subdir.
* bus/config-loader-libxml.c (bus_config_load): Take a parent
argument and pass it along to the call to bus_config_parser_new.
Also made a few small changes to allow this code to compile.
* bus/config-loader-expat.c (bus_config_load): Take a parent
argument and pass it along to the call to bus_config_parser_new.
* bus/bus.c (bus_context_new): Load the config file
with a NULL parent argument.
2004-03-29 Michael Meeks <michael@ximian.com>
* glib/dbus-gobject.c (set_object_property): split out /

View file

@ -283,7 +283,7 @@ bus_context_new (const DBusString *config_file,
context = NULL;
auth_mechanisms = NULL;
parser = bus_config_load (config_file, TRUE, error);
parser = bus_config_load (config_file, TRUE, NULL, error);
if (parser == NULL)
goto failed;

View file

@ -163,9 +163,10 @@ expat_CharacterDataHandler (void *userData,
BusConfigParser*
bus_config_load (const DBusString *file,
dbus_bool_t is_toplevel,
DBusError *error)
bus_config_load (const DBusString *file,
dbus_bool_t is_toplevel,
const BusConfigParser *parent,
DBusError *error)
{
XML_Parser expat;
const char *filename;
@ -208,7 +209,7 @@ bus_config_load (const DBusString *file,
goto failed;
}
parser = bus_config_parser_new (&dirname, is_toplevel);
parser = bus_config_parser_new (&dirname, is_toplevel, parent);
if (parser == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);

View file

@ -71,18 +71,22 @@ xml_text_reader_error (void *arg,
}
BusConfigParser*
bus_config_load (const DBusString *file,
DBusError *error)
bus_config_load (const DBusString *file,
dbus_bool_t is_toplevel,
const BusConfigParser *parent,
DBusError *error)
{
xmlTextReader *reader;
const char *filename;
BusConfigParser *parser;
DBusString dirname;
DBusError tmp_error;
int ret;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
_dbus_string_get_const_data (file, &filename);
filename = _dbus_string_get_const_data (file);
parser = NULL;
reader = NULL;
dbus_error_init (&tmp_error);
@ -100,13 +104,25 @@ bus_config_load (const DBusString *file,
"xmlMemSetup() didn't work for some reason\n");
return NULL;
}
parser = bus_config_parser_new ();
if (parser == NULL)
if (!_dbus_string_init (&dirname))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if (!_dbus_string_get_dirname (file, &dirname))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed;
}
parser = bus_config_parser_new (&dirname, is_toplevel, parent);
if (parser == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed;
}
errno = 0;
reader = xmlNewTextReaderFilename (filename);
@ -163,12 +179,13 @@ bus_config_load (const DBusString *file,
if (!bus_config_parser_finished (parser, error))
goto failed;
_dbus_string_free (&dirname);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return parser;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_string_free (&dirname);
if (parser)
bus_config_parser_unref (parser);
_dbus_assert (reader == NULL); /* must go to reader_out first */

View file

@ -278,8 +278,9 @@ merge_included (BusConfigParser *parser,
}
BusConfigParser*
bus_config_parser_new (const DBusString *basedir,
dbus_bool_t is_toplevel)
bus_config_parser_new (const DBusString *basedir,
dbus_bool_t is_toplevel,
const BusConfigParser *parent)
{
BusConfigParser *parser;
@ -306,42 +307,51 @@ bus_config_parser_new (const DBusString *basedir,
return NULL;
}
/* Make up some numbers! woot! */
parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
if (parent != NULL)
{
/* Initialize the parser's limits from the parent. */
parser->limits = parent->limits;
}
else
{
/* Making this long means the user has to wait longer for an error
* message if something screws up, but making it too short means
* they might see a false failure.
*/
parser->limits.activation_timeout = 25000; /* 25 seconds */
/* Make up some numbers! woot! */
parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
/* Making this long means the user has to wait longer for an error
* message if something screws up, but making it too short means
* they might see a false failure.
*/
parser->limits.activation_timeout = 25000; /* 25 seconds */
/* Making this long risks making a DOS attack easier, but too short
* and legitimate auth will fail. If interactive auth (ask user for
* password) is allowed, then potentially it has to be quite long.
*/
parser->limits.auth_timeout = 30000; /* 30 seconds */
parser->limits.max_incomplete_connections = 32;
parser->limits.max_connections_per_user = 128;
/* Note that max_completed_connections / max_connections_per_user
* is the number of users that would have to work together to
* DOS all the other users.
*/
parser->limits.max_completed_connections = 1024;
parser->limits.max_pending_activations = 256;
parser->limits.max_services_per_connection = 256;
parser->limits.max_match_rules_per_connection = 128;
parser->limits.reply_timeout = 5 * 60 * 1000; /* 5 minutes */
parser->limits.max_replies_per_connection = 32;
/* Making this long risks making a DOS attack easier, but too short
* and legitimate auth will fail. If interactive auth (ask user for
* password) is allowed, then potentially it has to be quite long.
*/
parser->limits.auth_timeout = 30000; /* 30 seconds */
parser->limits.max_incomplete_connections = 32;
parser->limits.max_connections_per_user = 128;
/* Note that max_completed_connections / max_connections_per_user
* is the number of users that would have to work together to
* DOS all the other users.
*/
parser->limits.max_completed_connections = 1024;
parser->limits.max_pending_activations = 256;
parser->limits.max_services_per_connection = 256;
parser->limits.max_match_rules_per_connection = 128;
parser->limits.reply_timeout = 5 * 60 * 1000; /* 5 minutes */
parser->limits.max_replies_per_connection = 32;
}
parser->refcount = 1;
return parser;
}
@ -1628,7 +1638,11 @@ include_file (BusConfigParser *parser,
DBusError tmp_error;
dbus_error_init (&tmp_error);
included = bus_config_load (filename, FALSE, &tmp_error);
/* Since parser is passed in as the parent, included
inherits parser's limits. */
included = bus_config_load (filename, FALSE, parser, &tmp_error);
if (included == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
@ -1655,6 +1669,9 @@ include_file (BusConfigParser *parser,
return FALSE;
}
/* Copy included's limits back to parser. */
parser->limits = included->limits;
bus_config_parser_unref (included);
return TRUE;
}
@ -2093,7 +2110,7 @@ do_load (const DBusString *full_path,
dbus_error_init (&error);
parser = bus_config_load (full_path, TRUE, &error);
parser = bus_config_load (full_path, TRUE, NULL, &error);
if (parser == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (&error);
@ -2150,9 +2167,9 @@ check_loader_oom_func (void *data)
}
static dbus_bool_t
process_test_subdir (const DBusString *test_base_dir,
const char *subdir,
Validity validity)
process_test_valid_subdir (const DBusString *test_base_dir,
const char *subdir,
Validity validity)
{
DBusString test_directory;
DBusString filename;
@ -2211,7 +2228,7 @@ process_test_subdir (const DBusString *test_base_dir,
{
_dbus_verbose ("Skipping non-.conf file %s\n",
_dbus_string_get_const_data (&filename));
_dbus_string_free (&full_path);
_dbus_string_free (&full_path);
goto next;
}
@ -2251,6 +2268,337 @@ process_test_subdir (const DBusString *test_base_dir,
return retval;
}
static dbus_bool_t
bools_equal (dbus_bool_t a,
dbus_bool_t b)
{
return a ? b : !b;
}
static dbus_bool_t
strings_equal_or_both_null (const char *a,
const char *b)
{
if (a == NULL || b == NULL)
return a == b;
else
return !strcmp (a, b);
}
static dbus_bool_t
elements_equal (const Element *a,
const Element *b)
{
if (a->type != b->type)
return FALSE;
if (!bools_equal (a->had_content, b->had_content))
return FALSE;
switch (a->type)
{
case ELEMENT_INCLUDE:
if (!bools_equal (a->d.include.ignore_missing,
b->d.include.ignore_missing))
return FALSE;
break;
case ELEMENT_POLICY:
if (a->d.policy.type != b->d.policy.type)
return FALSE;
if (a->d.policy.gid_or_uid != b->d.policy.gid_or_uid)
return FALSE;
break;
case ELEMENT_LIMIT:
if (strcmp (a->d.limit.name, b->d.limit.name))
return FALSE;
if (a->d.limit.value != b->d.limit.value)
return FALSE;
break;
default:
/* do nothing */
break;
}
return TRUE;
}
static dbus_bool_t
lists_of_elements_equal (DBusList *a,
DBusList *b)
{
DBusList *ia;
DBusList *ib;
ia = a;
ib = b;
while (ia != NULL && ib != NULL)
{
if (elements_equal (ia->data, ib->data))
return FALSE;
ia = _dbus_list_get_next_link (&a, ia);
ib = _dbus_list_get_next_link (&b, ib);
}
return ia == NULL && ib == NULL;
}
static dbus_bool_t
lists_of_c_strings_equal (DBusList *a,
DBusList *b)
{
DBusList *ia;
DBusList *ib;
ia = a;
ib = b;
while (ia != NULL && ib != NULL)
{
if (strcmp (ia->data, ib->data))
return FALSE;
ia = _dbus_list_get_next_link (&a, ia);
ib = _dbus_list_get_next_link (&b, ib);
}
return ia == NULL && ib == NULL;
}
static dbus_bool_t
limits_equal (const BusLimits *a,
const BusLimits *b)
{
return
(a->max_incoming_bytes == b->max_incoming_bytes
|| a->max_outgoing_bytes == b->max_outgoing_bytes
|| a->max_message_size == b->max_message_size
|| a->activation_timeout == b->activation_timeout
|| a->auth_timeout == b->auth_timeout
|| a->max_completed_connections == b->max_completed_connections
|| a->max_incomplete_connections == b->max_incomplete_connections
|| a->max_connections_per_user == b->max_connections_per_user
|| a->max_pending_activations == b->max_pending_activations
|| a->max_services_per_connection == b->max_services_per_connection
|| a->max_match_rules_per_connection == b->max_match_rules_per_connection
|| a->max_replies_per_connection == b->max_replies_per_connection
|| a->reply_timeout == b->reply_timeout);
}
static dbus_bool_t
config_parsers_equal (const BusConfigParser *a,
const BusConfigParser *b)
{
if (!_dbus_string_equal (&a->basedir, &b->basedir))
return FALSE;
if (!lists_of_elements_equal (a->stack, b->stack))
return FALSE;
if (!strings_equal_or_both_null (a->user, b->user))
return FALSE;
if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
return FALSE;
if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
return FALSE;
if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
return FALSE;
/* FIXME: compare policy */
if (! limits_equal (&a->limits, &b->limits))
return FALSE;
if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
return FALSE;
if (! bools_equal (a->fork, b->fork))
return FALSE;
if (! bools_equal (a->is_toplevel, b->is_toplevel))
return FALSE;
return TRUE;
}
static dbus_bool_t
all_are_equiv (const DBusString *target_directory)
{
DBusString filename;
DBusDirIter *dir;
BusConfigParser *first_parser;
BusConfigParser *parser;
DBusError error;
dbus_bool_t equal;
dbus_bool_t retval;
dir = NULL;
first_parser = NULL;
parser = NULL;
retval = FALSE;
if (!_dbus_string_init (&filename))
_dbus_assert_not_reached ("didn't allocate filename string");
dbus_error_init (&error);
dir = _dbus_directory_open (target_directory, &error);
if (dir == NULL)
{
_dbus_warn ("Could not open %s: %s\n",
_dbus_string_get_const_data (target_directory),
error.message);
dbus_error_free (&error);
goto finished;
}
printf ("Comparing:\n");
next:
while (_dbus_directory_get_next_file (dir, &filename, &error))
{
DBusString full_path;
if (!_dbus_string_init (&full_path))
_dbus_assert_not_reached ("couldn't init string");
if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
_dbus_assert_not_reached ("couldn't copy dir to full_path");
if (!_dbus_concat_dir_and_file (&full_path, &filename))
_dbus_assert_not_reached ("couldn't concat file to dir");
if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
{
_dbus_verbose ("Skipping non-.conf file %s\n",
_dbus_string_get_const_data (&filename));
_dbus_string_free (&full_path);
goto next;
}
printf (" %s\n", _dbus_string_get_const_data (&filename));
parser = bus_config_load (&full_path, TRUE, NULL, &error);
_dbus_string_free (&full_path);
if (parser == NULL)
{
_dbus_warn ("Could not load file %s: %s\n",
_dbus_string_get_const_data (&full_path),
error.message);
dbus_error_free (&error);
goto finished;
}
else if (first_parser == NULL)
{
first_parser = parser;
}
else
{
equal = config_parsers_equal (first_parser, parser);
bus_config_parser_unref (parser);
if (! equal)
goto finished;
}
}
retval = TRUE;
finished:
_dbus_string_free (&filename);
if (first_parser)
bus_config_parser_unref (first_parser);
if (dir)
_dbus_directory_close (dir);
return retval;
}
static dbus_bool_t
process_test_equiv_subdir (const DBusString *test_base_dir,
const char *subdir)
{
DBusString test_directory;
DBusString filename;
DBusDirIter *dir;
DBusError error;
dbus_bool_t equal;
dbus_bool_t retval;
dir = NULL;
retval = FALSE;
if (!_dbus_string_init (&test_directory))
_dbus_assert_not_reached ("didn't allocate test_directory");
_dbus_string_init_const (&filename, subdir);
if (!_dbus_string_copy (test_base_dir, 0,
&test_directory, 0))
_dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
if (!_dbus_concat_dir_and_file (&test_directory, &filename))
_dbus_assert_not_reached ("couldn't allocate full path");
_dbus_string_free (&filename);
if (!_dbus_string_init (&filename))
_dbus_assert_not_reached ("didn't allocate filename string");
dbus_error_init (&error);
dir = _dbus_directory_open (&test_directory, &error);
if (dir == NULL)
{
_dbus_warn ("Could not open %s: %s\n",
_dbus_string_get_const_data (&test_directory),
error.message);
dbus_error_free (&error);
goto finished;
}
while (_dbus_directory_get_next_file (dir, &filename, &error))
{
DBusString full_path;
/* Skip CVS's magic directories! */
if (_dbus_string_equal_c_str (&filename, "CVS"))
continue;
if (!_dbus_string_init (&full_path))
_dbus_assert_not_reached ("couldn't init string");
if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
_dbus_assert_not_reached ("couldn't copy dir to full_path");
if (!_dbus_concat_dir_and_file (&full_path, &filename))
_dbus_assert_not_reached ("couldn't concat file to dir");
equal = all_are_equiv (&full_path);
_dbus_string_free (&full_path);
if (!equal)
goto finished;
}
retval = TRUE;
finished:
_dbus_string_free (&test_directory);
_dbus_string_free (&filename);
if (dir)
_dbus_directory_close (dir);
return retval;
}
dbus_bool_t
bus_config_parser_test (const DBusString *test_data_dir)
{
@ -2261,7 +2609,10 @@ bus_config_parser_test (const DBusString *test_data_dir)
return TRUE;
}
if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
return FALSE;
if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
return FALSE;
return TRUE;

View file

@ -35,8 +35,10 @@
typedef struct BusConfigParser BusConfigParser;
BusConfigParser* bus_config_parser_new (const DBusString *basedir,
dbus_bool_t is_toplevel);
BusConfigParser* bus_config_parser_new (const DBusString *basedir,
dbus_bool_t is_toplevel,
const BusConfigParser *parent);
BusConfigParser* bus_config_parser_ref (BusConfigParser *parser);
void bus_config_parser_unref (BusConfigParser *parser);
dbus_bool_t bus_config_parser_check_doctype (BusConfigParser *parser,
@ -71,9 +73,10 @@ void bus_config_parser_get_limits (BusConfigParser *parser,
/* Loader functions (backended off one of the XML parsers). Returns a
* finished ConfigParser.
*/
BusConfigParser* bus_config_load (const DBusString *file,
dbus_bool_t is_toplevel,
DBusError *error);
BusConfigParser* bus_config_load (const DBusString *file,
dbus_bool_t is_toplevel,
const BusConfigParser *parent,
DBusError *error);
#endif /* BUS_CONFIG_PARSER_H */

View file

@ -0,0 +1,25 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>mybususer</user>
<listen>unix:path=/foo/bar</listen>
<listen>tcp:port=1234</listen>
<includedir>basic.d</includedir>
<servicedir>/usr/share/foo</servicedir>
<include ignore_missing="yes">nonexistent.conf</include>
<policy context="default">
<allow user="*"/>
</policy>
<limit name="max_incoming_bytes">5000</limit>
<limit name="max_outgoing_bytes">5000</limit>
<limit name="max_message_size">300</limit>
<limit name="activation_timeout">5000</limit>
<limit name="auth_timeout">6000</limit>
<limit name="max_completed_connections">50</limit>
<limit name="max_incomplete_connections">80</limit>
<limit name="max_connections_per_user">64</limit>
<limit name="max_pending_activations">64</limit>
<limit name="max_services_per_connection">256</limit>
</busconfig>

View file

@ -0,0 +1,5 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<include>basic-1.conf</include>
</busconfig>

View file

@ -0,0 +1,13 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>mybususer</user>
<listen>unix:path=/foo/bar</listen>
<listen>tcp:port=1234</listen>
<includedir>basic.d</includedir>
<servicedir>/usr/share/foo</servicedir>
<include ignore_missing="yes">nonexistent.conf</include>
<policy context="default">
<allow user="*"/>
</policy>
</busconfig>

View file

@ -0,0 +1,13 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>mybususer</user>
<listen>unix:path=/foo/bar</listen>
<listen>tcp:port=1234</listen>
<includedir>basic.d</includedir>
<servicedir>/usr/share/foo</servicedir>
<include ignore_missing="yes">nonexistent.conf</include>
<policy context="default">
<allow user="*"/>
</policy>
</busconfig>

View file

@ -0,0 +1,14 @@
<!-- This config file contains XML entities -->
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>mybususer</user>
<listen>unix:path=/foo/&lt;bar&gt;</listen>
<listen>tcp:port=1234</listen>
<includedir>basic.&#100;</includedir>
<servicedir>/usr/&amp;share/foo</servicedir>
<include ignore_missing="ye&#115;">nonexistent.conf&#110;</include>
<policy context="&#100;efault">
<allow user="*"/>
</policy>
</busconfig>

View file

@ -0,0 +1,5 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<include>entities-1.conf</include>
</busconfig>