2003-09-06 Havoc Pennington <hp@pobox.com>

* doc/dbus-specification.sgml: partial updates

	* bus/dbus-daemon-1.1.in: fix the config file docs for the
	zillionth time; hopefully I edited the right file this time.

	* bus/config-parser.c (append_rule_from_element): support
	send_type, send_path, receive_type, receive_path

	* bus/policy.c: add message type and path to the list of things
	that can be "firewalled"
This commit is contained in:
Havoc Pennington 2003-09-06 21:12:11 +00:00
parent 666fe95480
commit 83e41dff82
7 changed files with 309 additions and 50 deletions

View file

@ -1,3 +1,16 @@
2003-09-06 Havoc Pennington <hp@pobox.com>
* doc/dbus-specification.sgml: partial updates
* bus/dbus-daemon-1.1.in: fix the config file docs for the
zillionth time; hopefully I edited the right file this time.
* bus/config-parser.c (append_rule_from_element): support
send_type, send_path, receive_type, receive_path
* bus/policy.c: add message type and path to the list of things
that can be "firewalled"
2003-09-06 Havoc Pennington <hp@pobox.com>
* dbus/dbus-connection.c (dbus_connection_register_fallback): add this

View file

@ -808,6 +808,21 @@ start_busconfig_child (BusConfigParser *parser,
}
}
static int
message_type_from_string (const char *type_str)
{
if (strcmp (type_str, "method_call") == 0)
return DBUS_MESSAGE_TYPE_METHOD_CALL;
if (strcmp (type_str, "method_return") == 0)
return DBUS_MESSAGE_TYPE_METHOD_RETURN;
else if (strcmp (type_str, "signal") == 0)
return DBUS_MESSAGE_TYPE_SIGNAL;
else if (strcmp (type_str, "error") == 0)
return DBUS_MESSAGE_TYPE_ERROR;
else
return DBUS_MESSAGE_TYPE_INVALID;
}
static dbus_bool_t
append_rule_from_element (BusConfigParser *parser,
const char *element_name,
@ -820,10 +835,14 @@ append_rule_from_element (BusConfigParser *parser,
const char *send_member;
const char *send_error;
const char *send_service;
const char *send_path;
const char *send_type;
const char *receive_interface;
const char *receive_member;
const char *receive_error;
const char *receive_service;
const char *receive_path;
const char *receive_type;
const char *own;
const char *user;
const char *group;
@ -837,10 +856,14 @@ append_rule_from_element (BusConfigParser *parser,
"send_member", &send_member,
"send_error", &send_error,
"send_service", &send_service,
"send_path", &send_path,
"send_type", &send_type,
"receive_interface", &receive_interface,
"receive_member", &receive_member,
"receive_error", &receive_error,
"receive_service", &receive_service,
"receive_path", &receive_path,
"receive_type", &receive_type,
"own", &own,
"user", &user,
"group", &group,
@ -848,7 +871,9 @@ append_rule_from_element (BusConfigParser *parser,
return FALSE;
if (!(send_interface || send_member || send_error || send_service ||
send_type || send_path ||
receive_interface || receive_member || receive_error || receive_service ||
receive_type || receive_path ||
own || user || group))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
@ -857,11 +882,11 @@ append_rule_from_element (BusConfigParser *parser,
return FALSE;
}
if ((send_member && send_interface == NULL) ||
(receive_member && receive_interface == NULL))
if ((send_member && (send_interface == NULL && send_path == NULL)) ||
(receive_member && (receive_interface == NULL && receive_path == NULL)))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"On element <%s>, if you specify a member you must specify an interface",
"On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.",
element_name);
return FALSE;
}
@ -869,12 +894,13 @@ append_rule_from_element (BusConfigParser *parser,
/* Allowed combinations of elements are:
*
* base, must be all send or all receive:
* nothing
* interface
* interface + member
* error
*
* base send_ can combine with send_service,
* base receive_ with receive_service
* base send_ can combine with send_service, send_path, send_type
* base receive_ with receive_service, receive_path, receive_type
*
* user, group, own must occur alone
*/
@ -913,6 +939,22 @@ append_rule_from_element (BusConfigParser *parser,
(send_service && user) ||
(send_service && group)) ||
((send_type && receive_interface) ||
(send_type && receive_member) ||
(send_type && receive_error) ||
(send_type && receive_service) ||
(send_type && own) ||
(send_type && user) ||
(send_type && group)) ||
((send_path && receive_interface) ||
(send_path && receive_member) ||
(send_path && receive_error) ||
(send_path && receive_service) ||
(send_path && own) ||
(send_path && user) ||
(send_path && group)) ||
((receive_interface && receive_error) ||
(receive_interface && own) ||
(receive_interface && user) ||
@ -938,7 +980,7 @@ append_rule_from_element (BusConfigParser *parser,
element_name);
return FALSE;
}
rule = NULL;
/* In BusPolicyRule, NULL represents wildcard.
@ -946,11 +988,10 @@ append_rule_from_element (BusConfigParser *parser,
*/
#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
if (send_interface || send_member || send_error || send_service)
if (send_interface || send_member || send_error || send_service ||
send_path || send_type)
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
if (rule == NULL)
goto nomem;
int message_type;
if (IS_WILDCARD (send_interface))
send_interface = NULL;
@ -960,11 +1001,36 @@ append_rule_from_element (BusConfigParser *parser,
send_error = NULL;
if (IS_WILDCARD (send_service))
send_service = NULL;
if (IS_WILDCARD (send_path))
send_path = NULL;
if (IS_WILDCARD (send_type))
send_type = NULL;
message_type = DBUS_MESSAGE_TYPE_INVALID;
if (send_type != NULL)
{
message_type = message_type_from_string (send_type);
if (message_type == DBUS_MESSAGE_TYPE_INVALID)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Bad message type \"%s\"",
send_type);
return FALSE;
}
}
rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
if (rule == NULL)
goto nomem;
rule->d.send.message_type = message_type;
rule->d.send.path = _dbus_strdup (send_path);
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_service);
if (send_path && rule->d.send.path == NULL)
goto nomem;
if (send_interface && rule->d.send.interface == NULL)
goto nomem;
if (send_member && rule->d.send.member == NULL)
@ -974,11 +1040,10 @@ append_rule_from_element (BusConfigParser *parser,
if (send_service && rule->d.send.destination == NULL)
goto nomem;
}
else if (receive_interface || receive_member || receive_error || receive_service)
else if (receive_interface || receive_member || receive_error || receive_service ||
receive_path || receive_type)
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
if (rule == NULL)
goto nomem;
int message_type;
if (IS_WILDCARD (receive_interface))
receive_interface = NULL;
@ -988,11 +1053,37 @@ append_rule_from_element (BusConfigParser *parser,
receive_error = NULL;
if (IS_WILDCARD (receive_service))
receive_service = NULL;
if (IS_WILDCARD (receive_path))
receive_path = NULL;
if (IS_WILDCARD (receive_type))
receive_type = NULL;
message_type = DBUS_MESSAGE_TYPE_INVALID;
if (receive_type != NULL)
{
message_type = message_type_from_string (receive_type);
if (message_type == DBUS_MESSAGE_TYPE_INVALID)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Bad message type \"%s\"",
receive_type);
return FALSE;
}
}
rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
if (rule == NULL)
goto nomem;
rule->d.receive.message_type = message_type;
rule->d.receive.path = _dbus_strdup (receive_path);
rule->d.receive.interface = _dbus_strdup (receive_interface);
rule->d.receive.member = _dbus_strdup (receive_member);
rule->d.receive.error = _dbus_strdup (receive_error);
rule->d.receive.origin = _dbus_strdup (receive_service);
if (receive_path && rule->d.receive.path == NULL)
goto nomem;
if (receive_interface && rule->d.receive.interface == NULL)
goto nomem;
if (receive_member && rule->d.receive.member == NULL)

