1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* policy.c Bus security policy
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-hash.h>
29 #include <dbus/dbus-internals.h>
32 bus_policy_rule_new (BusPolicyRuleType type,
37 rule = dbus_new0 (BusPolicyRule, 1);
47 case BUS_POLICY_RULE_USER:
48 rule->d.user.uid = DBUS_UID_UNSET;
50 case BUS_POLICY_RULE_GROUP:
51 rule->d.group.gid = DBUS_GID_UNSET;
53 case BUS_POLICY_RULE_SEND:
54 case BUS_POLICY_RULE_RECEIVE:
55 case BUS_POLICY_RULE_OWN:
63 bus_policy_rule_ref (BusPolicyRule *rule)
65 _dbus_assert (rule->refcount > 0);
71 bus_policy_rule_unref (BusPolicyRule *rule)
73 _dbus_assert (rule->refcount > 0);
77 if (rule->refcount == 0)
81 case BUS_POLICY_RULE_SEND:
82 dbus_free (rule->d.send.message_name);
83 dbus_free (rule->d.send.destination);
85 case BUS_POLICY_RULE_RECEIVE:
86 dbus_free (rule->d.receive.message_name);
87 dbus_free (rule->d.receive.origin);
89 case BUS_POLICY_RULE_OWN:
90 dbus_free (rule->d.own.service_name);
92 case BUS_POLICY_RULE_USER:
94 case BUS_POLICY_RULE_GROUP:
106 DBusList *default_rules; /**< Default policy rules */
107 DBusList *mandatory_rules; /**< Mandatory policy rules */
108 DBusHashTable *rules_by_uid; /**< per-UID policy rules */
109 DBusHashTable *rules_by_gid; /**< per-GID policy rules */
113 free_rule_func (void *data,
116 BusPolicyRule *rule = data;
118 bus_policy_rule_unref (rule);
122 free_rule_list_func (void *data)
124 DBusList **list = data;
126 _dbus_list_foreach (list, free_rule_func, NULL);
128 _dbus_list_clear (list);
134 bus_policy_new (void)
138 policy = dbus_new0 (BusPolicy, 1);
142 policy->refcount = 1;
144 policy->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
146 free_rule_list_func);
147 if (policy->rules_by_uid == NULL)
150 policy->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
152 free_rule_list_func);
153 if (policy->rules_by_gid == NULL)
159 bus_policy_unref (policy);
164 bus_policy_ref (BusPolicy *policy)
166 _dbus_assert (policy->refcount > 0);
168 policy->refcount += 1;
172 bus_policy_unref (BusPolicy *policy)
174 _dbus_assert (policy->refcount > 0);
176 policy->refcount -= 1;
178 if (policy->refcount == 0)
180 _dbus_list_foreach (&policy->default_rules, free_rule_func, NULL);
181 _dbus_list_clear (&policy->default_rules);
183 _dbus_list_foreach (&policy->mandatory_rules, free_rule_func, NULL);
184 _dbus_list_clear (&policy->mandatory_rules);
186 if (policy->rules_by_uid)
188 _dbus_hash_table_unref (policy->rules_by_uid);
189 policy->rules_by_uid = NULL;
192 if (policy->rules_by_gid)
194 _dbus_hash_table_unref (policy->rules_by_gid);
195 policy->rules_by_gid = NULL;
203 add_list_to_client (DBusList **list,
204 BusClientPolicy *client)
208 link = _dbus_list_get_first_link (list);
211 BusPolicyRule *rule = link->data;
212 link = _dbus_list_get_next_link (list, link);
216 case BUS_POLICY_RULE_USER:
217 case BUS_POLICY_RULE_GROUP:
218 /* These aren't per-connection policies */
221 case BUS_POLICY_RULE_OWN:
222 case BUS_POLICY_RULE_SEND:
223 case BUS_POLICY_RULE_RECEIVE:
224 /* These are per-connection */
225 if (!bus_client_policy_append_rule (client, rule))
235 bus_policy_create_client_policy (BusPolicy *policy,
236 DBusConnection *connection)
238 BusClientPolicy *client;
241 _dbus_assert (dbus_connection_get_is_authenticated (connection));
243 client = bus_client_policy_new ();
247 if (!add_list_to_client (&policy->default_rules,
251 /* we avoid the overhead of looking up user's groups
252 * if we don't have any group rules anyway
254 if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0)
256 unsigned long *groups;
260 if (!bus_connection_get_groups (connection, &groups, &n_groups))
268 list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
273 if (!add_list_to_client (list, client))
286 if (!dbus_connection_get_unix_user (connection, &uid))
289 if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
293 list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
298 if (!add_list_to_client (list, client))
303 if (!add_list_to_client (&policy->mandatory_rules,
307 bus_client_policy_optimize (client);
312 bus_client_policy_unref (client);
317 list_allows_user (dbus_bool_t def,
320 const unsigned long *group_ids,
328 link = _dbus_list_get_first_link (list);
331 BusPolicyRule *rule = link->data;
332 link = _dbus_list_get_next_link (list, link);
334 if (rule->type == BUS_POLICY_RULE_USER)
336 _dbus_verbose ("List %p user rule uid="DBUS_UID_FORMAT"\n",
337 list, rule->d.user.uid);
339 if (rule->d.user.uid == DBUS_UID_UNSET)
341 else if (rule->d.user.uid != uid)
344 else if (rule->type == BUS_POLICY_RULE_GROUP)
346 _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n",
347 list, rule->d.user.uid);
349 if (rule->d.group.gid == DBUS_GID_UNSET)
356 while (i < n_group_ids)
358 if (rule->d.group.gid == group_ids[i])
363 if (i == n_group_ids)
370 allowed = rule->allow;
377 bus_policy_allow_user (BusPolicy *policy,
378 DBusUserDatabase *user_database,
382 unsigned long *group_ids;
385 /* On OOM or error we always reject the user */
386 if (!_dbus_user_database_get_groups (user_database,
387 uid, &group_ids, &n_group_ids, NULL))
389 _dbus_verbose ("Did not get any groups for UID %lu\n",
396 allowed = list_allows_user (allowed,
397 &policy->default_rules,
399 group_ids, n_group_ids);
401 allowed = list_allows_user (allowed,
402 &policy->mandatory_rules,
404 group_ids, n_group_ids);
406 dbus_free (group_ids);
408 _dbus_verbose ("UID %lu allowed = %d\n", uid, allowed);
414 bus_policy_append_default_rule (BusPolicy *policy,
417 if (!_dbus_list_append (&policy->default_rules, rule))
420 bus_policy_rule_ref (rule);
426 bus_policy_append_mandatory_rule (BusPolicy *policy,
429 if (!_dbus_list_append (&policy->mandatory_rules, rule))
432 bus_policy_rule_ref (rule);
438 get_list (DBusHashTable *hash,
443 list = _dbus_hash_table_lookup_ulong (hash, key);
447 list = dbus_new0 (DBusList*, 1);
451 if (!_dbus_hash_table_insert_ulong (hash, key, list))
462 bus_policy_append_user_rule (BusPolicy *policy,
468 list = get_list (policy->rules_by_uid, uid);
473 if (!_dbus_list_append (list, rule))
476 bus_policy_rule_ref (rule);
482 bus_policy_append_group_rule (BusPolicy *policy,
488 list = get_list (policy->rules_by_gid, gid);
493 if (!_dbus_list_append (list, rule))
496 bus_policy_rule_ref (rule);
501 struct BusClientPolicy
509 bus_client_policy_new (void)
511 BusClientPolicy *policy;
513 policy = dbus_new0 (BusClientPolicy, 1);
517 policy->refcount = 1;
523 bus_client_policy_ref (BusClientPolicy *policy)
525 _dbus_assert (policy->refcount > 0);
527 policy->refcount += 1;
531 rule_unref_foreach (void *data,
534 BusPolicyRule *rule = data;
536 bus_policy_rule_unref (rule);
540 bus_client_policy_unref (BusClientPolicy *policy)
542 _dbus_assert (policy->refcount > 0);
544 policy->refcount -= 1;
546 if (policy->refcount == 0)
548 _dbus_list_foreach (&policy->rules,
552 _dbus_list_clear (&policy->rules);
559 remove_rules_by_type_up_to (BusClientPolicy *policy,
560 BusPolicyRuleType type,
565 link = _dbus_list_get_first_link (&policy->rules);
566 while (link != up_to)
568 BusPolicyRule *rule = link->data;
569 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
571 if (rule->type == type)
573 _dbus_list_remove_link (&policy->rules, link);
574 bus_policy_rule_unref (rule);
582 bus_client_policy_optimize (BusClientPolicy *policy)
586 /* The idea here is that if we have:
588 * <allow send="foo"/>
591 * (for example) the deny will always override the allow. So we
592 * delete the allow. Ditto for deny followed by allow, etc. This is
593 * a dumb thing to put in a config file, but the <include> feature
594 * of files allows for an "inheritance and override" pattern where
595 * it could make sense. If an included file wants to "start over"
596 * with a blanket deny, no point keeping the rules from the parent
600 _dbus_verbose ("Optimizing policy with %d rules\n",
601 _dbus_list_get_length (&policy->rules));
603 link = _dbus_list_get_first_link (&policy->rules);
608 dbus_bool_t remove_preceding;
610 next = _dbus_list_get_next_link (&policy->rules, link);
613 remove_preceding = FALSE;
615 _dbus_assert (rule != NULL);
619 case BUS_POLICY_RULE_SEND:
621 rule->d.send.message_name == NULL &&
622 rule->d.send.destination == NULL;
624 case BUS_POLICY_RULE_RECEIVE:
626 rule->d.receive.message_name == NULL &&
627 rule->d.receive.origin == NULL;
629 case BUS_POLICY_RULE_OWN:
631 rule->d.own.service_name == NULL;
633 case BUS_POLICY_RULE_USER:
634 case BUS_POLICY_RULE_GROUP:
635 _dbus_assert_not_reached ("invalid rule");
639 if (remove_preceding)
640 remove_rules_by_type_up_to (policy, rule->type,
646 _dbus_verbose ("After optimization, policy has %d rules\n",
647 _dbus_list_get_length (&policy->rules));
651 bus_client_policy_append_rule (BusClientPolicy *policy,
654 _dbus_verbose ("Appending rule %p with type %d to policy %p\n",
655 rule, rule->type, policy);
657 if (!_dbus_list_append (&policy->rules, rule))
660 bus_policy_rule_ref (rule);
666 bus_client_policy_check_can_send (BusClientPolicy *policy,
667 BusRegistry *registry,
668 DBusConnection *receiver,
669 DBusMessage *message)
674 /* policy->rules is in the order the rules appeared
675 * in the config file, i.e. last rule that applies wins
679 link = _dbus_list_get_first_link (&policy->rules);
682 BusPolicyRule *rule = link->data;
684 link = _dbus_list_get_next_link (&policy->rules, link);
686 /* Rule is skipped if it specifies a different
687 * message name from the message, or a different
688 * destination from the message
691 if (rule->type != BUS_POLICY_RULE_SEND)
694 if (rule->d.send.message_name != NULL)
696 if (!dbus_message_has_name (message,
697 rule->d.send.message_name))
701 if (rule->d.send.destination != NULL)
703 /* receiver can be NULL for messages that are sent to the
704 * message bus itself, we check the strings in that case as
705 * built-in services don't have a DBusConnection but messages
706 * to them have a destination service name.
708 if (receiver == NULL)
710 if (!dbus_message_has_sender (message,
711 rule->d.send.destination))
719 _dbus_string_init_const (&str, rule->d.send.destination);
721 service = bus_registry_lookup (registry, &str);
725 if (!bus_service_has_owner (service, receiver))
731 allowed = rule->allow;
738 bus_client_policy_check_can_receive (BusClientPolicy *policy,
739 BusRegistry *registry,
740 DBusConnection *sender,
741 DBusMessage *message)
746 /* policy->rules is in the order the rules appeared
747 * in the config file, i.e. last rule that applies wins
751 link = _dbus_list_get_first_link (&policy->rules);
754 BusPolicyRule *rule = link->data;
756 link = _dbus_list_get_next_link (&policy->rules, link);
758 /* Rule is skipped if it specifies a different
759 * message name from the message, or a different
760 * origin from the message
763 if (rule->type != BUS_POLICY_RULE_RECEIVE)
766 if (rule->d.receive.message_name != NULL)
768 if (!dbus_message_has_name (message,
769 rule->d.receive.message_name))
773 if (rule->d.receive.origin != NULL)
775 /* sender can be NULL for messages that originate from the
776 * message bus itself, we check the strings in that case as
777 * built-in services don't have a DBusConnection but will
778 * still set the sender on their messages.
782 if (!dbus_message_has_sender (message,
783 rule->d.receive.origin))
791 _dbus_string_init_const (&str, rule->d.receive.origin);
793 service = bus_registry_lookup (registry, &str);
798 if (!bus_service_has_owner (service, sender))
804 allowed = rule->allow;
811 bus_client_policy_check_can_own (BusClientPolicy *policy,
812 DBusConnection *connection,
813 const DBusString *service_name)
818 /* policy->rules is in the order the rules appeared
819 * in the config file, i.e. last rule that applies wins
823 link = _dbus_list_get_first_link (&policy->rules);
826 BusPolicyRule *rule = link->data;
828 link = _dbus_list_get_next_link (&policy->rules, link);
830 /* Rule is skipped if it specifies a different service name from
834 if (rule->type != BUS_POLICY_RULE_OWN)
837 if (rule->d.own.service_name != NULL)
839 if (!_dbus_string_equal_c_str (service_name,
840 rule->d.own.service_name))
845 allowed = rule->allow;
851 #ifdef DBUS_BUILD_TESTS
854 bus_policy_test (const DBusString *test_data_dir)
856 /* This doesn't do anything for now because I decided to do it in
857 * dispatch.c instead by having some of the clients in dispatch.c
858 * have particular policies applied to them.
864 #endif /* DBUS_BUILD_TESTS */