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);
529 case POLICY_ITEM_USER:
530 if (!streq(name, "*")) {
531 const char *u = name;
533 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
535 log_error("Failed to resolve user %s: %s", name, strerror(-r));
540 case POLICY_ITEM_GROUP:
541 if (!streq(name, "*")) {
542 const char *g = name;
544 r = get_group_creds(&g, &i->gid);
546 log_error("Failed to resolve group %s: %s", name, strerror(-r));
558 state = STATE_ALLOW_DENY;
560 log_error("Unexpected token (14) in %s:%u.", path, line);
566 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
568 if (t == XML_ATTRIBUTE_VALUE)
569 state = STATE_ALLOW_DENY;
571 log_error("Unexpected token (15) in %s:%u.", path, line);
579 if (t == XML_TAG_OPEN)
581 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
584 state = STATE_BUSCONFIG;
594 int policy_load(Policy *p, char **files) {
600 STRV_FOREACH(i, files) {
602 r = file_load(p, *i);
604 _cleanup_strv_free_ char **l = NULL;
607 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
609 log_error("Failed to get configuration file list: %s", strerror(-r));
617 /* We ignore all errors but EISDIR, and just proceed. */
623 void policy_free(Policy *p) {
624 PolicyItem *i, *first;
629 while ((i = p->default_items)) {
630 LIST_REMOVE(items, p->default_items, i);
634 while ((i = p->mandatory_items)) {
635 LIST_REMOVE(items, p->mandatory_items, i);
639 while ((first = hashmap_steal_first(p->user_items))) {
641 while ((i = first)) {
642 LIST_REMOVE(items, first, i);
647 while ((first = hashmap_steal_first(p->group_items))) {
649 while ((i = first)) {
650 LIST_REMOVE(items, first, i);
655 hashmap_free(p->user_items);
656 hashmap_free(p->group_items);
658 p->user_items = p->group_items = NULL;
661 static void dump_items(PolicyItem *items, const char *prefix) {
671 LIST_FOREACH(items, i, items) {
673 printf("%sType: %s\n"
675 prefix, policy_item_type_to_string(i->type),
676 prefix, policy_item_class_to_string(i->class));
679 printf("%sInterface: %s\n",
680 prefix, i->interface);
683 printf("%sMember: %s\n",
687 printf("%sError: %s\n",
691 printf("%sPath: %s\n",
695 printf("%sName: %s\n",
698 if (i->message_type != 0)
699 printf("%sMessage Type: %s\n",
700 prefix, bus_message_type_to_string(i->message_type));
703 _cleanup_free_ char *user;
705 user = uid_to_name(i->uid);
707 printf("%sUser: %s\n",
708 prefix, strna(user));
712 _cleanup_free_ char *group;
714 group = gid_to_name(i->gid);
716 printf("%sGroup: %s\n",
717 prefix, strna(group));
722 static void dump_hashmap_items(Hashmap *h) {
727 HASHMAP_FOREACH_KEY(i, k, h, j) {
728 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
729 dump_items(i, "\t\t");
733 void policy_dump(Policy *p) {
735 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
736 dump_items(p->default_items, "\t");
738 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
739 dump_hashmap_items(p->group_items);
741 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
742 dump_hashmap_items(p->user_items);
744 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
745 dump_items(p->mandatory_items, "\t");
748 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
749 [_POLICY_ITEM_TYPE_UNSET] = "unset",
750 [POLICY_ITEM_ALLOW] = "allow",
751 [POLICY_ITEM_DENY] = "deny",
753 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
755 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
756 [_POLICY_ITEM_CLASS_UNSET] = "unset",
757 [POLICY_ITEM_SEND] = "send",
758 [POLICY_ITEM_RECV] = "recv",
759 [POLICY_ITEM_OWN] = "own",
760 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
761 [POLICY_ITEM_USER] = "user",
762 [POLICY_ITEM_GROUP] = "group",
763 [POLICY_ITEM_IGNORE] = "ignore",
765 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);