summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-04-24 22:30:38 +0000
committerHavoc Pennington <hp@redhat.com>2003-04-24 22:30:38 +0000
commit3185d7edde8ffc7672aa7d771966b0f1e0158aea (patch)
tree03f33d4ca7737d26badd04f2fd6ee95db0ffdba7
parent1820f3bd0a5a4b0ab14dbcc80ba1b68d2c48e01d (diff)
2003-04-24 Havoc Pennington <hp@redhat.com>
* test/data/valid-config-files/basic.conf: add <limit> tags to this test * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement <limit> tag in configuration file.
-rw-r--r--ChangeLog8
-rw-r--r--bus/bus.c55
-rw-r--r--bus/bus.h13
-rw-r--r--bus/config-parser.c199
-rw-r--r--bus/config-parser.h2
-rw-r--r--doc/config-file.txt30
-rw-r--r--test/data/valid-config-files/basic.conf10
7 files changed, 270 insertions, 47 deletions
diff --git a/ChangeLog b/ChangeLog
index f770a533..7accabfb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2003-04-24 Havoc Pennington <hp@redhat.com>
+ * test/data/valid-config-files/basic.conf: add <limit> tags to
+ this test
+
+ * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement
+ <limit> tag in configuration file.
+
+2003-04-24 Havoc Pennington <hp@redhat.com>
+
* bus/dispatch.c: somehow missed some name_is
* dbus/dbus-timeout.c (_dbus_timeout_set_enabled)
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;
@@ -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.
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 <policy> element and establishes a resource
limit. For example:
<limit name="max_message_size">64</limit>
- <limit name="max_connections">512</limit>
+ <limit name="max_completed_connections">512</limit>
+
+ 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
<deny>
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 @@
<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>
+
</busconfig>