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) {
326 const char *u = policy_user;
328 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
330 r = hashmap_ensure_allocated(&p->user_items, trivial_hash_func, trivial_compare_func);
335 log_error("User policy without name");
339 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
341 log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
346 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
347 LIST_PREPEND(items, first, i);
349 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
351 LIST_REMOVE(items, first, i);
356 } else if (policy_category == POLICY_CATEGORY_GROUP) {
357 const char *g = policy_group;
359 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
361 r = hashmap_ensure_allocated(&p->group_items, trivial_hash_func, trivial_compare_func);
366 log_error("Group policy without name");
370 r = get_group_creds(&g, &i->gid);
372 log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
377 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
378 LIST_PREPEND(items, first, i);
380 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
382 LIST_REMOVE(items, first, i);
388 state = STATE_POLICY;
391 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
392 log_error("Unexpected token (8) at %s:%u.", path, line);
398 case STATE_ALLOW_DENY_INTERFACE:
400 if (t == XML_ATTRIBUTE_VALUE) {
403 log_error("Duplicate interface at %s:%u.", path, line);
409 state = STATE_ALLOW_DENY;
411 log_error("Unexpected token (9) at %s:%u.", path, line);
417 case STATE_ALLOW_DENY_MEMBER:
419 if (t == XML_ATTRIBUTE_VALUE) {
422 log_error("Duplicate member in %s:%u.", path, line);
428 state = STATE_ALLOW_DENY;
430 log_error("Unexpected token (10) in %s:%u.", path, line);
436 case STATE_ALLOW_DENY_ERROR:
438 if (t == XML_ATTRIBUTE_VALUE) {
441 log_error("Duplicate error in %s:%u.", path, line);
447 state = STATE_ALLOW_DENY;
449 log_error("Unexpected token (11) in %s:%u.", path, line);
455 case STATE_ALLOW_DENY_PATH:
457 if (t == XML_ATTRIBUTE_VALUE) {
460 log_error("Duplicate path in %s:%u.", path, line);
466 state = STATE_ALLOW_DENY;
468 log_error("Unexpected token (12) in %s:%u.", path, line);
474 case STATE_ALLOW_DENY_MESSAGE_TYPE:
476 if (t == XML_ATTRIBUTE_VALUE) {
479 if (i->message_type != 0) {
480 log_error("Duplicate message type in %s:%u.", path, line);
484 r = bus_message_type_from_string(name, &i->message_type);
486 log_error("Invalid message type in %s:%u.", path, line);
490 state = STATE_ALLOW_DENY;
492 log_error("Unexpected token (13) in %s:%u.", path, line);
498 case STATE_ALLOW_DENY_NAME:
500 if (t == XML_ATTRIBUTE_VALUE) {
503 log_error("Duplicate name in %s:%u.", path, line);
509 state = STATE_ALLOW_DENY;
511 log_error("Unexpected token (14) in %s:%u.", path, line);
517 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
519 if (t == XML_ATTRIBUTE_VALUE)
520 state = STATE_ALLOW_DENY;
522 log_error("Unexpected token (15) in %s:%u.", path, line);
530 if (t == XML_TAG_OPEN)
532 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
535 state = STATE_BUSCONFIG;
545 int policy_load(Policy *p, char **files) {
551 STRV_FOREACH(i, files) {
553 r = file_load(p, *i);
555 _cleanup_strv_free_ char **l = NULL;
558 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
560 log_error("Failed to get configuration file list: %s", strerror(-r));
568 /* We ignore all errors but EISDIR, and just proceed. */
574 void policy_free(Policy *p) {
575 PolicyItem *i, *first;
580 while ((i = p->default_items)) {
581 LIST_REMOVE(items, p->default_items, i);
585 while ((i = p->mandatory_items)) {
586 LIST_REMOVE(items, p->mandatory_items, i);
590 while ((first = hashmap_steal_first(p->user_items))) {
592 while ((i = first)) {
593 LIST_REMOVE(items, first, i);
598 while ((first = hashmap_steal_first(p->group_items))) {
600 while ((i = first)) {
601 LIST_REMOVE(items, first, i);
606 hashmap_free(p->user_items);
607 hashmap_free(p->group_items);
609 p->user_items = p->group_items = NULL;
612 static void dump_items(PolicyItem *i, const char *prefix) {
620 printf("%sType: %s\n"
622 prefix, policy_item_type_to_string(i->type),
623 prefix, policy_item_class_to_string(i->class));
626 printf("%sInterface: %s\n",
627 prefix, i->interface);
630 printf("%sMember: %s\n",
634 printf("%sError: %s\n",
638 printf("%sPath: %s\n",
642 printf("%sName: %s\n",
645 if (i->message_type != 0)
646 printf("%sMessage Type: %s\n",
647 prefix, bus_message_type_to_string(i->message_type));
650 _cleanup_free_ char *user;
652 user = uid_to_name(i->uid);
654 printf("%sUser: %s\n",
655 prefix, strna(user));
659 _cleanup_free_ char *group;
661 group = gid_to_name(i->gid);
663 printf("%sGroup: %s\n",
664 prefix, strna(group));
668 printf("%s%s\n", prefix, draw_special_char(DRAW_DASH));
669 dump_items(i->items_next, prefix);
673 static void dump_hashmap_items(Hashmap *h) {
678 HASHMAP_FOREACH_KEY(i, k, h, j) {
679 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
680 dump_items(i, "\t\t");
684 noreturn void policy_dump(Policy *p) {
686 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
687 dump_items(p->default_items, "\t");
689 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
690 dump_hashmap_items(p->group_items);
692 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
693 dump_hashmap_items(p->user_items);
695 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
696 dump_items(p->mandatory_items, "\t");
701 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
702 [_POLICY_ITEM_TYPE_UNSET] = "unset",
703 [POLICY_ITEM_ALLOW] = "allow",
704 [POLICY_ITEM_DENY] = "deny",
706 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
708 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
709 [_POLICY_ITEM_CLASS_UNSET] = "unset",
710 [POLICY_ITEM_SEND] = "send",
711 [POLICY_ITEM_RECV] = "recv",
712 [POLICY_ITEM_OWN] = "own",
713 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
714 [POLICY_ITEM_USER] = "user",
715 [POLICY_ITEM_GROUP] = "group",
717 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);