1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* policy.c Policies for what a connection can do
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <dbus/dbus-list.h>
28 #include <dbus/dbus-internals.h>
31 bus_policy_rule_new (BusPolicyRuleType type,
36 rule = dbus_new0 (BusPolicyRule, 1);
48 bus_policy_rule_ref (BusPolicyRule *rule)
50 _dbus_assert (rule->refcount > 0);
56 bus_policy_rule_unref (BusPolicyRule *rule)
58 _dbus_assert (rule->refcount > 0);
62 if (rule->refcount == 0)
66 case BUS_POLICY_RULE_SEND:
67 dbus_free (rule->d.send.message_name);
68 dbus_free (rule->d.send.destination);
70 case BUS_POLICY_RULE_RECEIVE:
71 dbus_free (rule->d.receive.message_name);
72 dbus_free (rule->d.receive.origin);
74 case BUS_POLICY_RULE_OWN:
75 dbus_free (rule->d.own.service_name);
77 case BUS_POLICY_RULE_USER:
78 case BUS_POLICY_RULE_GROUP:
79 _dbus_assert_not_reached ("invalid rule");
99 policy = dbus_new0 (BusPolicy, 1);
103 policy->refcount = 1;
109 bus_policy_ref (BusPolicy *policy)
111 _dbus_assert (policy->refcount > 0);
113 policy->refcount += 1;
117 rule_unref_foreach (void *data,
120 BusPolicyRule *rule = data;
122 bus_policy_rule_unref (rule);
126 bus_policy_unref (BusPolicy *policy)
128 _dbus_assert (policy->refcount > 0);
130 policy->refcount -= 1;
132 if (policy->refcount == 0)
134 _dbus_list_foreach (&policy->rules,
138 _dbus_list_clear (&policy->rules);
145 remove_rules_by_type_up_to (BusPolicy *policy,
146 BusPolicyRuleType type,
151 link = _dbus_list_get_first (&policy->rules);
152 while (link != up_to)
154 BusPolicyRule *rule = link->data;
155 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
157 bus_policy_rule_unref (rule);
158 _dbus_list_remove_link (&policy->rules, link);
165 bus_policy_optimize (BusPolicy *policy)
169 /* The idea here is that if we have:
171 * <allow send="foo"/>
174 * (for example) the deny will always override the allow. So we
175 * delete the allow. Ditto for deny followed by allow, etc. This is
176 * a dumb thing to put in a config file, but the <include> feature
177 * of files allows for an "inheritance and override" pattern where
178 * it could make sense. If an included file wants to "start over"
179 * with a blanket deny, no point keeping the rules from the parent
183 _dbus_verbose ("Optimizing policy with %d rules\n",
184 _dbus_list_get_length (&policy->rules));
186 link = _dbus_list_get_first (&policy->rules);
189 BusPolicyRule *rule = link->data;
190 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
191 dbus_bool_t remove_preceding;
193 remove_preceding = FALSE;
197 case BUS_POLICY_RULE_SEND:
199 rule->d.send.message_name == NULL &&
200 rule->d.send.destination == NULL;
202 case BUS_POLICY_RULE_RECEIVE:
204 rule->d.receive.message_name == NULL &&
205 rule->d.receive.origin == NULL;
207 case BUS_POLICY_RULE_OWN:
209 rule->d.own.service_name == NULL;
211 case BUS_POLICY_RULE_USER:
212 case BUS_POLICY_RULE_GROUP:
213 _dbus_assert_not_reached ("invalid rule");
217 if (remove_preceding)
218 remove_rules_by_type_up_to (policy, rule->type,
224 _dbus_verbose ("After optimization, policy has %d rules\n",
225 _dbus_list_get_length (&policy->rules));
229 bus_policy_append_rule (BusPolicy *policy,
232 if (!_dbus_list_append (&policy->rules, rule))
235 bus_policy_rule_ref (rule);
241 bus_policy_check_can_send (BusPolicy *policy,
242 BusRegistry *registry,
243 DBusConnection *receiver,
244 DBusMessage *message)
249 /* policy->rules is in the order the rules appeared
250 * in the config file, i.e. last rule that applies wins
254 link = _dbus_list_get_first (&policy->rules);
257 BusPolicyRule *rule = link->data;
259 link = _dbus_list_get_next_link (&policy->rules, link);
261 /* Rule is skipped if it specifies a different
262 * message name from the message, or a different
263 * destination from the message
266 if (rule->type != BUS_POLICY_RULE_SEND)
269 if (rule->d.send.message_name != NULL)
271 if (!dbus_message_name_is (message,
272 rule->d.send.message_name))
276 if (rule->d.send.destination != NULL)
278 /* receiver can be NULL for messages that are sent to the
279 * message bus itself, we check the strings in that case as
280 * built-in services don't have a DBusConnection but messages
281 * to them have a destination service name.
283 if (receiver == NULL)
285 if (!dbus_message_sender_is (message,
286 rule->d.send.destination))
294 _dbus_string_init_const (&str, rule->d.send.destination);
296 service = bus_registry_lookup (registry, &str);
300 if (!bus_service_has_owner (service, receiver))
306 allowed = rule->allow;
313 bus_policy_check_can_receive (BusPolicy *policy,
314 BusRegistry *registry,
315 DBusConnection *sender,
316 DBusMessage *message)
321 /* policy->rules is in the order the rules appeared
322 * in the config file, i.e. last rule that applies wins
326 link = _dbus_list_get_first (&policy->rules);
329 BusPolicyRule *rule = link->data;
331 link = _dbus_list_get_next_link (&policy->rules, link);
333 /* Rule is skipped if it specifies a different
334 * message name from the message, or a different
335 * origin from the message
338 if (rule->type != BUS_POLICY_RULE_RECEIVE)
341 if (rule->d.receive.message_name != NULL)
343 if (!dbus_message_name_is (message,
344 rule->d.receive.message_name))
348 if (rule->d.receive.origin != NULL)
350 /* sender can be NULL for messages that originate from the
351 * message bus itself, we check the strings in that case as
352 * built-in services don't have a DBusConnection but will
353 * still set the sender on their messages.
357 if (!dbus_message_sender_is (message,
358 rule->d.receive.origin))
366 _dbus_string_init_const (&str, rule->d.receive.origin);
368 service = bus_registry_lookup (registry, &str);
373 if (!bus_service_has_owner (service, sender))
379 allowed = rule->allow;
386 bus_policy_check_can_own (BusPolicy *policy,
387 DBusConnection *connection,
388 const DBusString *service_name)
393 /* policy->rules is in the order the rules appeared
394 * in the config file, i.e. last rule that applies wins
398 link = _dbus_list_get_first (&policy->rules);
401 BusPolicyRule *rule = link->data;
403 link = _dbus_list_get_next_link (&policy->rules, link);
405 /* Rule is skipped if it specifies a different service name from
409 if (rule->type != BUS_POLICY_RULE_OWN)
412 if (rule->d.own.service_name != NULL)
414 if (!_dbus_string_equal_c_str (service_name,
415 rule->d.own.service_name))
420 allowed = rule->allow;
426 #ifdef DBUS_BUILD_TESTS
429 bus_policy_test (const DBusString *test_data_dir)
431 /* This doesn't do anything for now because I decided to do it in
432 * dispatch.c instead by having some of the clients in dispatch.c
433 * have particular policies applied to them.
439 #endif /* DBUS_BUILD_TESTS */