View file

@ -333,11 +333,22 @@ in the config file.
A <deny> element appears below a <policy> element and prohibits
some action. The possible attributes of a <deny> element are:
.nf
send="messagename"
send_interface="interface_name"
send_member="method_or_signal_name"
send_error="error_name"
send_service="service_name"
send_type="method_call|method_return|signal|error"
send_path="/path/name"
receive_interface="interface_name"
receive_member="method_or_signal_name"
receive_error="error_name"
receive_service="service_name"
receive_type="method_call|method_return|signal|error"
receive_path="/path/name"
receive="messagename"
own="servicename"
send_to="servicename"
receive_from="servicename"
user="username"
group="groupname"
.fi
@ -345,11 +356,11 @@ some action. The possible attributes of a <deny> element are:
.PP
Examples:
.nf
<deny send="org.freedesktop.System.Reboot"/>
<deny receive="org.freedesktop.System.Reboot"/>
<deny send_interface="org.freedesktop.System" send_member="Reboot"/>
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
<deny own="org.freedesktop.System"/>
<deny send_to="org.freedesktop.System"/>
<deny receive_from="org.freedesktop.System"/>
<deny send_service="org.freedesktop.System"/>
<deny receive_service="org.freedesktop.System"/>
<deny user="john"/>
<deny group="enemies"/>
.fi
@ -360,18 +371,22 @@ particular action. If it matches, the action is denied (unless later
rules in the config file allow it).
.PP
send_to and receive_from mean that messages may not be sent to or
received from the *owner* of the given service, not that they may not
be sent *to that service name*. That is, if a connection owns services
A, B, C, and sending to A is denied, sending to B or C will not work
either.
send_service and receive_service rules mean that messages may not be
sent to or received from the *owner* of the given service, not that
they may not be sent *to that service name*. That is, if a connection
owns services A, B, C, and sending to A is denied, sending to B or C
will not work either.
.PP
The other send_* and receive_* attributes are purely textual/by-value
matches against the given field in the message header.
.PP
user and group denials mean that the given user or group may
not connect to the message bus.
.PP
For "servicename" or "messagename" or "username" or "groupname"
For "service_name", "username", "groupname", etc.
the character "*" can be substituted, meaning "any." Complex globs
like "foo.bar.*" aren't allowed for now because they'd be work to
implement and maybe encourage sloppy security anyway.
@ -382,11 +397,21 @@ for a user or group; user/group denials can only be inside
context="default" or context="mandatory" policies.
.PP
A single <deny> rule may specify both send and send_to, OR both
receive and receive_from. In this case, the denial applies only if
both attributes match the message being denied.
e.g. <deny send="foo.bar" send_to="foo.blah"/> would deny
messages of the given name AND to the given service.
A single <deny> rule may specify combinations of attributes such as
send_service and send_interface and send_type. In this case, the
denial applies only if both attributes match the message being denied.
e.g. <deny send_interface="foo.bar" send_service="foo.blah"/> would
deny messages of the given interface AND to the given service.
To get an OR effect you specify multiple <deny> rules.
.PP
You can't include both send_ and receive_ attributes on the same
rule, since "whether the message can be sent" and "whether it can be
received" are evaluated separately.
.PP
Be careful with send_interface/receive_interface, because the
interface field in messages is optional.
.TP
.I "<allow>"

