Add send_broadcast as an attribute of <allow> and <deny> elements
authorSimon McVittie <smcv@collabora.com>
Wed, 19 Jul 2017 14:53:17 +0000 (15:53 +0100)
committerSimon McVittie <smcv@debian.org>
Fri, 28 Jul 2017 10:24:20 +0000 (11:24 +0100)
<allow send_broadcast="true" ...> only matches broadcasts,
which are signals with a NULL destination. There was previously
no way for the policy language to express "NULL destination",
only "any destination".

<allow send_broadcast="false" ...> only matches non-broadcasts,
which are non-signals or signals with a non-NULL destination.
There was previously no way for the policy language to express
"any non-NULL destination", only "any destination".

Reviewed-by: Philip Withnall <withnall@endlessm.com>
[smcv: improved documentation as per Philip's review]
Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Thiago Macieira <thiago@kde.org>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92853

bus/config-parser.c
bus/policy.c
bus/policy.h
doc/dbus-daemon.1.xml.in

index 4dc7d92..52576e9 100644 (file)
@@ -1294,6 +1294,7 @@ append_rule_from_element (BusConfigParser   *parser,
   const char *send_path;
   const char *send_type;
   const char *send_requested_reply;
+  const char *send_broadcast;
   /* TRUE if any send_ attribute is present */
   dbus_bool_t any_send_attribute;
 
@@ -1331,6 +1332,7 @@ append_rule_from_element (BusConfigParser   *parser,
                           "send_destination", &send_destination,
                           "send_path", &send_path,
                           "send_type", &send_type,
+                          "send_broadcast", &send_broadcast,
                           "receive_interface", &receive_interface,
                           "receive_member", &receive_member,
                           "receive_error", &receive_error,
@@ -1349,6 +1351,7 @@ append_rule_from_element (BusConfigParser   *parser,
     return FALSE;
 
   any_send_attribute = (send_destination != NULL ||
+                        send_broadcast != NULL ||
                         send_path != NULL ||
                         send_type != NULL ||
                         send_interface != NULL ||
@@ -1399,7 +1402,7 @@ append_rule_from_element (BusConfigParser   *parser,
    *     interface + member
    *     error
    * 
-   *   base send_ can combine with send_destination, send_path, send_type, send_requested_reply, eavesdrop
+   *   base send_ can combine with send_destination, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
    *   base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
    *
    *   user, group, own, own_prefix must occur alone
@@ -1496,6 +1499,16 @@ append_rule_from_element (BusConfigParser   *parser,
           return FALSE;
         }
 
+      if (send_broadcast &&
+          !(strcmp (send_broadcast, "true") == 0 ||
+            strcmp (send_broadcast, "false") == 0))
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "Bad value \"%s\" for %s attribute, must be true or false",
+                          send_broadcast, "send_broadcast");
+          return FALSE;
+        }
+
       if (send_requested_reply &&
           !(strcmp (send_requested_reply, "true") == 0 ||
             strcmp (send_requested_reply, "false") == 0))
@@ -1519,6 +1532,18 @@ append_rule_from_element (BusConfigParser   *parser,
       if (send_requested_reply)
         rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0);
 
+      if (send_broadcast)
+        {
+          if (strcmp (send_broadcast, "true") == 0)
+            rule->d.send.broadcast = BUS_POLICY_TRISTATE_TRUE;
+          else
+            rule->d.send.broadcast = BUS_POLICY_TRISTATE_FALSE;
+        }
+      else
+        {
+          rule->d.send.broadcast = BUS_POLICY_TRISTATE_ANY;
+        }
+
       rule->d.send.message_type = message_type;
       rule->d.send.path = _dbus_strdup (send_path);
       rule->d.send.interface = _dbus_strdup (send_interface);
index b5cca35..d8d82f4 100644 (file)
@@ -996,7 +996,27 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
               continue;
             }
         }
-      
+
+      if (rule->d.send.broadcast != BUS_POLICY_TRISTATE_ANY)
+        {
+          if (dbus_message_get_destination (message) == NULL &&
+              dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
+            {
+              /* it's a broadcast */
+              if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE)
+                {
+                  _dbus_verbose ("  (policy) skipping rule because message is a broadcast\n");
+                  continue;
+                }
+            }
+          /* else it isn't a broadcast: there is some destination */
+          else if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_TRUE)
+            {
+              _dbus_verbose ("  (policy) skipping rule because message is not a broadcast\n");
+              continue;
+            }
+        }
+
       if (rule->d.send.destination != NULL)
         {
           /* receiver can be NULL for messages that are sent to the
index d1d3e72..c5275a7 100644 (file)
@@ -39,6 +39,13 @@ typedef enum
   BUS_POLICY_RULE_GROUP
 } BusPolicyRuleType;
 
+typedef enum
+{
+  BUS_POLICY_TRISTATE_ANY = 0,
+  BUS_POLICY_TRISTATE_FALSE,
+  BUS_POLICY_TRISTATE_TRUE
+} BusPolicyTristate;
+
 /** determines whether the rule affects a connection, or some global item */
 #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
                                                (rule)->type == BUS_POLICY_RULE_GROUP))
@@ -66,6 +73,7 @@ struct BusPolicyRule
       unsigned int eavesdrop : 1;
       unsigned int requested_reply : 1;
       unsigned int log : 1;
+      unsigned int broadcast : 2; /**< really a BusPolicyTristate */
     } send;
 
     struct
index cd967c8..067fdcd 100644 (file)
@@ -842,6 +842,7 @@ statements, and works just like &lt;deny&gt; but with the inverse meaning.</para
    send_interface="interface_name" | "*"
    send_member="method_or_signal_name" | "*"
    send_error="error_name" | "*"
+   send_broadcast="true" | "false"
    send_destination="name" | "*"
    send_type="method_call" | "method_return" | "signal" | "error" | "*"
    send_path="/path/name" | "*"
@@ -915,6 +916,16 @@ will not work either. As a special case,
 <literal>receive_sender="*"</literal> similarly matches any message.</para>
 
 <para>
+  Rules with <literal>send_broadcast="true"</literal> match signal messages
+  with no destination (broadcasts). Rules with
+  <literal>send_broadcast="false"</literal> are the inverse: they match any
+  unicast destination (unicast signals, together with all method calls, replies
+  and errors) but do not match messages with no destination (broadcasts). This
+  is not the same as <literal>send_destination="*"</literal>, which matches any
+  sent message, regardless of whether it has a destination or not.
+</para>
+
+<para>
   The other <literal>send_</literal>* and <literal>receive_</literal>*
   attributes are purely textual/by-value matches against the given field in
   the message header, except that for the attributes where it is allowed,