struct
{
PolicyType type;
- unsigned long gid_uid_or_at_console;
+ unsigned long gid_uid_or_at_console;
} policy;
struct
parser->limits.pending_fd_timeout = 150000; /* 2.5 minutes */
parser->limits.max_incomplete_connections = 64;
- parser->limits.max_connections_per_user = 256;
+ parser->limits.max_connections_per_user = 512; /* 256 -> 512 */
/* Note that max_completed_connections / max_connections_per_user
* is the number of users that would have to work together to
/* this is effectively a limit on message queue size for messages
* that require a reply
*/
- parser->limits.max_replies_per_connection = 128;
+ parser->limits.max_replies_per_connection = 1024; /* 128 -> 1024 */
}
parser->refcount = 1;
const char *name;
const char **retloc;
int n_attrs;
-#define MAX_ATTRS 24
+#define MAX_ATTRS 25
LocateAttr attrs[MAX_ATTRS];
dbus_bool_t retval;
int i;
}
}
+/*
+ * Parse an attribute named name, whose content is content, or NULL if
+ * missing. It is meant to be a (long) integer between min and max inclusive.
+ * If it is missing, use def as the default value (which does not
+ * necessarily need to be between min and max).
+ */
+static dbus_bool_t
+parse_int_attribute (const char *name,
+ const char *content,
+ long min,
+ long max,
+ long def,
+ long *value,
+ DBusError *error)
+{
+ DBusString parse_string;
+
+ *value = def;
+
+ if (content == NULL)
+ return TRUE;
+
+ _dbus_string_init_const (&parse_string, content);
+
+ if (!_dbus_string_parse_int (&parse_string, 0, value, NULL) ||
+ *value < min || *value > max)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Bad value \"%s\" for %s attribute, must be an "
+ "integer in range %ld to %ld inclusive",
+ content, name, min, max);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
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,
+ BusPolicyRuleAccess access,
DBusError *error)
{
const char *log;
const char *send_member;
const char *send_error;
const char *send_destination;
+ const char *send_destination_prefix;
const char *send_path;
const char *send_type;
const char *send_requested_reply;
/* Group: message-matching modifiers that can go on send_ or receive_ */
const char *eavesdrop;
+ const char *max_fds_attr;
+ long max_fds = DBUS_MAXIMUM_MESSAGE_UNIX_FDS;
+ const char *min_fds_attr;
+ long min_fds = 0;
/* TRUE if any message-matching modifier is present */
dbus_bool_t any_message_attribute;
const char *own_prefix;
const char *user;
const char *group;
+ const char *privilege;
BusPolicyRule *rule;
"send_member", &send_member,
"send_error", &send_error,
"send_destination", &send_destination,
+ "send_destination_prefix", &send_destination_prefix,
"send_path", &send_path,
"send_type", &send_type,
"send_broadcast", &send_broadcast,
"receive_path", &receive_path,
"receive_type", &receive_type,
"eavesdrop", &eavesdrop,
+ "max_fds", &max_fds_attr,
+ "min_fds", &min_fds_attr,
"send_requested_reply", &send_requested_reply,
"receive_requested_reply", &receive_requested_reply,
"own", &own,
"user", &user,
"group", &group,
"log", &log,
+ "privilege", &privilege,
NULL))
return FALSE;
any_send_attribute = (send_destination != NULL ||
+ send_destination_prefix != NULL ||
send_broadcast != NULL ||
send_path != NULL ||
send_type != NULL ||
(!any_send_attribute && eavesdrop != NULL));
any_message_attribute = (any_send_attribute ||
any_receive_attribute ||
- eavesdrop != NULL);
+ eavesdrop != NULL ||
+ max_fds_attr != NULL ||
+ min_fds_attr != NULL);
if (!(any_send_attribute ||
any_receive_attribute ||
+ privilege ||
own || own_prefix || user || group))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
element_name);
return FALSE;
}
-
+
+ if (access == BUS_POLICY_RULE_ACCESS_CHECK)
+ {
+ if (privilege == NULL || !*privilege)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "On element <%s>, you must specify the privilege to be checked.",
+ element_name);
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (privilege != NULL && *privilege)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "On element <%s>, privilege %s is used outside of a check rule.",
+ element_name, privilege);
+ return FALSE;
+ }
+ else
+ privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
+ }
+
/* Allowed combinations of elements are:
*
* base, must be all send or all receive:
* interface + member
* error
*
- * base send_ can combine with send_destination, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
+ * base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
+ * send_destination must not occur with send_destination_prefix
* base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
*
* user, group, own, own_prefix must occur alone
return FALSE;
}
+ if (send_destination != NULL &&
+ send_broadcast != NULL &&
+ strcmp (send_broadcast, "true") == 0)
+ {
+ /* Broadcast messages have no destination, so this cannot
+ * possibly match */
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Rule with send_broadcast=\"true\" and "
+ "send_destination=\"%s\" cannot match anything",
+ send_destination);
+ return FALSE;
+ }
+
if (send_requested_reply &&
!(strcmp (send_requested_reply, "true") == 0 ||
strcmp (send_requested_reply, "false") == 0))
"send_requested_reply", send_requested_reply);
return FALSE;
}
-
- rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
+
+ /* Matching only messages with DBUS_MAXIMUM_MESSAGE_UNIX_FDS or fewer
+ * fds is the same as matching all messages, so we always set a maximum,
+ * but perhaps an unrealistically high one. */
+ if (!parse_int_attribute ("max_fds", max_fds_attr,
+ 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS,
+ DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds,
+ error) ||
+ !parse_int_attribute ("min_fds", min_fds_attr,
+ 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds,
+ error))
+ return FALSE;
+
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
if (rule == NULL)
goto nomem;
rule->d.send.interface = _dbus_strdup (send_interface);
rule->d.send.member = _dbus_strdup (send_member);
rule->d.send.error = _dbus_strdup (send_error);
- rule->d.send.destination = _dbus_strdup (send_destination);
+ if (send_destination)
+ {
+ rule->d.send.destination = _dbus_strdup (send_destination);
+ rule->d.send.destination_prefix = 0;
+ }
+ else if (send_destination_prefix)
+ {
+ rule->d.send.destination = _dbus_strdup (send_destination_prefix);
+ rule->d.send.destination_prefix = 1;
+ }
+ rule->d.send.max_fds = max_fds;
+ rule->d.send.min_fds = min_fds;
+
if (send_path && rule->d.send.path == NULL)
goto nomem;
if (send_interface && rule->d.send.interface == NULL)
goto nomem;
if (send_error && rule->d.send.error == NULL)
goto nomem;
- if (send_destination && rule->d.send.destination == NULL)
+ if ((send_destination || send_destination_prefix) && rule->d.send.destination == NULL)
goto nomem;
}
else if (any_receive_attribute)
"receive_requested_reply", receive_requested_reply);
return FALSE;
}
-
- rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
+
+ if (!parse_int_attribute ("max_fds", max_fds_attr,
+ 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS,
+ DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds,
+ error) ||
+ !parse_int_attribute ("min_fds", min_fds_attr,
+ 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds,
+ error))
+ return FALSE;
+
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
if (rule == NULL)
goto nomem;
rule->d.receive.member = _dbus_strdup (receive_member);
rule->d.receive.error = _dbus_strdup (receive_error);
rule->d.receive.origin = _dbus_strdup (receive_sender);
+ rule->d.receive.max_fds = max_fds;
+ rule->d.receive.min_fds = min_fds;
if (receive_path && rule->d.receive.path == NULL)
goto nomem;
}
else if (own || own_prefix)
{
- rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow);
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
if (rule == NULL)
goto nomem;
{
if (IS_WILDCARD (user))
{
- rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
if (rule == NULL)
goto nomem;
if (_dbus_parse_unix_user_from_config (&username, &uid))
{
- rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
if (rule == NULL)
goto nomem;
{
if (IS_WILDCARD (group))
{
- rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
if (rule == NULL)
goto nomem;
if (_dbus_parse_unix_group_from_config (&groupname, &gid))
{
- rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
+ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
if (rule == NULL)
goto nomem;
_dbus_assert (pe != NULL);
_dbus_assert (pe->type == ELEMENT_POLICY);
+ rule->privilege = _dbus_strdup (privilege);
+ if (privilege && !rule->privilege)
+ goto nomem;
+
switch (pe->d.policy.type)
{
case POLICY_IGNORED:
rule))
goto nomem;
break;
-
-
case POLICY_CONSOLE:
if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
rule))
{
if (!append_rule_from_element (parser, element_name,
attribute_names, attribute_values,
- TRUE, error))
+ BUS_POLICY_RULE_ACCESS_ALLOW, error))
return FALSE;
if (push_element (parser, ELEMENT_ALLOW) == NULL)
{
if (!append_rule_from_element (parser, element_name,
attribute_names, attribute_values,
- FALSE, error))
+ BUS_POLICY_RULE_ACCESS_DENY, error))
return FALSE;
if (push_element (parser, ELEMENT_DENY) == NULL)
return TRUE;
}
+ else if (strcmp (element_name, "check") == 0)
+ {
+ if (!append_rule_from_element (parser, element_name,
+ attribute_names, attribute_values,
+ BUS_POLICY_RULE_ACCESS_CHECK, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_CHECK) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,
case ELEMENT_POLICY:
case ELEMENT_ALLOW:
case ELEMENT_DENY:
+ case ELEMENT_CHECK:
case ELEMENT_FORK:
case ELEMENT_SYSLOG:
case ELEMENT_KEEP_UMASK:
case ELEMENT_POLICY:
case ELEMENT_ALLOW:
case ELEMENT_DENY:
+ case ELEMENT_CHECK:
case ELEMENT_FORK:
case ELEMENT_SYSLOG:
case ELEMENT_KEEP_UMASK:
dbus_error_init (&error);
parser = bus_config_load (full_path, TRUE, NULL, &error);
+ if (dbus_error_is_set (&error))
+ _dbus_verbose ("Failed to load file: %s\n", error.message);
if (parser == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (&error);