*/
#include "config-parser.h"
#include "test.h"
+#include "utils.h"
+#include "policy.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-internals.h>
#include <string.h>
ELEMENT_POLICY,
ELEMENT_LIMIT,
ELEMENT_ALLOW,
- ELEMENT_DENY
+ ELEMENT_DENY,
+ ELEMENT_FORK,
+ ELEMENT_PIDFILE,
+ ELEMENT_SERVICEDIR,
+ ELEMENT_INCLUDEDIR,
+ ELEMENT_TYPE
} ElementType;
+typedef enum
+{
+ /* we ignore policies for unknown groups/users */
+ POLICY_IGNORED,
+
+ /* non-ignored */
+ POLICY_DEFAULT,
+ POLICY_MANDATORY,
+ POLICY_USER,
+ POLICY_GROUP
+} PolicyType;
+
typedef struct
{
ElementType type;
struct
{
- char *mechanism;
- } auth;
-
- struct
- {
- char *context;
- char *user;
- char *group;
- DBusList *rules;
+ PolicyType type;
+ unsigned long gid_or_uid;
} policy;
struct
{
- int foo;
+ char *name;
+ long value;
} limit;
-
+
} d;
} Element;
{
int refcount;
+ DBusString basedir; /**< Directory we resolve paths relative to */
+
DBusList *stack; /**< stack of Element */
char *user; /**< user to run as */
+ char *bus_type; /**< Message bus type */
+
DBusList *listen_on; /**< List of addresses to listen to */
+
+ DBusList *mechanisms; /**< Auth mechanisms */
+
+ 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 */
+
+ char *pidfile;
};
static const char*
return "allow";
case ELEMENT_DENY:
return "deny";
+ case ELEMENT_FORK:
+ return "fork";
+ case ELEMENT_PIDFILE:
+ return "pidfile";
+ case ELEMENT_SERVICEDIR:
+ return "servicedir";
+ case ELEMENT_INCLUDEDIR:
+ return "includedir";
+ case ELEMENT_TYPE:
+ return "type";
}
_dbus_assert_not_reached ("bad element type");
static void
element_free (Element *e)
{
-
+ if (e->type == ELEMENT_LIMIT)
+ dbus_free (e->d.limit.name);
+
dbus_free (e);
}
included->user = NULL;
}
+ if (included->bus_type != NULL)
+ {
+ dbus_free (parser->bus_type);
+ parser->bus_type = included->bus_type;
+ included->bus_type = NULL;
+ }
+
+ if (included->fork)
+ parser->fork = TRUE;
+
+ if (included->pidfile != NULL)
+ {
+ dbus_free (parser->pidfile);
+ parser->pidfile = included->pidfile;
+ included->pidfile = NULL;
+ }
+
while ((link = _dbus_list_pop_first_link (&included->listen_on)))
_dbus_list_append_link (&parser->listen_on, link);
+ while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
+ _dbus_list_append_link (&parser->mechanisms, link);
+
+ while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
+ _dbus_list_append_link (&parser->service_dirs, link);
+
return TRUE;
}
BusConfigParser*
-bus_config_parser_new (void)
+bus_config_parser_new (const DBusString *basedir)
{
BusConfigParser *parser;
if (parser == NULL)
return NULL;
+ if (!_dbus_string_init (&parser->basedir))
+ {
+ dbus_free (parser);
+ return NULL;
+ }
+
+ if (((parser->policy = bus_policy_new ()) == NULL) ||
+ !_dbus_string_copy (basedir, 0, &parser->basedir, 0))
+ {
+ if (parser->policy)
+ bus_policy_unref (parser->policy);
+
+ _dbus_string_free (&parser->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;
+
+ /* 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->refcount = 1;
return parser;
pop_element (parser);
dbus_free (parser->user);
-
+ dbus_free (parser->bus_type);
+ dbus_free (parser->pidfile);
+
_dbus_list_foreach (&parser->listen_on,
(DBusForeachFunction) dbus_free,
NULL);
_dbus_list_clear (&parser->listen_on);
+ _dbus_list_foreach (&parser->service_dirs,
+ (DBusForeachFunction) dbus_free,
+ NULL);
+
+ _dbus_list_clear (&parser->service_dirs);
+
+ _dbus_list_foreach (&parser->mechanisms,
+ (DBusForeachFunction) dbus_free,
+ NULL);
+
+ _dbus_list_clear (&parser->mechanisms);
+
+ _dbus_string_free (&parser->basedir);
+
+ if (parser->policy)
+ bus_policy_unref (parser->policy);
+
dbus_free (parser);
}
}
if (push_element (parser, ELEMENT_USER) == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "type") == 0)
+ {
+ if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_TYPE) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "fork") == 0)
+ {
+ if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_FORK) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ parser->fork = TRUE;
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "pidfile") == 0)
+ {
+ if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_PIDFILE) == NULL)
+ {
+ BUS_SET_OOM (error);
return FALSE;
}
if (push_element (parser, ELEMENT_LISTEN) == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "auth") == 0)
+ {
+ if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_AUTH) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "includedir") == 0)
+ {
+ if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "servicedir") == 0)
+ {
+ if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
+ {
+ BUS_SET_OOM (error);
return FALSE;
}
if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
return FALSE;
}
if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
return FALSE;
}
- if (!locate_attributes (parser, "include",
+ e->d.policy.type = POLICY_IGNORED;
+
+ if (!locate_attributes (parser, "policy",
attribute_names,
attribute_values,
error,
NULL))
return FALSE;
- /* FIXME */
+ if (((context && user) ||
+ (context && group)) ||
+ (user && group) ||
+ !(context || user || group))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "<policy> element must have exactly one of (context|user|group) attributes");
+ return FALSE;
+ }
+
+ if (context != NULL)
+ {
+ if (strcmp (context, "default") == 0)
+ {
+ e->d.policy.type = POLICY_DEFAULT;
+ }
+ else if (strcmp (context, "mandatory") == 0)
+ {
+ e->d.policy.type = POLICY_MANDATORY;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
+ context);
+ return FALSE;
+ }
+ }
+ else if (user != NULL)
+ {
+ DBusString username;
+ _dbus_string_init_const (&username, user);
+
+ if (_dbus_get_user_id (&username,
+ &e->d.policy.gid_or_uid))
+ e->d.policy.type = POLICY_USER;
+ else
+ _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
+ user);
+ }
+ else if (group != NULL)
+ {
+ DBusString group_name;
+ _dbus_string_init_const (&group_name, group);
+
+ if (_dbus_get_group_id (&group_name,
+ &e->d.policy.gid_or_uid))
+ e->d.policy.type = POLICY_GROUP;
+ else
+ _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
+ group);
+ }
+ else
+ {
+ _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
+ }
return TRUE;
}
- else
+ else if (strcmp (element_name, "limit") == 0)
{
- dbus_set_error (error, DBUS_ERROR_FAILED,
- "Element <%s> not allowed inside <%s> in configuration file",
- element_name, "busconfig");
- return FALSE;
- }
-}
+ Element *e;
+ const char *name;
-static dbus_bool_t
-start_policy_child (BusConfigParser *parser,
- const char *element_name,
- const char **attribute_names,
- const char **attribute_values,
- DBusError *error)
-{
- if (strcmp (element_name, "allow") == 0)
- {
- if (push_element (parser, ELEMENT_ALLOW) == NULL)
+ if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
return FALSE;
}
- return TRUE;
- }
- else if (strcmp (element_name, "deny") == 0)
- {
- if (push_element (parser, ELEMENT_DENY) == NULL)
+ if (!locate_attributes (parser, "limit",
+ attribute_names,
+ attribute_values,
+ error,
+ "name", &name,
+ NULL))
+ return FALSE;
+
+ if (name == NULL)
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 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,
"Element <%s> not allowed inside <%s> in configuration file",
- element_name, "policy");
+ element_name, "busconfig");
return FALSE;
}
}
-dbus_bool_t
-bus_config_parser_start_element (BusConfigParser *parser,
- const char *element_name,
- const char **attribute_names,
- const char **attribute_values,
- DBusError *error)
+static dbus_bool_t
+append_rule_from_element (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ dbus_bool_t allow,
+ DBusError *error)
{
- ElementType t;
-
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ const char *send;
+ const char *receive;
+ const char *own;
+ const char *send_to;
+ const char *receive_from;
+ const char *user;
+ const char *group;
+ BusPolicyRule *rule;
+
+ if (!locate_attributes (parser, element_name,
+ attribute_names,
+ attribute_values,
+ error,
+ "send", &send,
+ "receive", &receive,
+ "own", &own,
+ "send_to", &send_to,
+ "receive_from", &receive_from,
+ "user", &user,
+ "group", &group,
+ NULL))
+ return FALSE;
- /* printf ("START: %s\n", element_name); */
+ if (!(send || receive || own || send_to || receive_from ||
+ user || group))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> must have one or more attributes",
+ element_name);
+ return FALSE;
+ }
- t = top_element_type (parser);
+ if (((send && own) ||
+ (send && receive) ||
+ (send && receive_from) ||
+ (send && user) ||
+ (send && group)) ||
+
+ ((receive && own) ||
+ (receive && send_to) ||
+ (receive && user) ||
+ (receive && group)) ||
+
+ ((own && send_to) ||
+ (own && receive_from) ||
+ (own && user) ||
+ (own && group)) ||
+
+ ((send_to && receive_from) ||
+ (send_to && user) ||
+ (send_to && group)) ||
+
+ ((receive_from && user) ||
+ (receive_from && group)) ||
+
+ (user && group))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Invalid combination of attributes on element <%s>, "
+ "only send/send_to or receive/receive_from may be paired",
+ element_name);
+ return FALSE;
+ }
- if (t == ELEMENT_NONE)
+ rule = NULL;
+
+ /* In BusPolicyRule, NULL represents wildcard.
+ * In the config file, '*' represents it.
+ */
+#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
+
+ if (send || send_to)
{
- if (strcmp (element_name, "busconfig") == 0)
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ if (IS_WILDCARD (send))
+ send = NULL;
+ if (IS_WILDCARD (send_to))
+ send_to = NULL;
+
+ rule->d.send.message_name = _dbus_strdup (send);
+ rule->d.send.destination = _dbus_strdup (send_to);
+ if (send && rule->d.send.message_name == NULL)
+ goto nomem;
+ if (send_to && rule->d.send.destination == NULL)
+ goto nomem;
+ }
+ else if (receive || receive_from)
+ {
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ if (IS_WILDCARD (receive))
+ receive = NULL;
+
+ if (IS_WILDCARD (receive_from))
+ receive_from = NULL;
+
+ rule->d.receive.message_name = _dbus_strdup (receive);
+ rule->d.receive.origin = _dbus_strdup (receive_from);
+ if (receive && rule->d.receive.message_name == NULL)
+ goto nomem;
+ if (receive_from && rule->d.receive.origin == NULL)
+ goto nomem;
+ }
+ else if (own)
+ {
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ if (IS_WILDCARD (own))
+ own = NULL;
+
+ rule->d.own.service_name = _dbus_strdup (own);
+ if (own && rule->d.own.service_name == NULL)
+ goto nomem;
+ }
+ else if (user)
+ {
+ if (IS_WILDCARD (user))
{
- if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
- return FALSE;
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ rule->d.user.uid = DBUS_UID_UNSET;
+ }
+ else
+ {
+ DBusString username;
+ dbus_uid_t uid;
- if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
+ _dbus_string_init_const (&username, user);
+
+ if (_dbus_get_user_id (&username, &uid))
{
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
- return FALSE;
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ rule->d.user.uid = uid;
}
+ else
+ {
+ _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
+ user, element_name);
+ }
+ }
+ }
+ else if (group)
+ {
+ if (IS_WILDCARD (group))
+ {
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
+ if (rule == NULL)
+ goto nomem;
- return TRUE;
+ rule->d.group.gid = DBUS_GID_UNSET;
}
else
{
- dbus_set_error (error, DBUS_ERROR_FAILED,
- "Unknown element <%s> at root of configuration file",
- element_name);
- return FALSE;
+ DBusString groupname;
+ dbus_gid_t gid;
+
+ _dbus_string_init_const (&groupname, group);
+
+ if (_dbus_get_user_id (&groupname, &gid))
+ {
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
+ if (rule == NULL)
+ goto nomem;
+
+ rule->d.group.gid = gid;
+ }
+ else
+ {
+ _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
+ group, element_name);
+ }
}
}
- else if (t == ELEMENT_BUSCONFIG)
- {
- return start_busconfig_child (parser, element_name,
- attribute_names, attribute_values,
- error);
- }
- else if (t == ELEMENT_POLICY)
+ else
+ _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
+
+ if (rule != NULL)
{
- return start_policy_child (parser, element_name,
- attribute_names, attribute_values,
+ Element *pe;
+
+ pe = peek_element (parser);
+ _dbus_assert (pe != NULL);
+ _dbus_assert (pe->type == ELEMENT_POLICY);
+
+ switch (pe->d.policy.type)
+ {
+ case POLICY_IGNORED:
+ /* drop the rule on the floor */
+ break;
+
+ case POLICY_DEFAULT:
+ if (!bus_policy_append_default_rule (parser->policy, rule))
+ goto nomem;
+ break;
+ case POLICY_MANDATORY:
+ if (!bus_policy_append_mandatory_rule (parser->policy, rule))
+ goto nomem;
+ break;
+ case POLICY_USER:
+ if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "<%s> rule cannot be per-user because it has bus-global semantics",
+ element_name);
+ goto failed;
+ }
+
+ if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_or_uid,
+ rule))
+ goto nomem;
+ break;
+ case POLICY_GROUP:
+ if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "<%s> rule cannot be per-group because it has bus-global semantics",
+ element_name);
+ goto failed;
+ }
+
+ if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_or_uid,
+ rule))
+ goto nomem;
+ break;
+ }
+
+ bus_policy_rule_unref (rule);
+ rule = NULL;
+ }
+
+ return TRUE;
+
+ nomem:
+ BUS_SET_OOM (error);
+ failed:
+ if (rule)
+ bus_policy_rule_unref (rule);
+ return FALSE;
+}
+
+static dbus_bool_t
+start_policy_child (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error)
+{
+ if (strcmp (element_name, "allow") == 0)
+ {
+ if (!append_rule_from_element (parser, element_name,
+ attribute_names, attribute_values,
+ TRUE, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_ALLOW) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "deny") == 0)
+ {
+ if (!append_rule_from_element (parser, element_name,
+ attribute_names, attribute_values,
+ FALSE, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_DENY) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> not allowed inside <%s> in configuration file",
+ element_name, "policy");
+ return FALSE;
+ }
+}
+
+dbus_bool_t
+bus_config_parser_start_element (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error)
+{
+ ElementType t;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ /* printf ("START: %s\n", element_name); */
+
+ t = top_element_type (parser);
+
+ if (t == ELEMENT_NONE)
+ {
+ if (strcmp (element_name, "busconfig") == 0)
+ {
+ if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Unknown element <%s> at root of configuration file",
+ element_name);
+ return FALSE;
+ }
+ }
+ else if (t == ELEMENT_BUSCONFIG)
+ {
+ return start_busconfig_child (parser, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (t == ELEMENT_POLICY)
+ {
+ return start_policy_child (parser, element_name,
+ attribute_names, attribute_values,
error);
}
else
}
}
+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 if (strcmp (name, "max_pending_activations") == 0)
+ {
+ must_be_positive = TRUE;
+ must_be_int = TRUE;
+ parser->limits.max_pending_activations = value;
+ }
+ else if (strcmp (name, "max_services_per_connection") == 0)
+ {
+ must_be_positive = TRUE;
+ must_be_int = TRUE;
+ parser->limits.max_services_per_connection = 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,
* being paranoid about XML parsers
*/
dbus_set_error (error, DBUS_ERROR_FAILED,
- "XML element ended which was not the topmost element on the stack");
+ "XML element <%s> ended but topmost element on the stack was <%s>",
+ element_name, n);
return FALSE;
}
case ELEMENT_INCLUDE:
case ELEMENT_USER:
+ case ELEMENT_TYPE:
case ELEMENT_LISTEN:
+ case ELEMENT_PIDFILE:
case ELEMENT_AUTH:
+ case ELEMENT_SERVICEDIR:
+ case ELEMENT_INCLUDEDIR:
+ case ELEMENT_LIMIT:
if (!e->had_content)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
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:
break;
}
return i == _dbus_string_get_length (str);
}
+static dbus_bool_t
+make_full_path (const DBusString *basedir,
+ const DBusString *filename,
+ DBusString *full_path)
+{
+ if (_dbus_path_is_absolute (filename))
+ {
+ return _dbus_string_copy (filename, 0, full_path, 0);
+ }
+ else
+ {
+ if (!_dbus_string_copy (basedir, 0, full_path, 0))
+ return FALSE;
+
+ if (!_dbus_concat_dir_and_file (full_path, filename))
+ return FALSE;
+
+ return TRUE;
+ }
+}
+
+static dbus_bool_t
+include_file (BusConfigParser *parser,
+ const DBusString *filename,
+ dbus_bool_t ignore_missing,
+ DBusError *error)
+{
+ /* FIXME good test case for this would load each config file in the
+ * test suite both alone, and as an include, and check
+ * that the result is the same
+ */
+ BusConfigParser *included;
+ DBusError tmp_error;
+
+ dbus_error_init (&tmp_error);
+ included = bus_config_load (filename, &tmp_error);
+ if (included == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+
+ if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
+ ignore_missing)
+ {
+ dbus_error_free (&tmp_error);
+ return TRUE;
+ }
+ else
+ {
+ dbus_move_error (&tmp_error, error);
+ return FALSE;
+ }
+ }
+ else
+ {
+ _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+
+ if (!merge_included (parser, included, error))
+ {
+ bus_config_parser_unref (included);
+ return FALSE;
+ }
+
+ bus_config_parser_unref (included);
+ return TRUE;
+ }
+}
+
+static dbus_bool_t
+include_dir (BusConfigParser *parser,
+ const DBusString *dirname,
+ DBusError *error)
+{
+ DBusString filename;
+ dbus_bool_t retval;
+ DBusError tmp_error;
+ DBusDirIter *dir;
+
+ if (!_dbus_string_init (&filename))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ retval = FALSE;
+
+ dir = _dbus_directory_open (dirname, error);
+
+ if (dir == NULL)
+ goto failed;
+
+ dbus_error_init (&tmp_error);
+ while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
+ {
+ DBusString full_path;
+
+ if (!_dbus_string_init (&full_path))
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
+ if (!_dbus_string_copy (dirname, 0, &full_path, 0))
+ {
+ BUS_SET_OOM (error);
+ _dbus_string_free (&full_path);
+ goto failed;
+ }
+
+ if (!_dbus_concat_dir_and_file (&full_path, &filename))
+ {
+ BUS_SET_OOM (error);
+ _dbus_string_free (&full_path);
+ goto failed;
+ }
+
+ if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
+ {
+ if (!include_file (parser, &full_path, TRUE, error))
+ {
+ _dbus_string_free (&full_path);
+ goto failed;
+ }
+ }
+
+ _dbus_string_free (&full_path);
+ }
+
+ if (dbus_error_is_set (&tmp_error))
+ {
+ dbus_move_error (&tmp_error, error);
+ goto failed;
+ }
+
+ retval = TRUE;
+
+ failed:
+ _dbus_string_free (&filename);
+
+ if (dir)
+ _dbus_directory_close (dir);
+
+ return retval;
+}
+
dbus_bool_t
bus_config_parser_content (BusConfigParser *parser,
const DBusString *content,
case ELEMENT_BUSCONFIG:
case ELEMENT_POLICY:
- case ELEMENT_LIMIT:
case ELEMENT_ALLOW:
case ELEMENT_DENY:
+ case ELEMENT_FORK:
if (all_whitespace (content))
return TRUE;
else
return FALSE;
}
- case ELEMENT_INCLUDE:
+ case ELEMENT_PIDFILE:
{
- /* FIXME good test case for this would load each config file in the
- * test suite both alone, and as an include, and check
- * that the result is the same
- */
- BusConfigParser *included;
- DBusError tmp_error;
+ char *s;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_copy_data (content, &s))
+ goto nomem;
+
+ dbus_free (parser->pidfile);
+ parser->pidfile = s;
+ }
+ break;
+ case ELEMENT_INCLUDE:
+ {
+ DBusString full_path;
+
e->had_content = TRUE;
+
+ if (!_dbus_string_init (&full_path))
+ goto nomem;
- dbus_error_init (&tmp_error);
- included = bus_config_load (content, &tmp_error);
- if (included == NULL)
+ if (!make_full_path (&parser->basedir, content, &full_path))
{
- _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
- if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
- e->d.include.ignore_missing)
- {
- dbus_error_free (&tmp_error);
- return TRUE;
- }
- else
- {
- dbus_move_error (&tmp_error, error);
- return FALSE;
- }
+ _dbus_string_free (&full_path);
+ goto nomem;
}
- else
+
+ if (!include_file (parser, &full_path,
+ e->d.include.ignore_missing, error))
{
- _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+ _dbus_string_free (&full_path);
+ return FALSE;
+ }
- if (!merge_included (parser, included, error))
- return FALSE;
+ _dbus_string_free (&full_path);
+ }
+ break;
+
+ case ELEMENT_INCLUDEDIR:
+ {
+ DBusString full_path;
+
+ e->had_content = TRUE;
- bus_config_parser_unref (included);
- return TRUE;
+ if (!_dbus_string_init (&full_path))
+ goto nomem;
+
+ if (!make_full_path (&parser->basedir, content, &full_path))
+ {
+ _dbus_string_free (&full_path);
+ goto nomem;
+ }
+
+ if (!include_dir (parser, &full_path, error))
+ {
+ _dbus_string_free (&full_path);
+ return FALSE;
}
+
+ _dbus_string_free (&full_path);
}
break;
-
+
case ELEMENT_USER:
{
char *s;
}
break;
+ case ELEMENT_TYPE:
+ {
+ char *s;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_copy_data (content, &s))
+ goto nomem;
+
+ dbus_free (parser->bus_type);
+ parser->bus_type = s;
+ }
+ break;
+
case ELEMENT_LISTEN:
{
char *s;
case ELEMENT_AUTH:
{
+ char *s;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_copy_data (content, &s))
+ goto nomem;
+
+ if (!_dbus_list_append (&parser->mechanisms,
+ s))
+ {
+ dbus_free (s);
+ goto nomem;
+ }
+ }
+ break;
+
+ case ELEMENT_SERVICEDIR:
+ {
+ char *s;
+ DBusString full_path;
+
e->had_content = TRUE;
- /* FIXME */
+
+ if (!_dbus_string_init (&full_path))
+ goto nomem;
+
+ if (!make_full_path (&parser->basedir, content, &full_path))
+ {
+ _dbus_string_free (&full_path);
+ goto nomem;
+ }
+
+ if (!_dbus_string_copy_data (&full_path, &s))
+ {
+ _dbus_string_free (&full_path);
+ goto nomem;
+ }
+
+ if (!_dbus_list_append (&parser->service_dirs, s))
+ {
+ _dbus_string_free (&full_path);
+ dbus_free (s);
+ goto nomem;
+ }
+
+ _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;
}
return TRUE;
nomem:
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ BUS_SET_OOM (error);
return FALSE;
}
return FALSE;
}
+
+ if (parser->listen_on == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Configuration file needs one or more <listen> elements giving addresses");
+ return FALSE;
+ }
return TRUE;
}
return parser->user;
}
+const char*
+bus_config_parser_get_type (BusConfigParser *parser)
+{
+ return parser->bus_type;
+}
+
+DBusList**
+bus_config_parser_get_addresses (BusConfigParser *parser)
+{
+ return &parser->listen_on;
+}
+
+DBusList**
+bus_config_parser_get_mechanisms (BusConfigParser *parser)
+{
+ return &parser->mechanisms;
+}
+
+DBusList**
+bus_config_parser_get_service_dirs (BusConfigParser *parser)
+{
+ return &parser->service_dirs;
+}
+
+dbus_bool_t
+bus_config_parser_get_fork (BusConfigParser *parser)
+{
+ return parser->fork;
+}
+
+const char *
+bus_config_parser_get_pidfile (BusConfigParser *parser)
+{
+ return parser->pidfile;
+}
+
+BusPolicy*
+bus_config_parser_steal_policy (BusConfigParser *parser)
+{
+ BusPolicy *policy;
+
+ _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
+
+ policy = parser->policy;
+
+ parser->policy = NULL;
+
+ 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>
retval = FALSE;
dir = NULL;
- if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&test_directory))
_dbus_assert_not_reached ("didn't allocate test_directory\n");
_dbus_string_init_const (&filename, subdir);
_dbus_assert_not_reached ("couldn't allocate full path");
_dbus_string_free (&filename);
- if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&filename))
_dbus_assert_not_reached ("didn't allocate filename string\n");
dbus_error_init (&error);
dir = _dbus_directory_open (&test_directory, &error);
if (dir == NULL)
{
- const char *s;
- _dbus_string_get_const_data (&test_directory, &s);
- _dbus_warn ("Could not open %s: %s\n", s,
+ _dbus_warn ("Could not open %s: %s\n",
+ _dbus_string_get_const_data (&test_directory),
error.message);
dbus_error_free (&error);
goto failed;
DBusString full_path;
LoaderOomData d;
- if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
+ if (!_dbus_string_init (&full_path))
_dbus_assert_not_reached ("couldn't init string");
if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
{
- const char *filename_c;
- _dbus_string_get_const_data (&filename, &filename_c);
_dbus_verbose ("Skipping non-.conf file %s\n",
- filename_c);
+ _dbus_string_get_const_data (&filename));
_dbus_string_free (&full_path);
goto next;
}
- {
- const char *s;
- _dbus_string_get_const_data (&filename, &s);
- printf (" %s\n", s);
- }
+ printf (" %s\n", _dbus_string_get_const_data (&filename));
_dbus_verbose (" expecting %s\n",
validity == VALID ? "valid" :
if (dbus_error_is_set (&error))
{
- const char *s;
- _dbus_string_get_const_data (&test_directory, &s);
_dbus_warn ("Could not get next file in %s: %s\n",
- s, error.message);
+ _dbus_string_get_const_data (&test_directory),
+ error.message);
dbus_error_free (&error);
goto failed;
}