X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fconfig-parser.c;h=5e279639cabf1be93f911bce5b593f09e964cf44;hb=b3bd48edfc1aab0a9dc64bfa4c380d845d218e73;hp=780d1757d6400e50e9a33873855bc0c49bbc9ad8;hpb=bc983ecf15455f49e7a92d038c93e181ae2cb438;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/config-parser.c b/bus/config-parser.c index 780d175..5e27963 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -47,6 +47,18 @@ typedef enum 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; @@ -62,17 +74,16 @@ typedef struct 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; @@ -96,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 */ @@ -170,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); } @@ -268,10 +283,42 @@ bus_config_parser_new (const DBusString *basedir) 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; + +#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 = 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; @@ -634,6 +681,8 @@ start_busconfig_child (BusConfigParser *parser, return FALSE; } + e->d.policy.type = POLICY_IGNORED; + if (!locate_attributes (parser, "policy", attribute_names, attribute_values, @@ -658,11 +707,11 @@ start_busconfig_child (BusConfigParser *parser, { if (strcmp (context, "default") == 0) { - + e->d.policy.type = POLICY_DEFAULT; } else if (strcmp (context, "mandatory") == 0) { - + e->d.policy.type = POLICY_MANDATORY; } else { @@ -671,19 +720,30 @@ start_busconfig_child (BusConfigParser *parser, context); return FALSE; } - - /* FIXME */ - } else if (user != NULL) { - /* FIXME */ + 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) { - /* FIXME */ + 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 { @@ -692,6 +752,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, + " 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, @@ -702,6 +797,266 @@ start_busconfig_child (BusConfigParser *parser, } 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) +{ + 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; + + 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; + } + + 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; + } + + 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) + { + 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)) + { + 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; + + _dbus_string_init_const (&username, user); + + if (_dbus_get_user_id (&username, &uid)) + { + 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; + + rule->d.group.gid = DBUS_GID_UNSET; + } + else + { + 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 + _dbus_assert_not_reached ("Did not handle some combination of attributes on or "); + + if (rule != NULL) + { + 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, @@ -710,6 +1065,11 @@ start_policy_child (BusConfigParser *parser, { 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); @@ -720,6 +1080,11 @@ start_policy_child (BusConfigParser *parser, } 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); @@ -796,6 +1161,103 @@ 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 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, + " 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, @@ -851,6 +1313,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, @@ -858,11 +1321,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: @@ -1068,7 +1537,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: @@ -1243,6 +1711,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); @@ -1334,6 +1825,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