From 3185d7edde8ffc7672aa7d771966b0f1e0158aea Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 24 Apr 2003 22:30:38 +0000 Subject: 2003-04-24 Havoc Pennington * test/data/valid-config-files/basic.conf: add tags to this test * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement tag in configuration file. --- ChangeLog | 8 ++ bus/bus.c | 55 ++------- bus/bus.h | 13 +++ bus/config-parser.c | 199 +++++++++++++++++++++++++++++++- bus/config-parser.h | 2 + doc/config-file.txt | 30 ++++- test/data/valid-config-files/basic.conf | 10 ++ 7 files changed, 270 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index f770a533..7accabfb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-04-24 Havoc Pennington + + * test/data/valid-config-files/basic.conf: add tags to + this test + + * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement + tag in configuration file. + 2003-04-24 Havoc Pennington * bus/dispatch.c: somehow missed some name_is diff --git a/bus/bus.c b/bus/bus.c index 53ad8e65..7bb4bf99 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -45,14 +45,7 @@ struct BusContext BusRegistry *registry; BusPolicy *policy; DBusUserDatabase *user_database; - long max_incoming_bytes; /**< How many incoming messages for a connection */ - long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a connection */ - long max_message_size; /**< Max size of a single message in bytes */ - 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 */ - int max_incomplete_connections; /**< Max number of incomplete connections */ - int max_connections_per_user; /**< Max number of connections auth'd as same user */ + BusLimits limits; }; static int server_data_slot = -1; @@ -215,10 +208,10 @@ new_connection_callback (DBusServer *server, } dbus_connection_set_max_received_size (new_connection, - context->max_incoming_bytes); + context->limits.max_incoming_bytes); dbus_connection_set_max_message_size (new_connection, - context->max_message_size); + context->limits.max_message_size); /* on OOM, we won't have ref'd the connection so it will die. */ } @@ -357,38 +350,14 @@ bus_context_new (const DBusString *config_file, context->refcount = 1; + /* get our limits and timeout lengths */ + bus_config_parser_get_limits (parser, &context->limits); + /* we need another ref of the server data slot for the context * to own */ if (!server_data_slot_ref ()) _dbus_assert_not_reached ("second ref of server data slot failed"); - - /* Make up some numbers! woot! */ - context->max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63; - context->max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63; - context->max_message_size = _DBUS_ONE_MEGABYTE * 32; - -#ifdef DBUS_BUILD_TESTS - context->activation_timeout = 6000; /* 6 seconds */ -#else - context->activation_timeout = 15000; /* 15 seconds */ -#endif - - /* 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. - * Ultimately it needs to come from the configuration file. - */ - context->auth_timeout = 3000; /* 3 seconds */ - - context->max_incomplete_connections = 32; - context->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. - */ - context->max_completed_connections = 1024; context->user_database = _dbus_user_database_new (); if (context->user_database == NULL) @@ -829,31 +798,31 @@ int bus_context_get_activation_timeout (BusContext *context) { - return context->activation_timeout; + return context->limits.activation_timeout; } int bus_context_get_auth_timeout (BusContext *context) { - return context->auth_timeout; + return context->limits.auth_timeout; } int bus_context_get_max_completed_connections (BusContext *context) { - return context->max_completed_connections; + return context->limits.max_completed_connections; } int bus_context_get_max_incomplete_connections (BusContext *context) { - return context->max_incomplete_connections; + return context->limits.max_incomplete_connections; } int bus_context_get_max_connections_per_user (BusContext *context) { - return context->max_connections_per_user; + return context->limits.max_connections_per_user; } dbus_bool_t @@ -919,7 +888,7 @@ bus_context_check_security_policy (BusContext *context, /* See if limits on size have been exceeded */ if (recipient && dbus_connection_get_outgoing_size (recipient) > - context->max_outgoing_bytes) + context->limits.max_outgoing_bytes) { const char *dest = dbus_message_get_destination (message); dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, diff --git a/bus/bus.h b/bus/bus.h index e4e6dabe..7cffb33a 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -41,6 +41,19 @@ typedef struct BusRegistry BusRegistry; typedef struct BusService BusService; typedef struct BusTransaction BusTransaction; + +typedef struct +{ + long max_incoming_bytes; /**< How many incoming messages for a connection */ + long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a connection */ + long max_message_size; /**< Max size of a single message in bytes */ + 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 */ + int max_incomplete_connections; /**< Max number of incomplete connections */ + int max_connections_per_user; /**< Max number of connections auth'd as same user */ +} BusLimits; + BusContext* bus_context_new (const DBusString *config_file, int print_addr_fd, DBusError *error); diff --git a/bus/config-parser.c b/bus/config-parser.c index bf959ae2..bd1c47b8 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -78,6 +78,12 @@ typedef struct unsigned long gid_or_uid; } policy; + struct + { + char *name; + long value; + } limit; + } d; } Element; @@ -101,6 +107,8 @@ struct BusConfigParser DBusList *service_dirs; /**< Directories to look for services in */ BusPolicy *policy; /**< Security policy */ + + BusLimits limits; /**< Limits */ unsigned int fork : 1; /**< TRUE to fork into daemon mode */ @@ -175,7 +183,9 @@ push_element (BusConfigParser *parser, static void element_free (Element *e) { - + if (e->type == ELEMENT_LIMIT) + dbus_free (e->d.limit.name); + dbus_free (e); } @@ -280,6 +290,32 @@ bus_config_parser_new (const DBusString *basedir) dbus_free (parser); 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; + +#ifdef DBUS_BUILD_TESTS + parser->limits.activation_timeout = 6000; /* 6 seconds */ +#else + parser->limits.activation_timeout = 15000; /* 15 seconds */ +#endif + + /* 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 = 3000; /* 3 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->refcount = 1; @@ -711,6 +747,41 @@ start_busconfig_child (BusConfigParser *parser, _dbus_assert_not_reached ("all attributes null and we didn't set error"); } + return TRUE; + } + else if (strcmp (element_name, "limit") == 0) + { + Element *e; + const char *name; + + if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!locate_attributes (parser, "limit", + attribute_names, + attribute_values, + error, + "name", &name, + NULL)) + return FALSE; + + if (name == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " element must have a \"name\" attribute"); + return FALSE; + } + + e->d.limit.name = _dbus_strdup (name); + if (e->d.limit.name == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + return TRUE; } else @@ -1087,6 +1158,91 @@ bus_config_parser_start_element (BusConfigParser *parser, } } +static dbus_bool_t +set_limit (BusConfigParser *parser, + const char *name, + long value, + DBusError *error) +{ + dbus_bool_t must_be_positive; + dbus_bool_t must_be_int; + + must_be_int = FALSE; + must_be_positive = FALSE; + + if (strcmp (name, "max_incoming_bytes") == 0) + { + must_be_positive = TRUE; + parser->limits.max_incoming_bytes = value; + } + else if (strcmp (name, "max_outgoing_bytes") == 0) + { + must_be_positive = TRUE; + parser->limits.max_outgoing_bytes = value; + } + else if (strcmp (name, "max_message_size") == 0) + { + must_be_positive = TRUE; + parser->limits.max_message_size = value; + } + else if (strcmp (name, "activation_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.activation_timeout = value; + } + else if (strcmp (name, "auth_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.auth_timeout = value; + } + else if (strcmp (name, "max_completed_connections") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_completed_connections = value; + } + else if (strcmp (name, "max_incomplete_connections") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_incomplete_connections = value; + } + else if (strcmp (name, "max_connections_per_user") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_connections_per_user = value; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "There is no limit called \"%s\"\n", + name); + return FALSE; + } + + if (must_be_positive && value < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " must be a positive number\n", + name); + return FALSE; + } + + if (must_be_int && + (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " value is too large\n", + name); + return FALSE; + } + + return TRUE; +} + dbus_bool_t bus_config_parser_end_element (BusConfigParser *parser, const char *element_name, @@ -1142,6 +1298,7 @@ bus_config_parser_end_element (BusConfigParser *parser, case ELEMENT_AUTH: case ELEMENT_SERVICEDIR: case ELEMENT_INCLUDEDIR: + case ELEMENT_LIMIT: if (!e->had_content) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -1149,11 +1306,17 @@ bus_config_parser_end_element (BusConfigParser *parser, element_type_to_name (e->type)); return FALSE; } + + if (e->type == ELEMENT_LIMIT) + { + if (!set_limit (parser, e->d.limit.name, e->d.limit.value, + error)) + return FALSE; + } break; case ELEMENT_BUSCONFIG: case ELEMENT_POLICY: - case ELEMENT_LIMIT: case ELEMENT_ALLOW: case ELEMENT_DENY: case ELEMENT_FORK: @@ -1359,7 +1522,6 @@ bus_config_parser_content (BusConfigParser *parser, case ELEMENT_BUSCONFIG: case ELEMENT_POLICY: - case ELEMENT_LIMIT: case ELEMENT_ALLOW: case ELEMENT_DENY: case ELEMENT_FORK: @@ -1534,6 +1696,29 @@ bus_config_parser_content (BusConfigParser *parser, _dbus_string_free (&full_path); } break; + + case ELEMENT_LIMIT: + { + long val; + + e->had_content = TRUE; + + val = 0; + if (!_dbus_string_parse_int (content, 0, &val, NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " element has invalid value (could not parse as integer)", + e->d.limit.name); + return FALSE; + } + + e->d.limit.value = val; + + _dbus_verbose ("Loaded value %ld for limit %s\n", + e->d.limit.value, + e->d.limit.name); + } + break; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1625,6 +1810,14 @@ bus_config_parser_steal_policy (BusConfigParser *parser) return policy; } +/* Overwrite any limits that were set in the configuration file */ +void +bus_config_parser_get_limits (BusConfigParser *parser, + BusLimits *limits) +{ + *limits = parser->limits; +} + #ifdef DBUS_BUILD_TESTS #include diff --git a/bus/config-parser.h b/bus/config-parser.h index 15644ee6..acf868ef 100644 --- a/bus/config-parser.h +++ b/bus/config-parser.h @@ -64,6 +64,8 @@ dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser); const char* bus_config_parser_get_pidfile (BusConfigParser *parser); DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser); BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser); +void bus_config_parser_get_limits (BusConfigParser *parser, + BusLimits *limits); /* Loader functions (backended off one of the XML parsers). Returns a * finished ConfigParser. diff --git a/doc/config-file.txt b/doc/config-file.txt index 62bb4137..ed3cdfab 100644 --- a/doc/config-file.txt +++ b/doc/config-file.txt @@ -131,7 +131,35 @@ Elements: Appears below a element and establishes a resource limit. For example: 64 - 512 + 512 + + Available limits are: + "max_incoming_bytes" : total size in bytes of messages + incoming from a connection + "max_outgoing_bytes" : total size in bytes of messages + queued up for a connection + "max_message_size" : max size of a single message in + bytes + "activation_timeout" : milliseconds (thousandths) until + an activated service has to connect + "auth_timeout" : milliseconds (thousandths) a + connection is given to + authenticate + "max_completed_connections" : max number of authenticated connections + "max_incomplete_connections" : max number of unauthenticated + connections + "max_connections_per_user" : max number of completed connections from + the same user + + Some notes: + + - the max incoming/outgoing queue sizes allow a new message + to be queued if one byte remains below the max. So you can + in fact exceed the max by max_message_size + + - max_completed_connections / max_connections_per_user is + the number of users that can work together to DOS all + other users by using up all connections send="messagename" diff --git a/test/data/valid-config-files/basic.conf b/test/data/valid-config-files/basic.conf index d109d71d..5addd692 100644 --- a/test/data/valid-config-files/basic.conf +++ b/test/data/valid-config-files/basic.conf @@ -10,4 +10,14 @@ + + 5000 + 5000 + 300 + 5000 + 6000 + 50 + 80 + 64 + -- cgit