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);
89 log_error("Failed to load %s: %s", path, strerror(-r));
95 _cleanup_free_ char *name = NULL;
98 t = xml_tokenize(&q, &name, &xml_state, &line);
100 log_error("XML parse failure in %s: %s", path, strerror(-t));
108 if (t == XML_TAG_OPEN) {
109 if (streq(name, "busconfig"))
110 state = STATE_BUSCONFIG;
112 log_error("Unexpected tag %s at %s:%u.", name, path, line);
116 } else if (t == XML_END)
118 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
119 log_error("Unexpected token (1) at %s:%u.", path, line);
125 case STATE_BUSCONFIG:
127 if (t == XML_TAG_OPEN) {
128 if (streq(name, "policy")) {
129 state = STATE_POLICY;
130 policy_category = POLICY_CATEGORY_NONE;
133 policy_user = policy_group = NULL;
138 } else if (t == XML_TAG_CLOSE_EMPTY ||
139 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
140 state = STATE_OUTSIDE;
141 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
142 log_error("Unexpected token (2) at %s:%u.", path, line);
150 if (t == XML_ATTRIBUTE_NAME) {
151 if (streq(name, "context"))
152 state = STATE_POLICY_CONTEXT;
153 else if (streq(name, "user"))
154 state = STATE_POLICY_USER;
155 else if (streq(name, "group"))
156 state = STATE_POLICY_GROUP;
158 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
159 state = STATE_POLICY_OTHER_ATTRIBUTE;
161 } else if (t == XML_TAG_CLOSE_EMPTY ||
162 (t == XML_TAG_CLOSE && streq(name, "policy")))
163 state = STATE_BUSCONFIG;
164 else if (t == XML_TAG_OPEN) {
167 if (streq(name, "allow"))
168 it = POLICY_ITEM_ALLOW;
169 else if (streq(name, "deny"))
170 it = POLICY_ITEM_DENY;
172 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
177 i = new0(PolicyItem, 1);
182 state = STATE_ALLOW_DENY;
184 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
185 log_error("Unexpected token (3) at %s:%u.", path, line);
191 case STATE_POLICY_CONTEXT:
193 if (t == XML_ATTRIBUTE_VALUE) {
194 if (streq(name, "default")) {
195 policy_category = POLICY_CATEGORY_DEFAULT;
196 state = STATE_POLICY;
197 } else if (streq(name, "mandatory")) {
198 policy_category = POLICY_CATEGORY_MANDATORY;
199 state = STATE_POLICY;
201 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
205 log_error("Unexpected token (4) at %s:%u.", path, line);
211 case STATE_POLICY_USER:
213 if (t == XML_ATTRIBUTE_VALUE) {
217 policy_category = POLICY_CATEGORY_USER;
218 state = STATE_POLICY;
220 log_error("Unexpected token (5) in %s:%u.", path, line);
226 case STATE_POLICY_GROUP:
228 if (t == XML_ATTRIBUTE_VALUE) {
232 policy_category = POLICY_CATEGORY_GROUP;
233 state = STATE_POLICY;
235 log_error("Unexpected token (6) at %s:%u.", path, line);
241 case STATE_POLICY_OTHER_ATTRIBUTE:
243 if (t == XML_ATTRIBUTE_VALUE)
244 state = STATE_POLICY;
246 log_error("Unexpected token (7) in %s:%u.", path, line);
252 case STATE_ALLOW_DENY:
256 if (t == XML_ATTRIBUTE_NAME) {
259 if (startswith(name, "send_"))
260 ic = POLICY_ITEM_SEND;
261 else if (startswith(name, "receive_"))
262 ic = POLICY_ITEM_RECV;
263 else if (streq(name, "own"))
264 ic = POLICY_ITEM_OWN;
265 else if (streq(name, "own_prefix"))
266 ic = POLICY_ITEM_OWN_PREFIX;
267 else if (streq(name, "user"))
268 ic = POLICY_ITEM_USER;
269 else if (streq(name, "group"))
270 ic = POLICY_ITEM_GROUP;
272 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
273 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
277 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
278 log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
284 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
287 u = strchr(name, '_');
292 if (streq(u, "interface"))
293 state = STATE_ALLOW_DENY_INTERFACE;
294 else if (streq(u, "member"))
295 state = STATE_ALLOW_DENY_MEMBER;
296 else if (streq(u, "error"))
297 state = STATE_ALLOW_DENY_ERROR;
298 else if (streq(u, "path"))
299 state = STATE_ALLOW_DENY_PATH;
300 else if (streq(u, "type"))
301 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
302 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
303 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
304 state = STATE_ALLOW_DENY_NAME;
306 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
307 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
311 state = STATE_ALLOW_DENY_NAME;
313 } else if (t == XML_TAG_CLOSE_EMPTY ||
314 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
316 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
317 log_error("Policy not set at %s:%u.", path, line);
321 if (policy_category == POLICY_CATEGORY_DEFAULT)
322 LIST_PREPEND(items, p->default_items, i);
323 else if (policy_category == POLICY_CATEGORY_MANDATORY)
324 LIST_PREPEND(items, p->default_items, i);
325 else if (policy_category == POLICY_CATEGORY_USER) {
328 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
330 r = hashmap_ensure_allocated(&p->user_items, trivial_hash_func, trivial_compare_func);
334 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
335 LIST_PREPEND(items, first, i);
337 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
339 LIST_REMOVE(items, first, i);
342 } else if (policy_category == POLICY_CATEGORY_GROUP) {
345 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
347 r = hashmap_ensure_allocated(&p->group_items, trivial_hash_func, trivial_compare_func);
351 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
352 LIST_PREPEND(items, first, i);
354 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
356 LIST_REMOVE(items, first, i);
361 state = STATE_POLICY;
364 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
365 log_error("Unexpected token (8) at %s:%u.", path, line);
371 case STATE_ALLOW_DENY_INTERFACE:
373 if (t == XML_ATTRIBUTE_VALUE) {
376 log_error("Duplicate interface at %s:%u.", path, line);
382 state = STATE_ALLOW_DENY;
384 log_error("Unexpected token (9) at %s:%u.", path, line);
390 case STATE_ALLOW_DENY_MEMBER:
392 if (t == XML_ATTRIBUTE_VALUE) {
395 log_error("Duplicate member in %s:%u.", path, line);
401 state = STATE_ALLOW_DENY;
403 log_error("Unexpected token (10) in %s:%u.", path, line);
409 case STATE_ALLOW_DENY_ERROR:
411 if (t == XML_ATTRIBUTE_VALUE) {
414 log_error("Duplicate error in %s:%u.", path, line);
420 state = STATE_ALLOW_DENY;
422 log_error("Unexpected token (11) in %s:%u.", path, line);
428 case STATE_ALLOW_DENY_PATH:
430 if (t == XML_ATTRIBUTE_VALUE) {
433 log_error("Duplicate path in %s:%u.", path, line);
439 state = STATE_ALLOW_DENY;
441 log_error("Unexpected token (12) in %s:%u.", path, line);
447 case STATE_ALLOW_DENY_MESSAGE_TYPE:
449 if (t == XML_ATTRIBUTE_VALUE) {
452 if (i->message_type != 0) {
453 log_error("Duplicate message type in %s:%u.", path, line);
457 r = bus_message_type_from_string(name, &i->message_type);
459 log_error("Invalid message type in %s:%u.", path, line);
463 state = STATE_ALLOW_DENY;
465 log_error("Unexpected token (13) in %s:%u.", path, line);
471 case STATE_ALLOW_DENY_NAME:
473 if (t == XML_ATTRIBUTE_VALUE) {
476 log_error("Duplicate name in %s:%u.", path, line);
482 state = STATE_ALLOW_DENY;
484 log_error("Unexpected token (14) in %s:%u.", path, line);
490 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
492 if (t == XML_ATTRIBUTE_VALUE)
493 state = STATE_ALLOW_DENY;
495 log_error("Unexpected token (15) in %s:%u.", path, line);
503 if (t == XML_TAG_OPEN)
505 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
508 state = STATE_BUSCONFIG;
518 int policy_load(Policy *p, char **files) {
524 STRV_FOREACH(i, files) {
526 r = file_load(p, *i);
528 _cleanup_strv_free_ char **l = NULL;
531 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
533 log_error("Failed to get configuration file list: %s", strerror(-r));
541 /* We ignore all errors but EISDIR, and just proceed. */
547 void policy_free(Policy *p) {
548 PolicyItem *i, *first;
553 while ((i = p->default_items)) {
554 LIST_REMOVE(items, p->default_items, i);
558 while ((i = p->mandatory_items)) {
559 LIST_REMOVE(items, p->mandatory_items, i);
563 while ((first = hashmap_steal_first(p->user_items))) {
565 while ((i = first)) {
566 LIST_REMOVE(items, first, i);
571 while ((first = hashmap_steal_first(p->group_items))) {
573 while ((i = first)) {
574 LIST_REMOVE(items, first, i);
579 hashmap_free(p->user_items);
580 hashmap_free(p->group_items);
582 p->user_items = p->group_items = NULL;
585 static void dump_items(PolicyItem *i) {
592 policy_item_type_to_string(i->type),
593 policy_item_class_to_string(i->class));
596 printf("Interface: %s\n",
600 printf("Member: %s\n",
604 printf("Error: %s\n",
615 if (i->message_type != 0)
616 printf("Message Type: %s\n",
617 bus_message_type_to_string(i->message_type));
620 _cleanup_free_ char *user;
622 user = uid_to_name(i->uid);
629 _cleanup_free_ char *group;
631 group = gid_to_name(i->gid);
633 printf("Group: %s\n",
639 dump_items(i->items_next);
643 static void dump_hashmap_items(Hashmap *h) {
648 HASHMAP_FOREACH_KEY(i, k, h, j) {
649 printf("Item for %u:\n", PTR_TO_UINT(k));
654 noreturn void policy_dump(Policy *p) {
656 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
657 dump_items(p->default_items);
659 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
660 dump_items(p->mandatory_items);
662 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
663 dump_hashmap_items(p->group_items);
665 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
666 dump_hashmap_items(p->user_items);
670 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
671 [_POLICY_ITEM_TYPE_UNSET] = "unset",
672 [POLICY_ITEM_ALLOW] = "allow",
673 [POLICY_ITEM_DENY] = "deny",
675 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
677 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
678 [_POLICY_ITEM_CLASS_UNSET] = "unset",
679 [POLICY_ITEM_SEND] = "send",
680 [POLICY_ITEM_RECV] = "recv",
681 [POLICY_ITEM_OWN] = "own",
682 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
683 [POLICY_ITEM_USER] = "user",
684 [POLICY_ITEM_GROUP] = "group",
686 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);