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;
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 the tag is fully empty so far, we consider it a recv */
333 if (i->class == _POLICY_ITEM_CLASS_UNSET)
334 i->class = POLICY_ITEM_RECV;
336 if (policy_category == POLICY_CATEGORY_DEFAULT)
337 item_append(i, &p->default_items);
338 else if (policy_category == POLICY_CATEGORY_MANDATORY)
339 item_append(i, &p->mandatory_items);
340 else if (policy_category == POLICY_CATEGORY_USER) {
341 const char *u = policy_user;
343 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
345 r = hashmap_ensure_allocated(&p->user_items, NULL);
350 log_error("User policy without name");
354 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
356 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
361 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
362 item_append(i, &first);
365 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
367 LIST_REMOVE(items, first, i);
372 } else if (policy_category == POLICY_CATEGORY_GROUP) {
373 const char *g = policy_group;
375 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
377 r = hashmap_ensure_allocated(&p->group_items, NULL);
382 log_error("Group policy without name");
386 r = get_group_creds(&g, &i->gid);
388 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
393 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
394 item_append(i, &first);
397 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
399 LIST_REMOVE(items, first, i);
405 state = STATE_POLICY;
408 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
409 log_error("Unexpected token (8) at %s:%u.", path, line);
415 case STATE_ALLOW_DENY_INTERFACE:
417 if (t == XML_ATTRIBUTE_VALUE) {
420 log_error("Duplicate interface at %s:%u.", path, line);
424 if (!streq(name, "*")) {
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);
445 if (!streq(name, "*")) {
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);
466 if (!streq(name, "*")) {
470 state = STATE_ALLOW_DENY;
472 log_error("Unexpected token (11) in %s:%u.", path, line);
478 case STATE_ALLOW_DENY_PATH:
480 if (t == XML_ATTRIBUTE_VALUE) {
483 log_error("Duplicate path in %s:%u.", path, line);
487 if (!streq(name, "*")) {
491 state = STATE_ALLOW_DENY;
493 log_error("Unexpected token (12) in %s:%u.", path, line);
499 case STATE_ALLOW_DENY_MESSAGE_TYPE:
501 if (t == XML_ATTRIBUTE_VALUE) {
504 if (i->message_type != 0) {
505 log_error("Duplicate message type in %s:%u.", path, line);
509 if (!streq(name, "*")) {
510 r = bus_message_type_from_string(name, &i->message_type);
512 log_error("Invalid message type in %s:%u.", path, line);
517 state = STATE_ALLOW_DENY;
519 log_error("Unexpected token (13) in %s:%u.", path, line);
525 case STATE_ALLOW_DENY_NAME:
527 if (t == XML_ATTRIBUTE_VALUE) {
530 log_error("Duplicate name in %s:%u.", path, line);
535 case POLICY_ITEM_USER:
536 if (!streq(name, "*")) {
537 const char *u = name;
539 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
541 log_error_errno(r, "Failed to resolve user %s: %m", name);
546 case POLICY_ITEM_GROUP:
547 if (!streq(name, "*")) {
548 const char *g = name;
550 r = get_group_creds(&g, &i->gid);
552 log_error_errno(r, "Failed to resolve group %s: %m", name);
558 case POLICY_ITEM_SEND:
559 case POLICY_ITEM_RECV:
561 if (streq(name, "*")) {
575 state = STATE_ALLOW_DENY;
577 log_error("Unexpected token (14) in %s:%u.", path, line);
583 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
585 if (t == XML_ATTRIBUTE_VALUE)
586 state = STATE_ALLOW_DENY;
588 log_error("Unexpected token (15) in %s:%u.", path, line);
596 if (t == XML_TAG_OPEN)
598 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
601 state = STATE_BUSCONFIG;
617 static const char *verdict_to_string(int v) {
631 struct policy_check_filter {
632 PolicyItemClass class;
637 const char *interface;
642 static int is_permissive(PolicyItem *i) {
646 return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
649 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
655 case POLICY_ITEM_SEND:
656 case POLICY_ITEM_RECV:
658 if (i->name && !streq_ptr(i->name, filter->name))
661 if ((i->message_type != 0) && (i->message_type != filter->message_type))
664 if (i->path && !streq_ptr(i->path, filter->path))
667 if (i->member && !streq_ptr(i->member, filter->member))
670 if (i->interface && !streq_ptr(i->interface, filter->interface))
673 return is_permissive(i);
675 case POLICY_ITEM_OWN:
676 assert(filter->name);
678 if (streq(i->name, "*") || streq(i->name, filter->name))
679 return is_permissive(i);
682 case POLICY_ITEM_OWN_PREFIX:
683 assert(filter->name);
685 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
686 return is_permissive(i);
689 case POLICY_ITEM_USER:
690 if (filter->uid != UID_INVALID)
691 if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
692 return is_permissive(i);
695 case POLICY_ITEM_GROUP:
696 if (filter->gid != GID_INVALID)
697 if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
698 return is_permissive(i);
701 case POLICY_ITEM_IGNORE:
709 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
716 /* Check all policies in a set - a broader one might be followed by a more specific one,
717 * and the order of rules in policy definitions matters */
718 LIST_FOREACH(items, i, items) {
721 if (i->class != filter->class &&
722 !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
725 v = check_policy_item(i, filter);
733 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
741 assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
744 * The policy check is implemented by the following logic:
746 * 1. Check default items
747 * 2. Check group items
748 * 3. Check user items
749 * 4. Check mandatory items
751 * Later rules override earlier rules.
754 verdict = check_policy_items(p->default_items, filter);
756 if (filter->gid != GID_INVALID) {
757 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
759 v = check_policy_items(items, filter);
765 if (filter->uid != UID_INVALID) {
766 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
768 v = check_policy_items(items, filter);
774 v = check_policy_items(p->mandatory_items, filter);
781 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
783 struct policy_check_filter filter = {
784 .class = POLICY_ITEM_OWN,
795 verdict = policy_check(p, &filter);
797 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
798 "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
799 uid, gid, strna(name), strna(verdict_to_string(verdict)));
801 return verdict == ALLOW;
804 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
806 struct policy_check_filter filter = {
814 filter.class = POLICY_ITEM_USER;
815 verdict = policy_check(p, &filter);
817 if (verdict != DENY) {
820 filter.class = POLICY_ITEM_GROUP;
821 v = policy_check(p, &filter);
826 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
827 "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
828 uid, gid, strna(verdict_to_string(verdict)));
830 return verdict == ALLOW;
833 bool policy_check_recv(Policy *p,
839 const char *interface,
840 const char *member) {
842 struct policy_check_filter filter = {
843 .class = POLICY_ITEM_RECV,
846 .message_type = message_type,
848 .interface = interface,
857 verdict = policy_check(p, &filter);
859 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
860 "Receive permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
861 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
863 return verdict == ALLOW;
866 bool policy_check_send(Policy *p,
872 const char *interface,
873 const char *member) {
875 struct policy_check_filter filter = {
876 .class = POLICY_ITEM_SEND,
879 .message_type = message_type,
881 .interface = interface,
890 verdict = policy_check(p, &filter);
892 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
893 "Send permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
894 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
896 return verdict == ALLOW;
899 int policy_load(Policy *p, char **files) {
905 STRV_FOREACH(i, files) {
907 r = file_load(p, *i);
909 _cleanup_strv_free_ char **l = NULL;
912 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
914 return log_error_errno(r, "Failed to get configuration file list: %m");
920 /* We ignore all errors but EISDIR, and just proceed. */
926 void policy_free(Policy *p) {
927 PolicyItem *i, *first;
932 while ((i = p->default_items)) {
933 LIST_REMOVE(items, p->default_items, i);
937 while ((i = p->mandatory_items)) {
938 LIST_REMOVE(items, p->mandatory_items, i);
942 while ((first = hashmap_steal_first(p->user_items))) {
944 while ((i = first)) {
945 LIST_REMOVE(items, first, i);
950 while ((first = hashmap_steal_first(p->group_items))) {
952 while ((i = first)) {
953 LIST_REMOVE(items, first, i);
958 hashmap_free(p->user_items);
959 hashmap_free(p->group_items);
961 p->user_items = p->group_items = NULL;
964 static void dump_items(PolicyItem *items, const char *prefix) {
974 LIST_FOREACH(items, i, items) {
976 printf("%sType: %s\n"
978 prefix, policy_item_type_to_string(i->type),
979 prefix, policy_item_class_to_string(i->class));
982 printf("%sInterface: %s\n",
983 prefix, i->interface);
986 printf("%sMember: %s\n",
990 printf("%sError: %s\n",
994 printf("%sPath: %s\n",
998 printf("%sName: %s\n",
1001 if (i->message_type != 0)
1002 printf("%sMessage Type: %s\n",
1003 prefix, bus_message_type_to_string(i->message_type));
1006 _cleanup_free_ char *user;
1008 user = uid_to_name(i->uid);
1010 printf("%sUser: %s (%d)\n",
1011 prefix, strna(user), i->uid);
1015 _cleanup_free_ char *group;
1017 group = gid_to_name(i->gid);
1019 printf("%sGroup: %s (%d)\n",
1020 prefix, strna(group), i->gid);
1022 printf("%s-\n", prefix);
1026 static void dump_hashmap_items(Hashmap *h) {
1031 HASHMAP_FOREACH_KEY(i, k, h, j) {
1032 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1033 dump_items(i, "\t\t");
1037 void policy_dump(Policy *p) {
1039 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1040 dump_items(p->default_items, "\t");
1042 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1043 dump_hashmap_items(p->group_items);
1045 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1046 dump_hashmap_items(p->user_items);
1048 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1049 dump_items(p->mandatory_items, "\t");
1054 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1055 [_POLICY_ITEM_TYPE_UNSET] = "unset",
1056 [POLICY_ITEM_ALLOW] = "allow",
1057 [POLICY_ITEM_DENY] = "deny",
1059 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1061 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1062 [_POLICY_ITEM_CLASS_UNSET] = "unset",
1063 [POLICY_ITEM_SEND] = "send",
1064 [POLICY_ITEM_RECV] = "recv",
1065 [POLICY_ITEM_OWN] = "own",
1066 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1067 [POLICY_ITEM_USER] = "user",
1068 [POLICY_ITEM_GROUP] = "group",
1069 [POLICY_ITEM_IGNORE] = "ignore",
1071 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);