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-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 i->class = POLICY_ITEM_IGNORE;
283 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
286 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
287 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
291 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
292 log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
298 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
301 u = strchr(name, '_');
306 if (streq(u, "interface"))
307 state = STATE_ALLOW_DENY_INTERFACE;
308 else if (streq(u, "member"))
309 state = STATE_ALLOW_DENY_MEMBER;
310 else if (streq(u, "error"))
311 state = STATE_ALLOW_DENY_ERROR;
312 else if (streq(u, "path"))
313 state = STATE_ALLOW_DENY_PATH;
314 else if (streq(u, "type"))
315 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
316 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
317 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
318 state = STATE_ALLOW_DENY_NAME;
320 if (streq(u, "requested_reply"))
321 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
323 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
324 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
328 state = STATE_ALLOW_DENY_NAME;
330 } else if (t == XML_TAG_CLOSE_EMPTY ||
331 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
333 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
334 log_error("Policy not set at %s:%u.", path, line);
338 if (policy_category == POLICY_CATEGORY_DEFAULT)
339 item_append(i, &p->default_items);
340 else if (policy_category == POLICY_CATEGORY_MANDATORY)
341 item_append(i, &p->mandatory_items);
342 else if (policy_category == POLICY_CATEGORY_USER) {
343 const char *u = policy_user;
345 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
347 r = hashmap_ensure_allocated(&p->user_items, NULL);
352 log_error("User policy without name");
356 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
358 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
363 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
364 item_append(i, &first);
367 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
369 LIST_REMOVE(items, first, i);
374 } else if (policy_category == POLICY_CATEGORY_GROUP) {
375 const char *g = policy_group;
377 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
379 r = hashmap_ensure_allocated(&p->group_items, NULL);
384 log_error("Group policy without name");
388 r = get_group_creds(&g, &i->gid);
390 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
395 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
396 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);
527 case POLICY_ITEM_USER:
528 if (!streq(name, "*")) {
529 const char *u = name;
531 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
533 log_error_errno(r, "Failed to resolve user %s: %m", name);
538 case POLICY_ITEM_GROUP:
539 if (!streq(name, "*")) {
540 const char *g = name;
542 r = get_group_creds(&g, &i->gid);
544 log_error_errno(r, "Failed to resolve group %s: %m", name);
556 state = STATE_ALLOW_DENY;
558 log_error("Unexpected token (14) in %s:%u.", path, line);
564 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
566 if (t == XML_ATTRIBUTE_VALUE)
567 state = STATE_ALLOW_DENY;
569 log_error("Unexpected token (15) in %s:%u.", path, line);
577 if (t == XML_TAG_OPEN)
579 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
582 state = STATE_BUSCONFIG;
598 static const char *verdict_to_string(int v) {
612 struct policy_check_filter {
613 PolicyItemClass class;
618 const char *interface;
623 static int is_permissive(PolicyItem *i) {
627 return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
630 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
636 case POLICY_ITEM_SEND:
637 case POLICY_ITEM_RECV:
639 if (i->name && !streq_ptr(i->name, filter->name))
642 if ((i->message_type != 0) && (i->message_type != filter->message_type))
645 if (i->path && !streq_ptr(i->path, filter->path))
648 if (i->member && !streq_ptr(i->member, filter->member))
651 if (i->interface && !streq_ptr(i->interface, filter->interface))
654 return is_permissive(i);
656 case POLICY_ITEM_OWN:
657 assert(filter->name);
659 if (streq(i->name, "*") || streq(i->name, filter->name))
660 return is_permissive(i);
663 case POLICY_ITEM_OWN_PREFIX:
664 assert(filter->name);
666 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
667 return is_permissive(i);
670 case POLICY_ITEM_USER:
671 if (filter->uid != UID_INVALID)
672 if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
673 return is_permissive(i);
676 case POLICY_ITEM_GROUP:
677 if (filter->gid != GID_INVALID)
678 if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
679 return is_permissive(i);
682 case POLICY_ITEM_IGNORE:
690 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
697 /* Check all policies in a set - a broader one might be followed by a more specific one,
698 * and the order of rules in policy definitions matters */
699 LIST_FOREACH(items, i, items) {
702 if (i->class != filter->class &&
703 !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
706 v = check_policy_item(i, filter);
714 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
722 assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
725 * The policy check is implemented by the following logic:
727 * 1. Check default items
728 * 2. Check group items
729 * 3. Check user items
730 * 4. Check mandatory items
732 * Later rules override earlier rules.
735 verdict = check_policy_items(p->default_items, filter);
737 if (filter->gid != GID_INVALID) {
738 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
740 v = check_policy_items(items, filter);
746 if (filter->uid != UID_INVALID) {
747 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
749 v = check_policy_items(items, filter);
755 v = check_policy_items(p->mandatory_items, filter);
762 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
764 struct policy_check_filter filter = {
765 .class = POLICY_ITEM_OWN,
776 verdict = policy_check(p, &filter);
778 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
779 "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
780 uid, gid, strna(name), strna(verdict_to_string(verdict)));
782 return verdict == ALLOW;
785 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
787 struct policy_check_filter filter = {
795 filter.class = POLICY_ITEM_USER;
796 verdict = policy_check(p, &filter);
798 if (verdict != DENY) {
801 filter.class = POLICY_ITEM_GROUP;
802 v = policy_check(p, &filter);
807 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
808 "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
809 uid, gid, strna(verdict_to_string(verdict)));
811 return verdict == ALLOW;
814 bool policy_check_recv(Policy *p,
820 const char *interface,
821 const char *member) {
823 struct policy_check_filter filter = {
824 .class = POLICY_ITEM_RECV,
827 .message_type = message_type,
829 .interface = interface,
838 verdict = policy_check(p, &filter);
840 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
841 "Recieve permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
842 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
844 return verdict == ALLOW;
847 bool policy_check_send(Policy *p,
853 const char *interface,
854 const char *member) {
856 struct policy_check_filter filter = {
857 .class = POLICY_ITEM_SEND,
860 .message_type = message_type,
862 .interface = interface,
871 verdict = policy_check(p, &filter);
873 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
874 "Send permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
875 uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
877 return verdict == ALLOW;
880 int policy_load(Policy *p, char **files) {
886 STRV_FOREACH(i, files) {
888 r = file_load(p, *i);
890 _cleanup_strv_free_ char **l = NULL;
893 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
895 return log_error_errno(r, "Failed to get configuration file list: %m");
901 /* We ignore all errors but EISDIR, and just proceed. */
907 void policy_free(Policy *p) {
908 PolicyItem *i, *first;
913 while ((i = p->default_items)) {
914 LIST_REMOVE(items, p->default_items, i);
918 while ((i = p->mandatory_items)) {
919 LIST_REMOVE(items, p->mandatory_items, i);
923 while ((first = hashmap_steal_first(p->user_items))) {
925 while ((i = first)) {
926 LIST_REMOVE(items, first, i);
931 while ((first = hashmap_steal_first(p->group_items))) {
933 while ((i = first)) {
934 LIST_REMOVE(items, first, i);
939 hashmap_free(p->user_items);
940 hashmap_free(p->group_items);
942 p->user_items = p->group_items = NULL;
945 static void dump_items(PolicyItem *items, const char *prefix) {
955 LIST_FOREACH(items, i, items) {
957 printf("%sType: %s\n"
959 prefix, policy_item_type_to_string(i->type),
960 prefix, policy_item_class_to_string(i->class));
963 printf("%sInterface: %s\n",
964 prefix, i->interface);
967 printf("%sMember: %s\n",
971 printf("%sError: %s\n",
975 printf("%sPath: %s\n",
979 printf("%sName: %s\n",
982 if (i->message_type != 0)
983 printf("%sMessage Type: %s\n",
984 prefix, bus_message_type_to_string(i->message_type));
987 _cleanup_free_ char *user;
989 user = uid_to_name(i->uid);
991 printf("%sUser: %s (%d)\n",
992 prefix, strna(user), i->uid);
996 _cleanup_free_ char *group;
998 group = gid_to_name(i->gid);
1000 printf("%sGroup: %s (%d)\n",
1001 prefix, strna(group), i->gid);
1003 printf("%s-\n", prefix);
1007 static void dump_hashmap_items(Hashmap *h) {
1012 HASHMAP_FOREACH_KEY(i, k, h, j) {
1013 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1014 dump_items(i, "\t\t");
1018 void policy_dump(Policy *p) {
1020 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1021 dump_items(p->default_items, "\t");
1023 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1024 dump_hashmap_items(p->group_items);
1026 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1027 dump_hashmap_items(p->user_items);
1029 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1030 dump_items(p->mandatory_items, "\t");
1033 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1034 [_POLICY_ITEM_TYPE_UNSET] = "unset",
1035 [POLICY_ITEM_ALLOW] = "allow",
1036 [POLICY_ITEM_DENY] = "deny",
1038 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1040 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1041 [_POLICY_ITEM_CLASS_UNSET] = "unset",
1042 [POLICY_ITEM_SEND] = "send",
1043 [POLICY_ITEM_RECV] = "recv",
1044 [POLICY_ITEM_OWN] = "own",
1045 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1046 [POLICY_ITEM_USER] = "user",
1047 [POLICY_ITEM_GROUP] = "group",
1048 [POLICY_ITEM_IGNORE] = "ignore",
1050 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);