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);
368 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
370 LIST_REMOVE(items, first, i);
375 } else if (policy_category == POLICY_CATEGORY_GROUP) {
376 const char *g = policy_group;
378 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
380 r = hashmap_ensure_allocated(&p->group_items, NULL);
385 log_error("Group policy without name");
389 r = get_group_creds(&g, &i->gid);
391 log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
396 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
397 item_append(i, &first);
399 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
401 LIST_REMOVE(items, first, i);
407 state = STATE_POLICY;
410 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
411 log_error("Unexpected token (8) at %s:%u.", path, line);
417 case STATE_ALLOW_DENY_INTERFACE:
419 if (t == XML_ATTRIBUTE_VALUE) {
422 log_error("Duplicate interface at %s:%u.", path, line);
428 state = STATE_ALLOW_DENY;
430 log_error("Unexpected token (9) at %s:%u.", path, line);
436 case STATE_ALLOW_DENY_MEMBER:
438 if (t == XML_ATTRIBUTE_VALUE) {
441 log_error("Duplicate member in %s:%u.", path, line);
447 state = STATE_ALLOW_DENY;
449 log_error("Unexpected token (10) in %s:%u.", path, line);
455 case STATE_ALLOW_DENY_ERROR:
457 if (t == XML_ATTRIBUTE_VALUE) {
460 log_error("Duplicate error in %s:%u.", path, line);
466 state = STATE_ALLOW_DENY;
468 log_error("Unexpected token (11) in %s:%u.", path, line);
474 case STATE_ALLOW_DENY_PATH:
476 if (t == XML_ATTRIBUTE_VALUE) {
479 log_error("Duplicate path in %s:%u.", path, line);
485 state = STATE_ALLOW_DENY;
487 log_error("Unexpected token (12) in %s:%u.", path, line);
493 case STATE_ALLOW_DENY_MESSAGE_TYPE:
495 if (t == XML_ATTRIBUTE_VALUE) {
498 if (i->message_type != 0) {
499 log_error("Duplicate message type in %s:%u.", path, line);
503 r = bus_message_type_from_string(name, &i->message_type);
505 log_error("Invalid message type in %s:%u.", path, line);
509 state = STATE_ALLOW_DENY;
511 log_error("Unexpected token (13) in %s:%u.", path, line);
517 case STATE_ALLOW_DENY_NAME:
519 if (t == XML_ATTRIBUTE_VALUE) {
522 log_error("Duplicate name in %s:%u.", path, line);
528 state = STATE_ALLOW_DENY;
530 log_error("Unexpected token (14) in %s:%u.", path, line);
536 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
538 if (t == XML_ATTRIBUTE_VALUE)
539 state = STATE_ALLOW_DENY;
541 log_error("Unexpected token (15) in %s:%u.", path, line);
549 if (t == XML_TAG_OPEN)
551 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
554 state = STATE_BUSCONFIG;
564 int policy_load(Policy *p, char **files) {
570 STRV_FOREACH(i, files) {
572 r = file_load(p, *i);
574 _cleanup_strv_free_ char **l = NULL;
577 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
579 log_error("Failed to get configuration file list: %s", strerror(-r));
587 /* We ignore all errors but EISDIR, and just proceed. */
593 void policy_free(Policy *p) {
594 PolicyItem *i, *first;
599 while ((i = p->default_items)) {
600 LIST_REMOVE(items, p->default_items, i);
604 while ((i = p->mandatory_items)) {
605 LIST_REMOVE(items, p->mandatory_items, i);
609 while ((first = hashmap_steal_first(p->user_items))) {
611 while ((i = first)) {
612 LIST_REMOVE(items, first, i);
617 while ((first = hashmap_steal_first(p->group_items))) {
619 while ((i = first)) {
620 LIST_REMOVE(items, first, i);
625 hashmap_free(p->user_items);
626 hashmap_free(p->group_items);
628 p->user_items = p->group_items = NULL;
631 static void dump_items(PolicyItem *i, const char *prefix) {
639 printf("%sType: %s\n"
641 prefix, policy_item_type_to_string(i->type),
642 prefix, policy_item_class_to_string(i->class));
645 printf("%sInterface: %s\n",
646 prefix, i->interface);
649 printf("%sMember: %s\n",
653 printf("%sError: %s\n",
657 printf("%sPath: %s\n",
661 printf("%sName: %s\n",
664 if (i->message_type != 0)
665 printf("%sMessage Type: %s\n",
666 prefix, bus_message_type_to_string(i->message_type));
669 _cleanup_free_ char *user;
671 user = uid_to_name(i->uid);
673 printf("%sUser: %s\n",
674 prefix, strna(user));
678 _cleanup_free_ char *group;
680 group = gid_to_name(i->gid);
682 printf("%sGroup: %s\n",
683 prefix, strna(group));
687 printf("%s%s\n", prefix, draw_special_char(DRAW_DASH));
688 dump_items(i->items_next, prefix);
692 static void dump_hashmap_items(Hashmap *h) {
697 HASHMAP_FOREACH_KEY(i, k, h, j) {
698 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
699 dump_items(i, "\t\t");
703 noreturn void policy_dump(Policy *p) {
705 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
706 dump_items(p->default_items, "\t");
708 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
709 dump_hashmap_items(p->group_items);
711 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
712 dump_hashmap_items(p->user_items);
714 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
715 dump_items(p->mandatory_items, "\t");
720 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
721 [_POLICY_ITEM_TYPE_UNSET] = "unset",
722 [POLICY_ITEM_ALLOW] = "allow",
723 [POLICY_ITEM_DENY] = "deny",
725 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
727 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
728 [_POLICY_ITEM_CLASS_UNSET] = "unset",
729 [POLICY_ITEM_SEND] = "send",
730 [POLICY_ITEM_RECV] = "recv",
731 [POLICY_ITEM_OWN] = "own",
732 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
733 [POLICY_ITEM_USER] = "user",
734 [POLICY_ITEM_GROUP] = "group",
735 [POLICY_ITEM_IGNORE] = "ignore",
737 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);