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 void item_append(PolicyItem *i, PolicyItem **list) {
46 LIST_FIND_TAIL(items, *list, tail);
47 LIST_INSERT_AFTER(items, *list, tail, i);
50 static int file_load(Policy *p, const char *path) {
52 _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
53 _cleanup_(policy_item_freep) PolicyItem *i = NULL;
54 void *xml_state = NULL;
66 STATE_POLICY_OTHER_ATTRIBUTE,
68 STATE_ALLOW_DENY_INTERFACE,
69 STATE_ALLOW_DENY_MEMBER,
70 STATE_ALLOW_DENY_ERROR,
71 STATE_ALLOW_DENY_PATH,
72 STATE_ALLOW_DENY_MESSAGE_TYPE,
73 STATE_ALLOW_DENY_NAME,
74 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
76 } state = STATE_OUTSIDE;
80 POLICY_CATEGORY_DEFAULT,
81 POLICY_CATEGORY_MANDATORY,
84 } policy_category = POLICY_CATEGORY_NONE;
90 r = read_full_file(path, &c, NULL);
97 log_error("Failed to load %s: %s", path, strerror(-r));
103 _cleanup_free_ char *name = NULL;
106 t = xml_tokenize(&q, &name, &xml_state, &line);
108 log_error("XML parse failure in %s: %s", path, strerror(-t));
116 if (t == XML_TAG_OPEN) {
117 if (streq(name, "busconfig"))
118 state = STATE_BUSCONFIG;
120 log_error("Unexpected tag %s at %s:%u.", name, path, line);
124 } else if (t == XML_END)
126 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
127 log_error("Unexpected token (1) at %s:%u.", path, line);
133 case STATE_BUSCONFIG:
135 if (t == XML_TAG_OPEN) {
136 if (streq(name, "policy")) {
137 state = STATE_POLICY;
138 policy_category = POLICY_CATEGORY_NONE;
141 policy_user = policy_group = NULL;
146 } else if (t == XML_TAG_CLOSE_EMPTY ||
147 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
148 state = STATE_OUTSIDE;
149 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
150 log_error("Unexpected token (2) at %s:%u.", path, line);
158 if (t == XML_ATTRIBUTE_NAME) {
159 if (streq(name, "context"))
160 state = STATE_POLICY_CONTEXT;
161 else if (streq(name, "user"))
162 state = STATE_POLICY_USER;
163 else if (streq(name, "group"))
164 state = STATE_POLICY_GROUP;
166 if (streq(name, "at_console"))
167 log_debug("Attribute %s of <policy> tag unsupported at %s:%u, ignoring.", name, path, line);
169 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
170 state = STATE_POLICY_OTHER_ATTRIBUTE;
172 } else if (t == XML_TAG_CLOSE_EMPTY ||
173 (t == XML_TAG_CLOSE && streq(name, "policy")))
174 state = STATE_BUSCONFIG;
175 else if (t == XML_TAG_OPEN) {
178 if (streq(name, "allow"))
179 it = POLICY_ITEM_ALLOW;
180 else if (streq(name, "deny"))
181 it = POLICY_ITEM_DENY;
183 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
188 i = new0(PolicyItem, 1);
193 state = STATE_ALLOW_DENY;
195 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
196 log_error("Unexpected token (3) at %s:%u.", path, line);
202 case STATE_POLICY_CONTEXT:
204 if (t == XML_ATTRIBUTE_VALUE) {
205 if (streq(name, "default")) {
206 policy_category = POLICY_CATEGORY_DEFAULT;
207 state = STATE_POLICY;
208 } else if (streq(name, "mandatory")) {
209 policy_category = POLICY_CATEGORY_MANDATORY;
210 state = STATE_POLICY;
212 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
216 log_error("Unexpected token (4) at %s:%u.", path, line);
222 case STATE_POLICY_USER:
224 if (t == XML_ATTRIBUTE_VALUE) {
228 policy_category = POLICY_CATEGORY_USER;
229 state = STATE_POLICY;
231 log_error("Unexpected token (5) in %s:%u.", path, line);
237 case STATE_POLICY_GROUP:
239 if (t == XML_ATTRIBUTE_VALUE) {
243 policy_category = POLICY_CATEGORY_GROUP;
244 state = STATE_POLICY;
246 log_error("Unexpected token (6) at %s:%u.", path, line);
252 case STATE_POLICY_OTHER_ATTRIBUTE:
254 if (t == XML_ATTRIBUTE_VALUE)
255 state = STATE_POLICY;
257 log_error("Unexpected token (7) in %s:%u.", path, line);
263 case STATE_ALLOW_DENY:
267 if (t == XML_ATTRIBUTE_NAME) {
270 if (startswith(name, "send_"))
271 ic = POLICY_ITEM_SEND;
272 else if (startswith(name, "receive_"))
273 ic = POLICY_ITEM_RECV;
274 else if (streq(name, "own"))
275 ic = POLICY_ITEM_OWN;
276 else if (streq(name, "own_prefix"))
277 ic = POLICY_ITEM_OWN_PREFIX;
278 else if (streq(name, "user"))
279 ic = POLICY_ITEM_USER;
280 else if (streq(name, "group"))
281 ic = POLICY_ITEM_GROUP;
282 else if (streq(name, "eavesdrop")) {
283 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
284 i->class = POLICY_ITEM_IGNORE;
285 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
288 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
289 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
293 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
294 log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
300 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
303 u = strchr(name, '_');
308 if (streq(u, "interface"))
309 state = STATE_ALLOW_DENY_INTERFACE;
310 else if (streq(u, "member"))
311 state = STATE_ALLOW_DENY_MEMBER;
312 else if (streq(u, "error"))
313 state = STATE_ALLOW_DENY_ERROR;
314 else if (streq(u, "path"))
315 state = STATE_ALLOW_DENY_PATH;
316 else if (streq(u, "type"))
317 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
318 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
319 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
320 state = STATE_ALLOW_DENY_NAME;
322 if (streq(u, "requested_reply"))
323 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
325 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
326 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
330 state = STATE_ALLOW_DENY_NAME;
332 } else if (t == XML_TAG_CLOSE_EMPTY ||
333 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
335 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
336 log_error("Policy not set at %s:%u.", path, line);
340 if (policy_category == POLICY_CATEGORY_DEFAULT)
341 item_append(i, &p->default_items);
342 else if (policy_category == POLICY_CATEGORY_MANDATORY)
343 item_append(i, &p->mandatory_items);
344 else if (policy_category == POLICY_CATEGORY_USER) {
345 const char *u = policy_user;
347 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
349 r = hashmap_ensure_allocated(&p->user_items, NULL);
354 log_error("User policy without name");
358 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
360 log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
365 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
366 item_append(i, &first);
369 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
371 LIST_REMOVE(items, first, i);
376 } else if (policy_category == POLICY_CATEGORY_GROUP) {
377 const char *g = policy_group;
379 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
381 r = hashmap_ensure_allocated(&p->group_items, NULL);
386 log_error("Group policy without name");
390 r = get_group_creds(&g, &i->gid);
392 log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
397 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
398 item_append(i, &first);
401 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
403 LIST_REMOVE(items, first, i);
409 state = STATE_POLICY;
412 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
413 log_error("Unexpected token (8) at %s:%u.", path, line);
419 case STATE_ALLOW_DENY_INTERFACE:
421 if (t == XML_ATTRIBUTE_VALUE) {
424 log_error("Duplicate interface at %s:%u.", path, line);
430 state = STATE_ALLOW_DENY;
432 log_error("Unexpected token (9) at %s:%u.", path, line);
438 case STATE_ALLOW_DENY_MEMBER:
440 if (t == XML_ATTRIBUTE_VALUE) {
443 log_error("Duplicate member in %s:%u.", path, line);
449 state = STATE_ALLOW_DENY;
451 log_error("Unexpected token (10) in %s:%u.", path, line);
457 case STATE_ALLOW_DENY_ERROR:
459 if (t == XML_ATTRIBUTE_VALUE) {
462 log_error("Duplicate error in %s:%u.", path, line);
468 state = STATE_ALLOW_DENY;
470 log_error("Unexpected token (11) in %s:%u.", path, line);
476 case STATE_ALLOW_DENY_PATH:
478 if (t == XML_ATTRIBUTE_VALUE) {
481 log_error("Duplicate path in %s:%u.", path, line);
487 state = STATE_ALLOW_DENY;
489 log_error("Unexpected token (12) in %s:%u.", path, line);
495 case STATE_ALLOW_DENY_MESSAGE_TYPE:
497 if (t == XML_ATTRIBUTE_VALUE) {
500 if (i->message_type != 0) {
501 log_error("Duplicate message type in %s:%u.", path, line);
505 r = bus_message_type_from_string(name, &i->message_type);
507 log_error("Invalid message type in %s:%u.", path, line);
511 state = STATE_ALLOW_DENY;
513 log_error("Unexpected token (13) in %s:%u.", path, line);
519 case STATE_ALLOW_DENY_NAME:
521 if (t == XML_ATTRIBUTE_VALUE) {
524 log_error("Duplicate name in %s:%u.", path, line);
530 state = STATE_ALLOW_DENY;
532 log_error("Unexpected token (14) in %s:%u.", path, line);
538 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
540 if (t == XML_ATTRIBUTE_VALUE)
541 state = STATE_ALLOW_DENY;
543 log_error("Unexpected token (15) in %s:%u.", path, line);
551 if (t == XML_TAG_OPEN)
553 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
556 state = STATE_BUSCONFIG;
566 int policy_load(Policy *p, char **files) {
572 STRV_FOREACH(i, files) {
574 r = file_load(p, *i);
576 _cleanup_strv_free_ char **l = NULL;
579 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
581 log_error("Failed to get configuration file list: %s", strerror(-r));
589 /* We ignore all errors but EISDIR, and just proceed. */
595 void policy_free(Policy *p) {
596 PolicyItem *i, *first;
601 while ((i = p->default_items)) {
602 LIST_REMOVE(items, p->default_items, i);
606 while ((i = p->mandatory_items)) {
607 LIST_REMOVE(items, p->mandatory_items, i);
611 while ((first = hashmap_steal_first(p->user_items))) {
613 while ((i = first)) {
614 LIST_REMOVE(items, first, i);
619 while ((first = hashmap_steal_first(p->group_items))) {
621 while ((i = first)) {
622 LIST_REMOVE(items, first, i);
627 hashmap_free(p->user_items);
628 hashmap_free(p->group_items);
630 p->user_items = p->group_items = NULL;
633 static void dump_items(PolicyItem *i, const char *prefix) {
641 printf("%sType: %s\n"
643 prefix, policy_item_type_to_string(i->type),
644 prefix, policy_item_class_to_string(i->class));
647 printf("%sInterface: %s\n",
648 prefix, i->interface);
651 printf("%sMember: %s\n",
655 printf("%sError: %s\n",
659 printf("%sPath: %s\n",
663 printf("%sName: %s\n",
666 if (i->message_type != 0)
667 printf("%sMessage Type: %s\n",
668 prefix, bus_message_type_to_string(i->message_type));
671 _cleanup_free_ char *user;
673 user = uid_to_name(i->uid);
675 printf("%sUser: %s\n",
676 prefix, strna(user));
680 _cleanup_free_ char *group;
682 group = gid_to_name(i->gid);
684 printf("%sGroup: %s\n",
685 prefix, strna(group));
689 printf("%s%s\n", prefix, draw_special_char(DRAW_DASH));
690 dump_items(i->items_next, prefix);
694 static void dump_hashmap_items(Hashmap *h) {
699 HASHMAP_FOREACH_KEY(i, k, h, j) {
700 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
701 dump_items(i, "\t\t");
705 noreturn void policy_dump(Policy *p) {
707 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
708 dump_items(p->default_items, "\t");
710 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
711 dump_hashmap_items(p->group_items);
713 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
714 dump_hashmap_items(p->user_items);
716 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
717 dump_items(p->mandatory_items, "\t");
722 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
723 [_POLICY_ITEM_TYPE_UNSET] = "unset",
724 [POLICY_ITEM_ALLOW] = "allow",
725 [POLICY_ITEM_DENY] = "deny",
727 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
729 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
730 [_POLICY_ITEM_CLASS_UNSET] = "unset",
731 [POLICY_ITEM_SEND] = "send",
732 [POLICY_ITEM_RECV] = "recv",
733 [POLICY_ITEM_OWN] = "own",
734 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
735 [POLICY_ITEM_USER] = "user",
736 [POLICY_ITEM_GROUP] = "group",
737 [POLICY_ITEM_IGNORE] = "ignore",
739 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);