diff options
Diffstat (limited to 'bus')
-rw-r--r-- | bus/bus.c | 55 | ||||
-rw-r--r-- | bus/bus.h | 13 | ||||
-rw-r--r-- | bus/config-parser.c | 199 | ||||
-rw-r--r-- | bus/config-parser.h | 2 |
4 files changed, 223 insertions, 46 deletions
@@ -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, @@ -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; @@ -713,6 +749,41 @@ start_busconfig_child (BusConfigParser *parser, 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, + "<limit> 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 { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -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, + "<limit name=\"%s\"> 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, + "<limit name=\"%s\"> 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, + "<limit name=\"%s\"> 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 <stdio.h> 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. |