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-message.h"
28 #include "bus-xml-policy.h"
30 static void policy_item_free(PolicyItem *i) {
41 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
43 static void item_append(PolicyItem *i, PolicyItem **list) {
47 LIST_FIND_TAIL(items, *list, tail);
48 LIST_INSERT_AFTER(items, *list, tail, i);
51 static int file_load(Policy *p, const char *path) {
53 _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
54 _cleanup_(policy_item_freep) PolicyItem *i = NULL;
55 void *xml_state = NULL;
67 STATE_POLICY_OTHER_ATTRIBUTE,
69 STATE_ALLOW_DENY_INTERFACE,
70 STATE_ALLOW_DENY_MEMBER,
71 STATE_ALLOW_DENY_ERROR,
72 STATE_ALLOW_DENY_PATH,
73 STATE_ALLOW_DENY_MESSAGE_TYPE,
74 STATE_ALLOW_DENY_NAME,
75 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
77 } state = STATE_OUTSIDE;
81 POLICY_CATEGORY_DEFAULT,
82 POLICY_CATEGORY_MANDATORY,
85 } policy_category = POLICY_CATEGORY_NONE;
91 r = read_full_file(path, &c, NULL);
98 return log_error_errno(r, "Failed to load %s: %m", path);
103 _cleanup_free_ char *name = NULL;
106 t = xml_tokenize(&q, &name, &xml_state, &line);
108 return log_error_errno(t, "XML parse failure in %s: %m", path);
114 if (t == XML_TAG_OPEN) {
115 if (streq(name, "busconfig"))
116 state = STATE_BUSCONFIG;
118 log_error("Unexpected tag %s at %s:%u.", name, path, line);
122 } else if (t == XML_END)
124 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
125 log_error("Unexpected token (1) at %s:%u.", path, line);
131 case STATE_BUSCONFIG:
133 if (t == XML_TAG_OPEN) {
134 if (streq(name, "policy")) {
135 state = STATE_POLICY;
136 policy_category = POLICY_CATEGORY_NONE;
139 policy_user = policy_group = NULL;
144 } else if (t == XML_TAG_CLOSE_EMPTY ||
145 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
146 state = STATE_OUTSIDE;
147 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
148 log_error("Unexpected token (2) at %s:%u.", path, line);
156 if (t == XML_ATTRIBUTE_NAME) {
157 if (streq(name, "context"))
158 state = STATE_POLICY_CONTEXT;
159 else if (streq(name, "user"))
160 state = STATE_POLICY_USER;
161 else if (streq(name, "group"))
162 state = STATE_POLICY_GROUP;
164 if (streq(name, "at_console"))
165 log_debug("Attribute %s of <policy> tag unsupported at %s:%u, ignoring.", name, path, line);
167 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
168 state = STATE_POLICY_OTHER_ATTRIBUTE;
170 } else if (t == XML_TAG_CLOSE_EMPTY ||
171 (t == XML_TAG_CLOSE && streq(name, "policy")))
172 state = STATE_BUSCONFIG;
173 else if (t == XML_TAG_OPEN) {
176 if (streq(name, "allow"))
177 it = POLICY_ITEM_ALLOW;
178 else if (streq(name, "deny"))
179 it = POLICY_ITEM_DENY;
181 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
186 i = new0(PolicyItem, 1);
191 state = STATE_ALLOW_DENY;
193 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
194 log_error("Unexpected token (3) at %s:%u.", path, line);
200 case STATE_POLICY_CONTEXT:
202 if (t == XML_ATTRIBUTE_VALUE) {
203 if (streq(name, "default")) {
204 policy_category = POLICY_CATEGORY_DEFAULT;
205 state = STATE_POLICY;
206 } else if (streq(name, "mandatory")) {
207 policy_category = POLICY_CATEGORY_MANDATORY;
208 state = STATE_POLICY;
210 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
214 log_error("Unexpected token (4) at %s:%u.", path, line);
220 case STATE_POLICY_USER:
222 if (t == XML_ATTRIBUTE_VALUE) {
226 policy_category = POLICY_CATEGORY_USER;
227 state = STATE_POLICY;
229 log_error("Unexpected token (5) in %s:%u.", path, line);
235 case STATE_POLICY_GROUP:
237 if (t == XML_ATTRIBUTE_VALUE) {
241 policy_category = POLICY_CATEGORY_GROUP;
242 state = STATE_POLICY;
244 log_error("Unexpected token (6) at %s:%u.", path, line);
250 case STATE_POLICY_OTHER_ATTRIBUTE:
252 if (t == XML_ATTRIBUTE_VALUE)
253 state = STATE_POLICY;
255 log_error("Unexpected token (7) in %s:%u.", path, line);
261 case STATE_ALLOW_DENY:
265 if (t == XML_ATTRIBUTE_NAME) {
268 if (startswith(name, "send_"))
269 ic = POLICY_ITEM_SEND;
270 else if (startswith(name, "receive_"))
271 ic = POLICY_ITEM_RECV;
272 else if (streq(name, "own"))
273 ic = POLICY_ITEM_OWN;
274 else if (streq(name, "own_prefix"))
275 ic = POLICY_ITEM_OWN_PREFIX;
276 else if (streq(name, "user"))
277 ic = POLICY_ITEM_USER;
278 else if (streq(name, "group"))
279 ic = POLICY_ITEM_GROUP;
280 else if (streq(name, "eavesdrop")) {
281 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
282 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
283 ic = POLICY_ITEM_RECV; /* eavesdrop is a type of receive attribute match! */
285 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
286 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
290 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
291 log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
297 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
300 u = strchr(name, '_');
305 if (streq(u, "interface"))
306 state = STATE_ALLOW_DENY_INTERFACE;
307 else if (streq(u, "member"))
308 state = STATE_ALLOW_DENY_MEMBER;
309 else if (streq(u, "error"))
310 state = STATE_ALLOW_DENY_ERROR;
311 else if (streq(u, "path"))
312 state = STATE_ALLOW_DENY_PATH;
313 else if (streq(u, "type"))
314 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
315 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
316 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
317 state = STATE_ALLOW_DENY_NAME;
319 if (streq(u, "requested_reply"))
320 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
322 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
323 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
327 state = STATE_ALLOW_DENY_NAME;
329 } else if (t == XML_TAG_CLOSE_EMPTY ||
330 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
332 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
333 log_error("Policy not set at %s:%u.", path, line);
337 if (policy_category == POLICY_CATEGORY_DEFAULT)
338 item_append(i, &p->default_items);
339 else if (policy_category == POLICY_CATEGORY_MANDATORY)
340 item_append(i, &p->mandatory_items);
341 else if (policy_category == POLICY_CATEGORY_USER) {
342 const char *u = policy_user;
344 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
346 r = hashmap_ensure_allocated(&p->user_items, NULL);
351 log_error("User policy without name");
355 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
357 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
362 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
363 item_append(i, &first);
366 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
368 LIST_REMOVE(items, first, i);
373 } else if (policy_category == POLICY_CATEGORY_GROUP) {
374 const char *g = policy_group;
376 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
378 r = hashmap_ensure_allocated(&p->group_items, NULL);
383 log_error("Group policy without name");
387 r = get_group_creds(&g, &i->gid);
389 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
394 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
395 item_append(i, &first);
398 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
400 LIST_REMOVE(items, first, i);
406 state = STATE_POLICY;
409 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
410 log_error("Unexpected token (8) at %s:%u.", path, line);
416 case STATE_ALLOW_DENY_INTERFACE:
418 if (t == XML_ATTRIBUTE_VALUE) {
421 log_error("Duplicate interface at %s:%u.", path, line);
427 state = STATE_ALLOW_DENY;
429 log_error("Unexpected token (9) at %s:%u.", path, line);
435 case STATE_ALLOW_DENY_MEMBER:
437 if (t == XML_ATTRIBUTE_VALUE) {
440 log_error("Duplicate member in %s:%u.", path, line);
446 state = STATE_ALLOW_DENY;
448 log_error("Unexpected token (10) in %s:%u.", path, line);
454 case STATE_ALLOW_DENY_ERROR:
456 if (t == XML_ATTRIBUTE_VALUE) {
459 log_error("Duplicate error in %s:%u.", path, line);
465 state = STATE_ALLOW_DENY;
467 log_error("Unexpected token (11) in %s:%u.", path, line);
473 case STATE_ALLOW_DENY_PATH:
475 if (t == XML_ATTRIBUTE_VALUE) {
478 log_error("Duplicate path in %s:%u.", path, line);
484 state = STATE_ALLOW_DENY;
486 log_error("Unexpected token (12) in %s:%u.", path, line);
492 case STATE_ALLOW_DENY_MESSAGE_TYPE:
494 if (t == XML_ATTRIBUTE_VALUE) {
497 if (i->message_type != 0) {
498 log_error("Duplicate message type in %s:%u.", path, line);
502 r = bus_message_type_from_string(name, &i->message_type);
504 log_error("Invalid message type in %s:%u.", path, line);
508 state = STATE_ALLOW_DENY;
510 log_error("Unexpected token (13) in %s:%u.", path, line);
516 case STATE_ALLOW_DENY_NAME:
518 if (t == XML_ATTRIBUTE_VALUE) {
521 log_error("Duplicate name in %s:%u.", path, line);
526 case POLICY_ITEM_USER:
527 if (!streq(name, "*")) {
528 const char *u = name;
530 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
532 log_error_errno(r, "Failed to resolve user %s: %m", name);
537 case POLICY_ITEM_GROUP:
538 if (!streq(name, "*")) {
539 const char *g = name;
541 r = get_group_creds(&g, &i->gid);
543 log_error_errno(r, "Failed to resolve group %s: %m", name);
555 state = STATE_ALLOW_DENY;
557 log_error("Unexpected token (14) in %s:%u.", path, line);
563 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
565 if (t == XML_ATTRIBUTE_VALUE)
566 state = STATE_ALLOW_DENY;
568 log_error("Unexpected token (15) in %s:%u.", path, line);
576 if (t == XML_TAG_OPEN)
578 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
581 state = STATE_BUSCONFIG;
597 static const char *verdict_to_string(int v) {
611 struct policy_check_filter {
612 PolicyItemClass class;
617 const char *interface;
622 static int is_permissive(PolicyItem *i) {
626 return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
629 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
635 case POLICY_ITEM_SEND:
636 case POLICY_ITEM_RECV:
638 if (i->name && !streq_ptr(i->name, filter->name))
641 if ((i->message_type != 0) && (i->message_type != filter->message_type))
644 if (i->path && !streq_ptr(i->path, filter->path))
647 if (i->member && !streq_ptr(i->member, filter->member))
650 if (i->interface && !streq_ptr(i->interface, filter->interface))
653 return is_permissive(i);
655 case POLICY_ITEM_OWN:
656 assert(filter->name);
658 if (streq(i->name, "*") || streq(i->name, filter->name))
659 return is_permissive(i);
662 case POLICY_ITEM_OWN_PREFIX:
663 assert(filter->name);
665 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
666 return is_permissive(i);
669 case POLICY_ITEM_USER:
670 if (filter->uid != UID_INVALID)
671 if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
672 return is_permissive(i);
675 case POLICY_ITEM_GROUP:
676 if (filter->gid != GID_INVALID)
677 if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
678 return is_permissive(i);
681 case POLICY_ITEM_IGNORE:
689 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
696 /* Check all policies in a set - a broader one might be followed by a more specific one,
697 * and the order of rules in policy definitions matters */
698 LIST_FOREACH(items, i, items) {
701 if (i->class != filter->class &&
702 !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
705 v = check_policy_item(i, filter);
713 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
721 assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
724 * The policy check is implemented by the following logic:
726 * 1. Check default items
727 * 2. Check group items
728 * 3. Check user items
729 * 4. Check mandatory items
731 * Later rules override earlier rules.
734 verdict = check_policy_items(p->default_items, filter);
736 if (filter->gid != GID_INVALID) {
737 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
739 v = check_policy_items(items, filter);
745 if (filter->uid != UID_INVALID) {
746 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
748 v = check_policy_items(items, filter);
754 v = check_policy_items(p->mandatory_items, filter);
761 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
763 struct policy_check_filter filter = {
764 .class = POLICY_ITEM_OWN,
775 verdict = policy_check(p, &filter);
777 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
778 "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
779 uid, gid, strna(name), strna(verdict_to_string(verdict)));
781 return verdict == ALLOW;
784 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
786 struct policy_check_filter filter = {
794 filter.class = POLICY_ITEM_USER;
795 verdict = policy_check(p, &filter);
797 if (verdict != DENY) {
800 filter.class = POLICY_ITEM_GROUP;
801 v = policy_check(p, &filter);
806 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
807 "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
808 uid, gid, strna(verdict_to_string(verdict)));
810 return verdict == ALLOW;
813 bool policy_check_recv(Policy *p,
819 const char *interface,
820 const char *member) {
822 struct policy_check_filter filter = {
823 .class = POLICY_ITEM_RECV,
826 .message_type = message_type,
828 .interface = interface,
837 verdict = policy_check(p, &filter);
839 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
840 "Receive permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
841 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
843 return verdict == ALLOW;
846 bool policy_check_send(Policy *p,
852 const char *interface,
853 const char *member) {
855 struct policy_check_filter filter = {
856 .class = POLICY_ITEM_SEND,
859 .message_type = message_type,
861 .interface = interface,
870 verdict = policy_check(p, &filter);
872 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
873 "Send permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
874 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
876 return verdict == ALLOW;
879 int policy_load(Policy *p, char **files) {
885 STRV_FOREACH(i, files) {
887 r = file_load(p, *i);
889 _cleanup_strv_free_ char **l = NULL;
892 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
894 return log_error_errno(r, "Failed to get configuration file list: %m");
900 /* We ignore all errors but EISDIR, and just proceed. */
906 void policy_free(Policy *p) {
907 PolicyItem *i, *first;
912 while ((i = p->default_items)) {
913 LIST_REMOVE(items, p->default_items, i);
917 while ((i = p->mandatory_items)) {
918 LIST_REMOVE(items, p->mandatory_items, i);
922 while ((first = hashmap_steal_first(p->user_items))) {
924 while ((i = first)) {
925 LIST_REMOVE(items, first, i);
930 while ((first = hashmap_steal_first(p->group_items))) {
932 while ((i = first)) {
933 LIST_REMOVE(items, first, i);
938 hashmap_free(p->user_items);
939 hashmap_free(p->group_items);
941 p->user_items = p->group_items = NULL;
944 static void dump_items(PolicyItem *items, const char *prefix) {
954 LIST_FOREACH(items, i, items) {
956 printf("%sType: %s\n"
958 prefix, policy_item_type_to_string(i->type),
959 prefix, policy_item_class_to_string(i->class));
962 printf("%sInterface: %s\n",
963 prefix, i->interface);
966 printf("%sMember: %s\n",
970 printf("%sError: %s\n",
974 printf("%sPath: %s\n",
978 printf("%sName: %s\n",
981 if (i->message_type != 0)
982 printf("%sMessage Type: %s\n",
983 prefix, bus_message_type_to_string(i->message_type));
986 _cleanup_free_ char *user;
988 user = uid_to_name(i->uid);
990 printf("%sUser: %s (%d)\n",
991 prefix, strna(user), i->uid);
995 _cleanup_free_ char *group;
997 group = gid_to_name(i->gid);
999 printf("%sGroup: %s (%d)\n",
1000 prefix, strna(group), i->gid);
1002 printf("%s-\n", prefix);
1006 static void dump_hashmap_items(Hashmap *h) {
1011 HASHMAP_FOREACH_KEY(i, k, h, j) {
1012 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1013 dump_items(i, "\t\t");
1017 void policy_dump(Policy *p) {
1019 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1020 dump_items(p->default_items, "\t");
1022 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1023 dump_hashmap_items(p->group_items);
1025 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1026 dump_hashmap_items(p->user_items);
1028 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1029 dump_items(p->mandatory_items, "\t");
1032 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1033 [_POLICY_ITEM_TYPE_UNSET] = "unset",
1034 [POLICY_ITEM_ALLOW] = "allow",
1035 [POLICY_ITEM_DENY] = "deny",
1037 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1039 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1040 [_POLICY_ITEM_CLASS_UNSET] = "unset",
1041 [POLICY_ITEM_SEND] = "send",
1042 [POLICY_ITEM_RECV] = "recv",
1043 [POLICY_ITEM_OWN] = "own",
1044 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1045 [POLICY_ITEM_USER] = "user",
1046 [POLICY_ITEM_GROUP] = "group",
1047 [POLICY_ITEM_IGNORE] = "ignore",
1049 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);