1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "conf-files.h"
26 #include "bus-internal.h"
27 #include "bus-policy.h"
29 static void policy_item_free(PolicyItem *i) {
40 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
42 static int file_load(Policy *p, const char *path) {
44 _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
45 _cleanup_(policy_item_freep) PolicyItem *i = NULL;
46 void *xml_state = NULL;
58 STATE_POLICY_OTHER_ATTRIBUTE,
60 STATE_ALLOW_DENY_INTERFACE,
61 STATE_ALLOW_DENY_MEMBER,
62 STATE_ALLOW_DENY_ERROR,
63 STATE_ALLOW_DENY_PATH,
64 STATE_ALLOW_DENY_MESSAGE_TYPE,
65 STATE_ALLOW_DENY_NAME,
66 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
68 } state = STATE_OUTSIDE;
72 POLICY_CATEGORY_DEFAULT,
73 POLICY_CATEGORY_MANDATORY,
76 } policy_category = POLICY_CATEGORY_NONE;
82 r = read_full_file(path, &c, NULL);
87 log_error("Failed to load %s: %s", path, strerror(-r));
93 _cleanup_free_ char *name = NULL;
96 t = xml_tokenize(&q, &name, &xml_state, &line);
98 log_error("XML parse failure in %s: %s", path, strerror(-t));
106 if (t == XML_TAG_OPEN) {
107 if (streq(name, "busconfig"))
108 state = STATE_BUSCONFIG;
110 log_error("Unexpected tag %s at %s:%u.", name, path, line);
114 } else if (t == XML_END)
116 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
117 log_error("Unexpected token (1) at %s:%u.", path, line);
123 case STATE_BUSCONFIG:
125 if (t == XML_TAG_OPEN) {
126 if (streq(name, "policy")) {
127 state = STATE_POLICY;
128 policy_category = POLICY_CATEGORY_NONE;
131 policy_user = policy_group = NULL;
136 } else if (t == XML_TAG_CLOSE_EMPTY ||
137 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
138 state = STATE_OUTSIDE;
139 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
140 log_error("Unexpected token (2) at %s:%u.", path, line);
148 if (t == XML_ATTRIBUTE_NAME) {
149 if (streq(name, "context"))
150 state = STATE_POLICY_CONTEXT;
151 else if (streq(name, "user"))
152 state = STATE_POLICY_USER;
153 else if (streq(name, "group"))
154 state = STATE_POLICY_GROUP;
156 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
157 state = STATE_POLICY_OTHER_ATTRIBUTE;
159 } else if (t == XML_TAG_CLOSE_EMPTY ||
160 (t == XML_TAG_CLOSE && streq(name, "policy")))
161 state = STATE_BUSCONFIG;
162 else if (t == XML_TAG_OPEN) {
165 if (streq(name, "allow"))
166 it = POLICY_ITEM_ALLOW;
167 else if (streq(name, "deny"))
168 it = POLICY_ITEM_DENY;
170 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
175 i = new0(PolicyItem, 1);
180 state = STATE_ALLOW_DENY;
182 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
183 log_error("Unexpected token (3) at %s:%u.", path, line);
189 case STATE_POLICY_CONTEXT:
191 if (t == XML_ATTRIBUTE_VALUE) {
192 if (streq(name, "default")) {
193 policy_category = POLICY_CATEGORY_DEFAULT;
194 state = STATE_POLICY;
195 } else if (streq(name, "mandatory")) {
196 policy_category = POLICY_CATEGORY_MANDATORY;
197 state = STATE_POLICY;
199 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
203 log_error("Unexpected token (4) at %s:%u.", path, line);
209 case STATE_POLICY_USER:
211 if (t == XML_ATTRIBUTE_VALUE) {
215 policy_category = POLICY_CATEGORY_USER;
216 state = STATE_POLICY;
218 log_error("Unexpected token (5) in %s:%u.", path, line);
224 case STATE_POLICY_GROUP:
226 if (t == XML_ATTRIBUTE_VALUE) {
230 policy_category = POLICY_CATEGORY_GROUP;
231 state = STATE_POLICY;
233 log_error("Unexpected token (6) at %s:%u.", path, line);
239 case STATE_POLICY_OTHER_ATTRIBUTE:
241 if (t == XML_ATTRIBUTE_VALUE)
242 state = STATE_POLICY;
244 log_error("Unexpected token (7) in %s:%u.", path, line);
250 case STATE_ALLOW_DENY:
254 if (t == XML_ATTRIBUTE_NAME) {
257 if (startswith(name, "send_"))
258 ic = POLICY_ITEM_SEND;
259 else if (startswith(name, "receive_"))
260 ic = POLICY_ITEM_RECV;
261 else if (streq(name, "own"))
262 ic = POLICY_ITEM_OWN;
263 else if (streq(name, "own_prefix"))
264 ic = POLICY_ITEM_OWN_PREFIX;
265 else if (streq(name, "user"))
266 ic = POLICY_ITEM_USER;
267 else if (streq(name, "group"))
268 ic = POLICY_ITEM_GROUP;
270 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
271 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
275 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
276 log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
282 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
285 u = strchr(name, '_');
290 if (streq(u, "interface"))
291 state = STATE_ALLOW_DENY_INTERFACE;
292 else if (streq(u, "member"))
293 state = STATE_ALLOW_DENY_MEMBER;
294 else if (streq(u, "error"))
295 state = STATE_ALLOW_DENY_ERROR;
296 else if (streq(u, "path"))
297 state = STATE_ALLOW_DENY_PATH;
298 else if (streq(u, "type"))
299 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
300 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
301 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
302 state = STATE_ALLOW_DENY_NAME;
304 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
305 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
309 state = STATE_ALLOW_DENY_NAME;
311 } else if (t == XML_TAG_CLOSE_EMPTY ||
312 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
314 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
315 log_error("Policy not set at %s:%u.", path, line);
319 if (policy_category == POLICY_CATEGORY_DEFAULT)
320 LIST_PREPEND(items, p->default_items, i);
321 else if (policy_category == POLICY_CATEGORY_MANDATORY)
322 LIST_PREPEND(items, p->default_items, i);
323 else if (policy_category == POLICY_CATEGORY_USER) {
326 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
328 r = hashmap_ensure_allocated(&p->user_items, trivial_hash_func, trivial_compare_func);
332 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
333 LIST_PREPEND(items, first, i);
335 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
337 LIST_REMOVE(items, first, i);
340 } else if (policy_category == POLICY_CATEGORY_GROUP) {
343 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
345 r = hashmap_ensure_allocated(&p->group_items, trivial_hash_func, trivial_compare_func);
349 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
350 LIST_PREPEND(items, first, i);
352 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
354 LIST_REMOVE(items, first, i);
359 state = STATE_POLICY;
362 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
363 log_error("Unexpected token (8) at %s:%u.", path, line);
369 case STATE_ALLOW_DENY_INTERFACE:
371 if (t == XML_ATTRIBUTE_VALUE) {
374 log_error("Duplicate interface at %s:%u.", path, line);
380 state = STATE_ALLOW_DENY;
382 log_error("Unexpected token (9) at %s:%u.", path, line);
388 case STATE_ALLOW_DENY_MEMBER:
390 if (t == XML_ATTRIBUTE_VALUE) {
393 log_error("Duplicate member in %s:%u.", path, line);
399 state = STATE_ALLOW_DENY;
401 log_error("Unexpected token (10) in %s:%u.", path, line);
407 case STATE_ALLOW_DENY_ERROR:
409 if (t == XML_ATTRIBUTE_VALUE) {
412 log_error("Duplicate error in %s:%u.", path, line);
418 state = STATE_ALLOW_DENY;
420 log_error("Unexpected token (11) in %s:%u.", path, line);
426 case STATE_ALLOW_DENY_PATH:
428 if (t == XML_ATTRIBUTE_VALUE) {
431 log_error("Duplicate path in %s:%u.", path, line);
437 state = STATE_ALLOW_DENY;
439 log_error("Unexpected token (12) in %s:%u.", path, line);
445 case STATE_ALLOW_DENY_MESSAGE_TYPE:
447 if (t == XML_ATTRIBUTE_VALUE) {
450 if (i->message_type != 0) {
451 log_error("Duplicate message type in %s:%u.", path, line);
455 r = bus_message_type_from_string(name, &i->message_type);
457 log_error("Invalid message type in %s:%u.", path, line);
461 state = STATE_ALLOW_DENY;
463 log_error("Unexpected token (13) in %s:%u.", path, line);
469 case STATE_ALLOW_DENY_NAME:
471 if (t == XML_ATTRIBUTE_VALUE) {
474 log_error("Duplicate name in %s:%u.", path, line);
480 state = STATE_ALLOW_DENY;
482 log_error("Unexpected token (14) in %s:%u.", path, line);
488 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
490 if (t == XML_ATTRIBUTE_VALUE)
491 state = STATE_ALLOW_DENY;
493 log_error("Unexpected token (15) in %s:%u.", path, line);
501 if (t == XML_TAG_OPEN)
503 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
506 state = STATE_BUSCONFIG;
516 int policy_load(Policy *p) {
517 _cleanup_strv_free_ char **l = NULL;
523 file_load(p, "/etc/dbus-1/system.conf");
524 file_load(p, "/etc/dbus-1/system-local.conf");
526 r = conf_files_list(&l, ".conf", NULL, "/etc/dbus-1/system.d/", NULL);
528 log_error("Failed to get configuration file list: %s", strerror(-r));
538 void policy_free(Policy *p) {
539 PolicyItem *i, *first;
544 while ((i = p->default_items)) {
545 LIST_REMOVE(items, p->default_items, i);
549 while ((i = p->mandatory_items)) {
550 LIST_REMOVE(items, p->mandatory_items, i);
554 while ((first = hashmap_steal_first(p->user_items))) {
556 while ((i = first)) {
557 LIST_REMOVE(items, first, i);
562 while ((first = hashmap_steal_first(p->group_items))) {
564 while ((i = first)) {
565 LIST_REMOVE(items, first, i);
570 hashmap_free(p->user_items);
571 hashmap_free(p->group_items);
573 p->user_items = p->group_items = NULL;
576 static void dump_items(PolicyItem *i) {
583 policy_item_type_to_string(i->type),
584 policy_item_class_to_string(i->class));
587 printf("Interface: %s\n",
591 printf("Member: %s\n",
595 printf("Error: %s\n",
606 if (i->message_type != 0)
607 printf("Message Type: %s\n",
608 bus_message_type_to_string(i->message_type));
611 _cleanup_free_ char *user;
613 user = uid_to_name(i->uid);
620 _cleanup_free_ char *group;
622 group = gid_to_name(i->gid);
624 printf("Group: %s\n",
630 dump_items(i->items_next);
634 static void dump_hashmap_items(Hashmap *h) {
639 HASHMAP_FOREACH_KEY(i, k, h, j) {
640 printf("Item for %u:\n", PTR_TO_UINT(k));
645 noreturn void policy_dump(Policy *p) {
647 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
648 dump_items(p->default_items);
650 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
651 dump_items(p->mandatory_items);
653 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
654 dump_hashmap_items(p->group_items);
656 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
657 dump_hashmap_items(p->user_items);
661 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
662 [_POLICY_ITEM_TYPE_UNSET] = "unset",
663 [POLICY_ITEM_ALLOW] = "allow",
664 [POLICY_ITEM_DENY] = "deny",
666 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
668 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
669 [_POLICY_ITEM_CLASS_UNSET] = "unset",
670 [POLICY_ITEM_SEND] = "send",
671 [POLICY_ITEM_RECV] = "recv",
672 [POLICY_ITEM_OWN] = "own",
673 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
674 [POLICY_ITEM_USER] = "user",
675 [POLICY_ITEM_GROUP] = "group",
677 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);