View file

@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type,
rule->d.group.gid = DBUS_GID_UNSET;
break;
case BUS_POLICY_RULE_SEND:
rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
break;
case BUS_POLICY_RULE_RECEIVE:
rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
break;
case BUS_POLICY_RULE_OWN:
break;
}
@ -80,12 +84,14 @@ bus_policy_rule_unref (BusPolicyRule *rule)
switch (rule->type)
{
case BUS_POLICY_RULE_SEND:
dbus_free (rule->d.send.path);
dbus_free (rule->d.send.interface);
dbus_free (rule->d.send.member);
dbus_free (rule->d.send.error);
dbus_free (rule->d.send.destination);
break;
case BUS_POLICY_RULE_RECEIVE:
dbus_free (rule->d.receive.path);
dbus_free (rule->d.receive.interface);
dbus_free (rule->d.receive.member);
dbus_free (rule->d.receive.error);
@ -717,6 +723,8 @@ bus_client_policy_optimize (BusClientPolicy *policy)
{
case BUS_POLICY_RULE_SEND:
remove_preceding =
rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
rule->d.send.path == NULL &&
rule->d.send.interface == NULL &&
rule->d.send.member == NULL &&
rule->d.send.error == NULL &&
@ -724,6 +732,8 @@ bus_client_policy_optimize (BusClientPolicy *policy)
break;
case BUS_POLICY_RULE_RECEIVE:
remove_preceding =
rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
rule->d.receive.path == NULL &&
rule->d.receive.interface == NULL &&
rule->d.receive.member == NULL &&
rule->d.receive.error == NULL &&
@ -799,6 +809,26 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
continue;
}
if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
if (dbus_message_get_type (message) != rule->d.send.message_type)
{
_dbus_verbose (" (policy) skipping rule for different message type\n");
continue;
}
}
if (rule->d.send.path != NULL)
{
if (dbus_message_get_path (message) != NULL &&
strcmp (dbus_message_get_path (message),
rule->d.send.path) != 0)
{
_dbus_verbose (" (policy) skipping rule for different path\n");
continue;
}
}
if (rule->d.send.interface != NULL)
{
if (dbus_message_get_interface (message) != NULL &&
@ -911,6 +941,26 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
_dbus_verbose (" (policy) skipping non-receive rule\n");
continue;
}
if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
if (dbus_message_get_type (message) != rule->d.receive.message_type)
{
_dbus_verbose (" (policy) skipping rule for different message type\n");
continue;
}
}
if (rule->d.receive.path != NULL)
{
if (dbus_message_get_path (message) != NULL &&
strcmp (dbus_message_get_path (message),
rule->d.receive.path) != 0)
{
_dbus_verbose (" (policy) skipping rule for different path\n");
continue;
}
}
if (rule->d.receive.interface != NULL)
{

View file

@ -54,7 +54,10 @@ struct BusPolicyRule
{
struct
{
/* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
int message_type;
/* any of these can be NULL meaning "any" */
char *path;
char *interface;
char *member;
char *error;
@ -63,7 +66,10 @@ struct BusPolicyRule
struct
{
/* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
int message_type;
/* any of these can be NULL meaning "any" */
char *path;
char *interface;
char *member;
char *error;

View file

@ -3,8 +3,8 @@
<article id="index">
<artheader>
<title>D-BUS Specification</title>
<releaseinfo>Version 0.7</releaseinfo>
<date>26 March 2003</date>
<releaseinfo>Version 0.8</releaseinfo>
<date>06 September 2003</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@ -65,10 +65,10 @@
<para>
D-BUS is <emphasis>easy to use</emphasis> because it works in terms
of <firstterm>messages</firstterm> rather than byte streams, and
does not require users to understand any complex concepts such as a
new type system or elaborate APIs. Libraries implementing D-BUS
may choose to abstract messages as "method calls" (see
<xref linkend="message-conventions-method">).
automatically handles a lot of the hard IPC issues. Also, the D-BUS
library is designed to be wrapped in a way that lets users use their
framework's existing object/type system, rather than learning a new
one specifically for IPC.
</para>
</listitem>
</itemizedlist>
@ -83,11 +83,10 @@
forwards messages among them.
</para>
<para>
Things that D-BUS can be used for is for example notification of
system changes (notification of when a camera is plugged in to a
computer, or a new version of some software has been installed),
or desktop interoperablity, for example a file monitoring
service or a configuration service.
Uses of D-BUS include notification of system changes (notification of when
a camera is plugged in to a computer, or a new version of some software
has been installed), or desktop interoperablity, for example a file
monitoring service or a configuration service.
</para>
</sect1>
@ -279,9 +278,27 @@
</thead>
<tbody>
<row>
<entry>name</entry>
<entry>path</entry>
<entry>STRING</entry>
<entry>The name of the message, such as org.freedesktop.Peer.Ping</entry>
<entry>The object to send the message to; objects are identified by
a path, "/foo/bar"</entry>
</row>
<row>
<entry>ifce</entry>
<entry>STRING</entry>
<entry>The interface to invoke a method call on, or
that a signal is emitted from. e.g. "org.freedesktop.Introspectable"</entry>
</row>
<row>
<entry>mebr</entry>
<entry>STRING</entry>
<entry>The member, either the method name or signal name.
e.g. "Frobate"</entry>
</row>
<row>
<entry>ernm</entry>
<entry>STRING</entry>
<entry>The name of the error that occurred, for errors</entry>
</row>
<row>
<entry>rply</entry>
@ -298,10 +315,10 @@
<xref linkend="message-bus">.</entry>
</row>
<row>
<entry>sndr</entry>
<entry>sdrs</entry>
<entry>STRING</entry>
<entry>The name of the base service that sent this message.
The message bus fills in this field; the field is
<entry>Sender service. The name of the base service that sent
this message. The message bus fills in this field; the field is
only meaningful in combination with the message bus.</entry>
</row>
</tbody>
@ -480,9 +497,9 @@
<sect2 id="message-protocol-names">
<title>Valid names</title>
<para>
Messages and services have names with type STRING, meaning that
Services have names with type STRING, meaning that
they must be valid UTF-8. However, there are also some
additional restrictions that apply to message and service names
additional restrictions that apply to service names
specifically:
<itemizedlist>
<listitem><para>They must contain at least one '.' (period) character</para></listitem>

View file

@ -0,0 +1,57 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<user>mybususer</user>
<listen>unix:path=/foo/bar</listen>
<listen>tcp:port=1234</listen>
<includedir>basic.d</includedir>
<servicedir>/usr/share/foo</servicedir>
<include ignore_missing="yes">nonexistent.conf</include>
<policy context="default">
<allow user="*"/>
<deny send_interface="org.freedesktop.System" send_member="Reboot"/>
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
<deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
<deny own="org.freedesktop.System"/>
<deny send_service="org.freedesktop.System"/>
<deny receive_service="org.freedesktop.System"/>
<deny user="root"/>
<deny group="root"/>
<allow send_type="error"/>
<allow send_type="method_call"/>
<allow send_type="method_return"/>
<allow send_type="signal"/>
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
</policy>
<policy context="mandatory">
<allow user="*"/>
<deny send_interface="org.freedesktop.System" send_member="Reboot"/>
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
<deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
<deny own="org.freedesktop.System"/>
<deny send_service="org.freedesktop.System"/>
<deny receive_service="org.freedesktop.System"/>
<deny user="root"/>
<deny group="root"/>
<allow send_type="error"/>
<allow send_type="method_call"/>
<allow send_type="method_return"/>
<allow send_type="signal"/>
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
<deny send_service="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
</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>
<limit name="max_pending_activations">64</limit>
<limit name="max_services_per_connection">256</limit>
</busconfig>