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 const 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))
281 if (!dbus_connection_get_unix_user (connection, &uid))
284 if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
288 list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
293 if (!add_list_to_client (list, client))
298 if (!add_list_to_client (&policy->mandatory_rules,
302 bus_client_policy_optimize (client);
307 bus_client_policy_unref (client);
312 list_allows_user (dbus_bool_t def,
315 const unsigned long *group_ids,
323 link = _dbus_list_get_first_link (list);
326 BusPolicyRule *rule = link->data;
327 link = _dbus_list_get_next_link (list, link);
329 if (rule->type == BUS_POLICY_RULE_USER)
331 _dbus_verbose ("List %p user rule uid="DBUS_UID_FORMAT"\n",
332 list, rule->d.user.uid);
334 if (rule->d.user.uid == DBUS_UID_UNSET)
336 else if (rule->d.user.uid != uid)
339 else if (rule->type == BUS_POLICY_RULE_GROUP)
341 _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n",
342 list, rule->d.user.uid);
344 if (rule->d.group.gid == DBUS_GID_UNSET)
351 while (i < n_group_ids)
353 if (rule->d.group.gid == group_ids[i])
358 if (i == n_group_ids)
365 allowed = rule->allow;
372 bus_policy_allow_user (BusPolicy *policy,
376 unsigned long *group_ids;
379 /* On OOM or error we always reject the user */
380 if (!_dbus_get_groups (uid, &group_ids, &n_group_ids, NULL))
382 _dbus_verbose ("Did not get any groups for UID %lu\n",
389 allowed = list_allows_user (allowed,
390 &policy->default_rules,
392 group_ids, n_group_ids);
394 allowed = list_allows_user (allowed,
395 &policy->mandatory_rules,
397 group_ids, n_group_ids);
399 dbus_free (group_ids);
401 _dbus_verbose ("UID %lu allowed = %d\n", uid, allowed);
407 bus_policy_append_default_rule (BusPolicy *policy,
410 if (!_dbus_list_append (&policy->default_rules, rule))
413 bus_policy_rule_ref (rule);
419 bus_policy_append_mandatory_rule (BusPolicy *policy,
422 if (!_dbus_list_append (&policy->mandatory_rules, rule))
425 bus_policy_rule_ref (rule);
431 get_list (DBusHashTable *hash,
436 list = _dbus_hash_table_lookup_ulong (hash, key);
440 list = dbus_new0 (DBusList*, 1);
444 if (!_dbus_hash_table_insert_ulong (hash, key, list))
455 bus_policy_append_user_rule (BusPolicy *policy,
461 list = get_list (policy->rules_by_uid, uid);
466 if (!_dbus_list_append (list, rule))
469 bus_policy_rule_ref (rule);
475 bus_policy_append_group_rule (BusPolicy *policy,
481 list = get_list (policy->rules_by_gid, gid);
486 if (!_dbus_list_append (list, rule))
489 bus_policy_rule_ref (rule);
494 struct BusClientPolicy
502 bus_client_policy_new (void)
504 BusClientPolicy *policy;
506 policy = dbus_new0 (BusClientPolicy, 1);
510 policy->refcount = 1;
516 bus_client_policy_ref (BusClientPolicy *policy)
518 _dbus_assert (policy->refcount > 0);
520 policy->refcount += 1;
524 rule_unref_foreach (void *data,
527 BusPolicyRule *rule = data;
529 bus_policy_rule_unref (rule);
533 bus_client_policy_unref (BusClientPolicy *policy)
535 _dbus_assert (policy->refcount > 0);
537 policy->refcount -= 1;
539 if (policy->refcount == 0)
541 _dbus_list_foreach (&policy->rules,
545 _dbus_list_clear (&policy->rules);
552 remove_rules_by_type_up_to (BusClientPolicy *policy,
553 BusPolicyRuleType type,
558 link = _dbus_list_get_first_link (&policy->rules);
559 while (link != up_to)
561 BusPolicyRule *rule = link->data;
562 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
564 if (rule->type == type)
566 _dbus_list_remove_link (&policy->rules, link);
567 bus_policy_rule_unref (rule);
575 bus_client_policy_optimize (BusClientPolicy *policy)
579 /* The idea here is that if we have:
581 * <allow send="foo"/>
584 * (for example) the deny will always override the allow. So we
585 * delete the allow. Ditto for deny followed by allow, etc. This is
586 * a dumb thing to put in a config file, but the <include> feature
587 * of files allows for an "inheritance and override" pattern where
588 * it could make sense. If an included file wants to "start over"
589 * with a blanket deny, no point keeping the rules from the parent
593 _dbus_verbose ("Optimizing policy with %d rules\n",
594 _dbus_list_get_length (&policy->rules));
596 link = _dbus_list_get_first_link (&policy->rules);
601 dbus_bool_t remove_preceding;
603 next = _dbus_list_get_next_link (&policy->rules, link);
606 remove_preceding = FALSE;
608 _dbus_assert (rule != NULL);
612 case BUS_POLICY_RULE_SEND:
614 rule->d.send.message_name == NULL &&
615 rule->d.send.destination == NULL;
617 case BUS_POLICY_RULE_RECEIVE:
619 rule->d.receive.message_name == NULL &&
620 rule->d.receive.origin == NULL;
622 case BUS_POLICY_RULE_OWN:
624 rule->d.own.service_name == NULL;
626 case BUS_POLICY_RULE_USER:
627 case BUS_POLICY_RULE_GROUP:
628 _dbus_assert_not_reached ("invalid rule");
632 if (remove_preceding)
633 remove_rules_by_type_up_to (policy, rule->type,
639 _dbus_verbose ("After optimization, policy has %d rules\n",
640 _dbus_list_get_length (&policy->rules));
644 bus_client_policy_append_rule (BusClientPolicy *policy,
647 _dbus_verbose ("Appending rule %p with type %d to policy %p\n",
648 rule, rule->type, policy);
650 if (!_dbus_list_append (&policy->rules, rule))
653 bus_policy_rule_ref (rule);
659 bus_client_policy_check_can_send (BusClientPolicy *policy,
660 BusRegistry *registry,
661 DBusConnection *receiver,
662 DBusMessage *message)
667 /* policy->rules is in the order the rules appeared
668 * in the config file, i.e. last rule that applies wins
672 link = _dbus_list_get_first_link (&policy->rules);
675 BusPolicyRule *rule = link->data;
677 link = _dbus_list_get_next_link (&policy->rules, link);
679 /* Rule is skipped if it specifies a different
680 * message name from the message, or a different
681 * destination from the message
684 if (rule->type != BUS_POLICY_RULE_SEND)
687 if (rule->d.send.message_name != NULL)
689 if (!dbus_message_name_is (message,
690 rule->d.send.message_name))
694 if (rule->d.send.destination != NULL)
696 /* receiver can be NULL for messages that are sent to the
697 * message bus itself, we check the strings in that case as
698 * built-in services don't have a DBusConnection but messages
699 * to them have a destination service name.
701 if (receiver == NULL)
703 if (!dbus_message_sender_is (message,
704 rule->d.send.destination))
712 _dbus_string_init_const (&str, rule->d.send.destination);
714 service = bus_registry_lookup (registry, &str);
718 if (!bus_service_has_owner (service, receiver))
724 allowed = rule->allow;
731 bus_client_policy_check_can_receive (BusClientPolicy *policy,
732 BusRegistry *registry,
733 DBusConnection *sender,
734 DBusMessage *message)
739 /* policy->rules is in the order the rules appeared
740 * in the config file, i.e. last rule that applies wins
744 link = _dbus_list_get_first_link (&policy->rules);
747 BusPolicyRule *rule = link->data;
749 link = _dbus_list_get_next_link (&policy->rules, link);
751 /* Rule is skipped if it specifies a different
752 * message name from the message, or a different
753 * origin from the message
756 if (rule->type != BUS_POLICY_RULE_RECEIVE)
759 if (rule->d.receive.message_name != NULL)
761 if (!dbus_message_name_is (message,
762 rule->d.receive.message_name))
766 if (rule->d.receive.origin != NULL)
768 /* sender can be NULL for messages that originate from the
769 * message bus itself, we check the strings in that case as
770 * built-in services don't have a DBusConnection but will
771 * still set the sender on their messages.
775 if (!dbus_message_sender_is (message,
776 rule->d.receive.origin))
784 _dbus_string_init_const (&str, rule->d.receive.origin);
786 service = bus_registry_lookup (registry, &str);
791 if (!bus_service_has_owner (service, sender))
797 allowed = rule->allow;
804 bus_client_policy_check_can_own (BusClientPolicy *policy,
805 DBusConnection *connection,
806 const DBusString *service_name)
811 /* policy->rules is in the order the rules appeared
812 * in the config file, i.e. last rule that applies wins
816 link = _dbus_list_get_first_link (&policy->rules);
819 BusPolicyRule *rule = link->data;
821 link = _dbus_list_get_next_link (&policy->rules, link);
823 /* Rule is skipped if it specifies a different service name from
827 if (rule->type != BUS_POLICY_RULE_OWN)
830 if (rule->d.own.service_name != NULL)
832 if (!_dbus_string_equal_c_str (service_name,
833 rule->d.own.service_name))
838 allowed = rule->allow;
844 #ifdef DBUS_BUILD_TESTS
847 bus_policy_test (const DBusString *test_data_dir)
849 /* This doesn't do anything for now because I decided to do it in
850 * dispatch.c instead by having some of the clients in dispatch.c
851 * have particular policies applied to them.
857 #endif /* DBUS_BUILD_TESTS */