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:
93 dbus_free (rule->d.user.user);
95 case BUS_POLICY_RULE_GROUP:
96 dbus_free (rule->d.group.group);
108 DBusList *default_rules; /**< Default policy rules */
109 DBusList *mandatory_rules; /**< Mandatory policy rules */
110 DBusHashTable *rules_by_uid; /**< per-UID policy rules */
111 DBusHashTable *rules_by_gid; /**< per-GID policy rules */
115 free_rule_func (void *data,
118 BusPolicyRule *rule = data;
120 bus_policy_rule_unref (rule);
124 free_rule_list_func (void *data)
126 DBusList **list = data;
128 _dbus_list_foreach (list, free_rule_func, NULL);
130 _dbus_list_clear (list);
136 bus_policy_new (void)
140 policy = dbus_new0 (BusPolicy, 1);
144 policy->refcount = 1;
146 policy->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
148 free_rule_list_func);
149 if (policy->rules_by_uid == NULL)
152 policy->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
154 free_rule_list_func);
155 if (policy->rules_by_gid == NULL)
161 bus_policy_unref (policy);
166 bus_policy_ref (BusPolicy *policy)
168 _dbus_assert (policy->refcount > 0);
170 policy->refcount += 1;
174 bus_policy_unref (BusPolicy *policy)
176 _dbus_assert (policy->refcount > 0);
178 policy->refcount -= 1;
180 if (policy->refcount == 0)
182 _dbus_list_foreach (&policy->default_rules, free_rule_func, NULL);
183 _dbus_list_clear (&policy->default_rules);
185 _dbus_list_foreach (&policy->mandatory_rules, free_rule_func, NULL);
186 _dbus_list_clear (&policy->mandatory_rules);
188 if (policy->rules_by_uid)
190 _dbus_hash_table_unref (policy->rules_by_uid);
191 policy->rules_by_uid = NULL;
194 if (policy->rules_by_gid)
196 _dbus_hash_table_unref (policy->rules_by_gid);
197 policy->rules_by_gid = NULL;
205 add_list_to_client (DBusList **list,
206 BusClientPolicy *client)
210 link = _dbus_list_get_first_link (list);
213 BusPolicyRule *rule = link->data;
214 link = _dbus_list_get_next_link (list, link);
218 case BUS_POLICY_RULE_USER:
219 case BUS_POLICY_RULE_GROUP:
220 /* These aren't per-connection policies */
223 case BUS_POLICY_RULE_OWN:
224 case BUS_POLICY_RULE_SEND:
225 case BUS_POLICY_RULE_RECEIVE:
226 /* These are per-connection */
227 if (!bus_client_policy_append_rule (client, rule))
237 bus_policy_create_client_policy (BusPolicy *policy,
238 DBusConnection *connection)
240 BusClientPolicy *client;
244 _dbus_assert (dbus_connection_get_is_authenticated (connection));
246 client = bus_client_policy_new ();
250 if (!add_list_to_client (&policy->default_rules,
254 /* we avoid the overhead of looking up user's groups
255 * if we don't have any group rules anyway
257 if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0)
259 const unsigned long *groups;
263 if (!bus_connection_get_groups (connection, &groups, &n_groups))
269 list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
274 if (!add_list_to_client (list, client))
282 if (!dbus_connection_get_unix_user (connection, &uid))
285 list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
288 if (!add_list_to_client (list, client))
291 if (!add_list_to_client (&policy->mandatory_rules,
295 bus_client_policy_optimize (client);
300 bus_client_policy_unref (client);
305 list_allows_user (dbus_bool_t def,
308 const unsigned long *group_ids,
314 /* FIXME there's currently no handling of wildcard user/group rules.
319 link = _dbus_list_get_first_link (list);
322 BusPolicyRule *rule = link->data;
323 link = _dbus_list_get_next_link (list, link);
325 if (rule->type == BUS_POLICY_RULE_USER)
327 if (rule->d.user.uid != uid)
330 else if (rule->type == BUS_POLICY_RULE_GROUP)
335 while (i < n_group_ids)
337 if (rule->d.group.gid == group_ids[i])
342 if (i == n_group_ids)
348 allowed = rule->allow;
355 bus_policy_allow_user (BusPolicy *policy,
359 unsigned long *group_ids;
362 /* On OOM or error we always reject the user */
363 if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
365 _dbus_verbose ("Did not get any groups for UID %lu\n",
372 allowed = list_allows_user (allowed,
373 &policy->default_rules,
375 group_ids, n_group_ids);
377 allowed = list_allows_user (allowed,
378 &policy->mandatory_rules,
380 group_ids, n_group_ids);
382 dbus_free (group_ids);
388 bus_policy_append_default_rule (BusPolicy *policy,
391 if (!_dbus_list_append (&policy->default_rules, rule))
394 bus_policy_rule_ref (rule);
400 bus_policy_append_mandatory_rule (BusPolicy *policy,
403 if (!_dbus_list_append (&policy->mandatory_rules, rule))
406 bus_policy_rule_ref (rule);
412 get_list (DBusHashTable *hash,
417 list = _dbus_hash_table_lookup_ulong (hash, key);
421 list = dbus_new0 (DBusList*, 1);
425 if (!_dbus_hash_table_insert_ulong (hash, key, list))
436 bus_policy_append_user_rule (BusPolicy *policy,
442 list = get_list (policy->rules_by_uid, uid);
447 if (!_dbus_list_append (list, rule))
450 bus_policy_rule_ref (rule);
456 bus_policy_append_group_rule (BusPolicy *policy,
462 list = get_list (policy->rules_by_gid, gid);
467 if (!_dbus_list_append (list, rule))
470 bus_policy_rule_ref (rule);
475 struct BusClientPolicy
483 bus_client_policy_new (void)
485 BusClientPolicy *policy;
487 policy = dbus_new0 (BusClientPolicy, 1);
491 policy->refcount = 1;
497 bus_client_policy_ref (BusClientPolicy *policy)
499 _dbus_assert (policy->refcount > 0);
501 policy->refcount += 1;
505 rule_unref_foreach (void *data,
508 BusPolicyRule *rule = data;
510 bus_policy_rule_unref (rule);
514 bus_client_policy_unref (BusClientPolicy *policy)
516 _dbus_assert (policy->refcount > 0);
518 policy->refcount -= 1;
520 if (policy->refcount == 0)
522 _dbus_list_foreach (&policy->rules,
526 _dbus_list_clear (&policy->rules);
533 remove_rules_by_type_up_to (BusClientPolicy *policy,
534 BusPolicyRuleType type,
539 link = _dbus_list_get_first (&policy->rules);
540 while (link != up_to)
542 BusPolicyRule *rule = link->data;
543 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
545 bus_policy_rule_unref (rule);
546 _dbus_list_remove_link (&policy->rules, link);
553 bus_client_policy_optimize (BusClientPolicy *policy)
557 /* The idea here is that if we have:
559 * <allow send="foo"/>
562 * (for example) the deny will always override the allow. So we
563 * delete the allow. Ditto for deny followed by allow, etc. This is
564 * a dumb thing to put in a config file, but the <include> feature
565 * of files allows for an "inheritance and override" pattern where
566 * it could make sense. If an included file wants to "start over"
567 * with a blanket deny, no point keeping the rules from the parent
571 _dbus_verbose ("Optimizing policy with %d rules\n",
572 _dbus_list_get_length (&policy->rules));
574 link = _dbus_list_get_first (&policy->rules);
577 BusPolicyRule *rule = link->data;
578 DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
579 dbus_bool_t remove_preceding;
581 remove_preceding = FALSE;
585 case BUS_POLICY_RULE_SEND:
587 rule->d.send.message_name == NULL &&
588 rule->d.send.destination == NULL;
590 case BUS_POLICY_RULE_RECEIVE:
592 rule->d.receive.message_name == NULL &&
593 rule->d.receive.origin == NULL;
595 case BUS_POLICY_RULE_OWN:
597 rule->d.own.service_name == NULL;
599 case BUS_POLICY_RULE_USER:
600 case BUS_POLICY_RULE_GROUP:
601 _dbus_assert_not_reached ("invalid rule");
605 if (remove_preceding)
606 remove_rules_by_type_up_to (policy, rule->type,
612 _dbus_verbose ("After optimization, policy has %d rules\n",
613 _dbus_list_get_length (&policy->rules));
617 bus_client_policy_append_rule (BusClientPolicy *policy,
620 if (!_dbus_list_append (&policy->rules, rule))
623 bus_policy_rule_ref (rule);
629 bus_client_policy_check_can_send (BusClientPolicy *policy,
630 BusRegistry *registry,
631 DBusConnection *receiver,
632 DBusMessage *message)
637 /* policy->rules is in the order the rules appeared
638 * in the config file, i.e. last rule that applies wins
642 link = _dbus_list_get_first (&policy->rules);
645 BusPolicyRule *rule = link->data;
647 link = _dbus_list_get_next_link (&policy->rules, link);
649 /* Rule is skipped if it specifies a different
650 * message name from the message, or a different
651 * destination from the message
654 if (rule->type != BUS_POLICY_RULE_SEND)
657 if (rule->d.send.message_name != NULL)
659 if (!dbus_message_name_is (message,
660 rule->d.send.message_name))
664 if (rule->d.send.destination != NULL)
666 /* receiver can be NULL for messages that are sent to the
667 * message bus itself, we check the strings in that case as
668 * built-in services don't have a DBusConnection but messages
669 * to them have a destination service name.
671 if (receiver == NULL)
673 if (!dbus_message_sender_is (message,
674 rule->d.send.destination))
682 _dbus_string_init_const (&str, rule->d.send.destination);
684 service = bus_registry_lookup (registry, &str);
688 if (!bus_service_has_owner (service, receiver))
694 allowed = rule->allow;
701 bus_client_policy_check_can_receive (BusClientPolicy *policy,
702 BusRegistry *registry,
703 DBusConnection *sender,
704 DBusMessage *message)
709 /* policy->rules is in the order the rules appeared
710 * in the config file, i.e. last rule that applies wins
714 link = _dbus_list_get_first (&policy->rules);
717 BusPolicyRule *rule = link->data;
719 link = _dbus_list_get_next_link (&policy->rules, link);
721 /* Rule is skipped if it specifies a different
722 * message name from the message, or a different
723 * origin from the message
726 if (rule->type != BUS_POLICY_RULE_RECEIVE)
729 if (rule->d.receive.message_name != NULL)
731 if (!dbus_message_name_is (message,
732 rule->d.receive.message_name))
736 if (rule->d.receive.origin != NULL)
738 /* sender can be NULL for messages that originate from the
739 * message bus itself, we check the strings in that case as
740 * built-in services don't have a DBusConnection but will
741 * still set the sender on their messages.
745 if (!dbus_message_sender_is (message,
746 rule->d.receive.origin))
754 _dbus_string_init_const (&str, rule->d.receive.origin);
756 service = bus_registry_lookup (registry, &str);
761 if (!bus_service_has_owner (service, sender))
767 allowed = rule->allow;
774 bus_client_policy_check_can_own (BusClientPolicy *policy,
775 DBusConnection *connection,
776 const DBusString *service_name)
781 /* policy->rules is in the order the rules appeared
782 * in the config file, i.e. last rule that applies wins
786 link = _dbus_list_get_first (&policy->rules);
789 BusPolicyRule *rule = link->data;
791 link = _dbus_list_get_next_link (&policy->rules, link);
793 /* Rule is skipped if it specifies a different service name from
797 if (rule->type != BUS_POLICY_RULE_OWN)
800 if (rule->d.own.service_name != NULL)
802 if (!_dbus_string_equal_c_str (service_name,
803 rule->d.own.service_name))
808 allowed = rule->allow;
814 #ifdef DBUS_BUILD_TESTS
817 bus_policy_test (const DBusString *test_data_dir)
819 /* This doesn't do anything for now because I decided to do it in
820 * dispatch.c instead by having some of the clients in dispatch.c
821 * have particular policies applied to them.
827 #endif /* DBUS_BUILD_TESTS */