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 state = STATE_POLICY;
217 log_error("Unexpected token (5) in %s:%u.", path, line);
223 case STATE_POLICY_GROUP:
225 if (t == XML_ATTRIBUTE_VALUE) {
229 state = STATE_POLICY;
231 log_error("Unexpected token (6) at %s:%u.", path, line);
237 case STATE_POLICY_OTHER_ATTRIBUTE:
239 if (t == XML_ATTRIBUTE_VALUE)
240 state = STATE_POLICY;
242 log_error("Unexpected token (7) in %s:%u.", path, line);
248 case STATE_ALLOW_DENY:
252 if (t == XML_ATTRIBUTE_NAME) {
255 if (startswith(name, "send_"))
256 ic = POLICY_ITEM_SEND;
257 else if (startswith(name, "receive_"))
258 ic = POLICY_ITEM_RECV;
259 else if (streq(name, "own"))
260 ic = POLICY_ITEM_OWN;
261 else if (streq(name, "own_prefix"))
262 ic = POLICY_ITEM_OWN_PREFIX;
263 else if (streq(name, "user"))
264 ic = POLICY_ITEM_USER;
265 else if (streq(name, "group"))
266 ic = POLICY_ITEM_GROUP;
268 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
269 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
273 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
274 log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
280 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
283 u = strchr(name, '_');
288 if (streq(u, "interface"))
289 state = STATE_ALLOW_DENY_INTERFACE;
290 else if (streq(u, "member"))
291 state = STATE_ALLOW_DENY_MEMBER;
292 else if (streq(u, "error"))
293 state = STATE_ALLOW_DENY_ERROR;
294 else if (streq(u, "path"))
295 state = STATE_ALLOW_DENY_PATH;
296 else if (streq(u, "type"))
297 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
298 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
299 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
300 state = STATE_ALLOW_DENY_NAME;
302 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
303 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
307 state = STATE_ALLOW_DENY_NAME;
309 } else if (t == XML_TAG_CLOSE_EMPTY ||
310 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
312 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
313 log_error("Policy not set at %s:%u.", path, line);
317 if (policy_category == POLICY_CATEGORY_DEFAULT)
318 LIST_PREPEND(items, p->default_items, i);
319 else if (policy_category == POLICY_CATEGORY_MANDATORY)
320 LIST_PREPEND(items, p->default_items, i);
321 else if (policy_category == POLICY_CATEGORY_USER) {
324 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
326 r = hashmap_ensure_allocated(&p->user_items, trivial_hash_func, trivial_compare_func);
330 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
331 LIST_PREPEND(items, first, i);
333 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
335 LIST_REMOVE(items, first, i);
338 } else if (policy_category == POLICY_CATEGORY_GROUP) {
341 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
343 r = hashmap_ensure_allocated(&p->group_items, trivial_hash_func, trivial_compare_func);
347 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
348 LIST_PREPEND(items, first, i);
350 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
352 LIST_REMOVE(items, first, i);
357 state = STATE_POLICY;
360 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
361 log_error("Unexpected token (8) at %s:%u.", path, line);
367 case STATE_ALLOW_DENY_INTERFACE:
369 if (t == XML_ATTRIBUTE_VALUE) {
372 log_error("Duplicate interface at %s:%u.", path, line);
378 state = STATE_ALLOW_DENY;
380 log_error("Unexpected token (9) at %s:%u.", path, line);
386 case STATE_ALLOW_DENY_MEMBER:
388 if (t == XML_ATTRIBUTE_VALUE) {
391 log_error("Duplicate member in %s:%u.", path, line);
397 state = STATE_ALLOW_DENY;
399 log_error("Unexpected token (10) in %s:%u.", path, line);
405 case STATE_ALLOW_DENY_ERROR:
407 if (t == XML_ATTRIBUTE_VALUE) {
410 log_error("Duplicate error in %s:%u.", path, line);
416 state = STATE_ALLOW_DENY;
418 log_error("Unexpected token (11) in %s:%u.", path, line);
424 case STATE_ALLOW_DENY_PATH:
426 if (t == XML_ATTRIBUTE_VALUE) {
429 log_error("Duplicate path in %s:%u.", path, line);
435 state = STATE_ALLOW_DENY;
437 log_error("Unexpected token (12) in %s:%u.", path, line);
443 case STATE_ALLOW_DENY_MESSAGE_TYPE:
445 if (t == XML_ATTRIBUTE_VALUE) {
448 if (i->message_type != 0) {
449 log_error("Duplicate message type in %s:%u.", path, line);
453 r = bus_message_type_from_string(name, &i->message_type);
455 log_error("Invalid message type in %s:%u.", path, line);
459 state = STATE_ALLOW_DENY;
461 log_error("Unexpected token (13) in %s:%u.", path, line);
467 case STATE_ALLOW_DENY_NAME:
469 if (t == XML_ATTRIBUTE_VALUE) {
472 log_error("Duplicate name in %s:%u.", path, line);
478 state = STATE_ALLOW_DENY;
480 log_error("Unexpected token (14) in %s:%u.", path, line);
486 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
488 if (t == XML_ATTRIBUTE_VALUE)
489 state = STATE_ALLOW_DENY;
491 log_error("Unexpected token (15) in %s:%u.", path, line);
499 if (t == XML_TAG_OPEN)
501 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
504 state = STATE_BUSCONFIG;
514 int policy_load(Policy *p) {
515 _cleanup_strv_free_ char **l = NULL;
521 file_load(p, "/etc/dbus-1/system.conf");
522 file_load(p, "/etc/dbus-1/system-local.conf");
524 r = conf_files_list(&l, ".conf", NULL, "/etc/dbus-1/system.d/", NULL);
526 log_error("Failed to get configuration file list: %s", strerror(-r));
536 void policy_free(Policy *p) {
537 PolicyItem *i, *first;
542 while ((i = p->default_items)) {
543 LIST_REMOVE(items, p->default_items, i);
547 while ((i = p->mandatory_items)) {
548 LIST_REMOVE(items, p->mandatory_items, i);
552 while ((first = hashmap_steal_first(p->user_items))) {
554 while ((i = first)) {
555 LIST_REMOVE(items, first, i);
562 while ((first = hashmap_steal_first(p->group_items))) {
564 while ((i = first)) {
565 LIST_REMOVE(items, first, i);
572 hashmap_free(p->user_items);
573 hashmap_free(p->group_items);
575 p->user_items = p->group_items = NULL;
578 static void dump_items(PolicyItem *i) {
585 policy_item_type_to_string(i->type),
586 policy_item_class_to_string(i->class));
589 printf("Interface: %s\n",
593 printf("Member: %s\n",
597 printf("Error: %s\n",
608 if (i->message_type != 0)
609 printf("Message Type: %s\n",
610 bus_message_type_to_string(i->message_type));
613 _cleanup_free_ char *user;
615 user = uid_to_name(i->uid);
622 _cleanup_free_ char *group;
624 group = gid_to_name(i->gid);
626 printf("Group: %s\n",
632 dump_items(i->items_next);
636 static void dump_hashmap_items(Hashmap *h) {
641 HASHMAP_FOREACH_KEY(i, k, h, j) {
642 printf("Item for %s", k);
647 void policy_dump(Policy *p) {
649 printf("→ Default Items:\n");
650 dump_items(p->default_items);
652 printf("→ Mandatory Items:\n");
653 dump_items(p->mandatory_items);
655 printf("→ Group Items:\n");
656 dump_hashmap_items(p->group_items);
658 printf("→ User Items:\n");
659 dump_hashmap_items(p->user_items);
663 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
664 [_POLICY_ITEM_TYPE_UNSET] = "unset",
665 [POLICY_ITEM_ALLOW] = "allow",
666 [POLICY_ITEM_DENY] = "deny",
668 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
670 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
671 [_POLICY_ITEM_CLASS_UNSET] = "unset",
672 [POLICY_ITEM_SEND] = "send",
673 [POLICY_ITEM_RECV] = "recv",
674 [POLICY_ITEM_OWN] = "own",
675 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
676 [POLICY_ITEM_USER] = "user",
677 [POLICY_ITEM_GROUP] = "group",
679 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);