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/>.
26 #include "conf-files.h"
27 #include "bus-internal.h"
28 #include "bus-xml-policy.h"
31 static void policy_item_free(PolicyItem *i) {
42 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
44 static void item_append(PolicyItem *i, PolicyItem **list) {
48 LIST_FIND_TAIL(items, *list, tail);
49 LIST_INSERT_AFTER(items, *list, tail, i);
52 static int file_load(Policy *p, const char *path) {
54 _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
55 _cleanup_(policy_item_freep) PolicyItem *i = NULL;
56 void *xml_state = NULL;
69 STATE_POLICY_OTHER_ATTRIBUTE,
71 STATE_ALLOW_DENY_INTERFACE,
72 STATE_ALLOW_DENY_MEMBER,
73 STATE_ALLOW_DENY_ERROR,
74 STATE_ALLOW_DENY_PATH,
75 STATE_ALLOW_DENY_MESSAGE_TYPE,
76 STATE_ALLOW_DENY_NAME,
77 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
79 } state = STATE_OUTSIDE;
83 POLICY_CATEGORY_DEFAULT,
84 POLICY_CATEGORY_MANDATORY,
85 POLICY_CATEGORY_ON_CONSOLE,
86 POLICY_CATEGORY_NO_CONSOLE,
89 } policy_category = POLICY_CATEGORY_NONE;
95 r = read_full_file(path, &c, NULL);
102 return log_error_errno(r, "Failed to load %s: %m", path);
107 _cleanup_free_ char *name = NULL;
110 t = xml_tokenize(&q, &name, &xml_state, &line);
112 return log_error_errno(t, "XML parse failure in %s: %m", path);
118 if (t == XML_TAG_OPEN) {
119 if (streq(name, "busconfig"))
120 state = STATE_BUSCONFIG;
122 log_error("Unexpected tag %s at %s:%u.", name, path, line);
126 } else if (t == XML_END)
128 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
129 log_error("Unexpected token (1) at %s:%u.", path, line);
135 case STATE_BUSCONFIG:
137 if (t == XML_TAG_OPEN) {
138 if (streq(name, "policy")) {
139 state = STATE_POLICY;
140 policy_category = POLICY_CATEGORY_NONE;
143 policy_user = policy_group = NULL;
148 } else if (t == XML_TAG_CLOSE_EMPTY ||
149 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
150 state = STATE_OUTSIDE;
151 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
152 log_error("Unexpected token (2) at %s:%u.", path, line);
160 if (t == XML_ATTRIBUTE_NAME) {
161 if (streq(name, "context"))
162 state = STATE_POLICY_CONTEXT;
163 else if (streq(name, "at_console"))
164 state = STATE_POLICY_CONSOLE;
165 else if (streq(name, "user"))
166 state = STATE_POLICY_USER;
167 else if (streq(name, "group"))
168 state = STATE_POLICY_GROUP;
170 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
171 state = STATE_POLICY_OTHER_ATTRIBUTE;
173 } else if (t == XML_TAG_CLOSE_EMPTY ||
174 (t == XML_TAG_CLOSE && streq(name, "policy")))
175 state = STATE_BUSCONFIG;
176 else if (t == XML_TAG_OPEN) {
179 if (streq(name, "allow"))
180 it = POLICY_ITEM_ALLOW;
181 else if (streq(name, "deny"))
182 it = POLICY_ITEM_DENY;
184 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
189 i = new0(PolicyItem, 1);
194 state = STATE_ALLOW_DENY;
196 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
197 log_error("Unexpected token (3) at %s:%u.", path, line);
203 case STATE_POLICY_CONTEXT:
205 if (t == XML_ATTRIBUTE_VALUE) {
206 if (streq(name, "default")) {
207 policy_category = POLICY_CATEGORY_DEFAULT;
208 state = STATE_POLICY;
209 } else if (streq(name, "mandatory")) {
210 policy_category = POLICY_CATEGORY_MANDATORY;
211 state = STATE_POLICY;
213 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
217 log_error("Unexpected token (4) at %s:%u.", path, line);
223 case STATE_POLICY_CONSOLE:
225 if (t == XML_ATTRIBUTE_VALUE) {
226 if (streq(name, "true")) {
227 policy_category = POLICY_CATEGORY_ON_CONSOLE;
228 state = STATE_POLICY;
229 } else if (streq(name, "false")) {
230 policy_category = POLICY_CATEGORY_NO_CONSOLE;
231 state = STATE_POLICY;
233 log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
237 log_error("Unexpected token (4.1) at %s:%u.", path, line);
243 case STATE_POLICY_USER:
245 if (t == XML_ATTRIBUTE_VALUE) {
249 policy_category = POLICY_CATEGORY_USER;
250 state = STATE_POLICY;
252 log_error("Unexpected token (5) in %s:%u.", path, line);
258 case STATE_POLICY_GROUP:
260 if (t == XML_ATTRIBUTE_VALUE) {
264 policy_category = POLICY_CATEGORY_GROUP;
265 state = STATE_POLICY;
267 log_error("Unexpected token (6) at %s:%u.", path, line);
273 case STATE_POLICY_OTHER_ATTRIBUTE:
275 if (t == XML_ATTRIBUTE_VALUE)
276 state = STATE_POLICY;
278 log_error("Unexpected token (7) in %s:%u.", path, line);
284 case STATE_ALLOW_DENY:
288 if (t == XML_ATTRIBUTE_NAME) {
291 if (startswith(name, "send_"))
292 ic = POLICY_ITEM_SEND;
293 else if (startswith(name, "receive_"))
294 ic = POLICY_ITEM_RECV;
295 else if (streq(name, "own"))
296 ic = POLICY_ITEM_OWN;
297 else if (streq(name, "own_prefix"))
298 ic = POLICY_ITEM_OWN_PREFIX;
299 else if (streq(name, "user"))
300 ic = POLICY_ITEM_USER;
301 else if (streq(name, "group"))
302 ic = POLICY_ITEM_GROUP;
303 else if (streq(name, "eavesdrop")) {
304 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
305 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
308 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
309 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
313 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
314 log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
320 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
323 u = strchr(name, '_');
328 if (streq(u, "interface"))
329 state = STATE_ALLOW_DENY_INTERFACE;
330 else if (streq(u, "member"))
331 state = STATE_ALLOW_DENY_MEMBER;
332 else if (streq(u, "error"))
333 state = STATE_ALLOW_DENY_ERROR;
334 else if (streq(u, "path"))
335 state = STATE_ALLOW_DENY_PATH;
336 else if (streq(u, "type"))
337 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
338 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
339 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
340 state = STATE_ALLOW_DENY_NAME;
342 if (streq(u, "requested_reply"))
343 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
345 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
346 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
350 state = STATE_ALLOW_DENY_NAME;
352 } else if (t == XML_TAG_CLOSE_EMPTY ||
353 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
355 /* If the tag is fully empty so far, we consider it a recv */
356 if (i->class == _POLICY_ITEM_CLASS_UNSET)
357 i->class = POLICY_ITEM_RECV;
359 if (policy_category == POLICY_CATEGORY_DEFAULT)
360 item_append(i, &p->default_items);
361 else if (policy_category == POLICY_CATEGORY_MANDATORY)
362 item_append(i, &p->mandatory_items);
363 else if (policy_category == POLICY_CATEGORY_ON_CONSOLE)
364 item_append(i, &p->on_console_items);
365 else if (policy_category == POLICY_CATEGORY_NO_CONSOLE)
366 item_append(i, &p->no_console_items);
367 else if (policy_category == POLICY_CATEGORY_USER) {
368 const char *u = policy_user;
370 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
372 r = hashmap_ensure_allocated(&p->user_items, NULL);
377 log_error("User policy without name");
381 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
383 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
388 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
389 item_append(i, &first);
392 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
394 LIST_REMOVE(items, first, i);
399 } else if (policy_category == POLICY_CATEGORY_GROUP) {
400 const char *g = policy_group;
402 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
404 r = hashmap_ensure_allocated(&p->group_items, NULL);
409 log_error("Group policy without name");
413 r = get_group_creds(&g, &i->gid);
415 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
420 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
421 item_append(i, &first);
424 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
426 LIST_REMOVE(items, first, i);
432 state = STATE_POLICY;
435 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
436 log_error("Unexpected token (8) at %s:%u.", path, line);
442 case STATE_ALLOW_DENY_INTERFACE:
444 if (t == XML_ATTRIBUTE_VALUE) {
447 log_error("Duplicate interface at %s:%u.", path, line);
451 if (!streq(name, "*")) {
455 state = STATE_ALLOW_DENY;
457 log_error("Unexpected token (9) at %s:%u.", path, line);
463 case STATE_ALLOW_DENY_MEMBER:
465 if (t == XML_ATTRIBUTE_VALUE) {
468 log_error("Duplicate member in %s:%u.", path, line);
472 if (!streq(name, "*")) {
476 state = STATE_ALLOW_DENY;
478 log_error("Unexpected token (10) in %s:%u.", path, line);
484 case STATE_ALLOW_DENY_ERROR:
486 if (t == XML_ATTRIBUTE_VALUE) {
489 log_error("Duplicate error in %s:%u.", path, line);
493 if (!streq(name, "*")) {
497 state = STATE_ALLOW_DENY;
499 log_error("Unexpected token (11) in %s:%u.", path, line);
505 case STATE_ALLOW_DENY_PATH:
507 if (t == XML_ATTRIBUTE_VALUE) {
510 log_error("Duplicate path in %s:%u.", path, line);
514 if (!streq(name, "*")) {
518 state = STATE_ALLOW_DENY;
520 log_error("Unexpected token (12) in %s:%u.", path, line);
526 case STATE_ALLOW_DENY_MESSAGE_TYPE:
528 if (t == XML_ATTRIBUTE_VALUE) {
531 if (i->message_type != 0) {
532 log_error("Duplicate message type in %s:%u.", path, line);
536 if (!streq(name, "*")) {
537 r = bus_message_type_from_string(name, &i->message_type);
539 log_error("Invalid message type in %s:%u.", path, line);
544 state = STATE_ALLOW_DENY;
546 log_error("Unexpected token (13) in %s:%u.", path, line);
552 case STATE_ALLOW_DENY_NAME:
554 if (t == XML_ATTRIBUTE_VALUE) {
557 log_error("Duplicate name in %s:%u.", path, line);
562 case POLICY_ITEM_USER:
563 if (!streq(name, "*")) {
564 const char *u = name;
566 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
568 log_error_errno(r, "Failed to resolve user %s: %m", name);
573 case POLICY_ITEM_GROUP:
574 if (!streq(name, "*")) {
575 const char *g = name;
577 r = get_group_creds(&g, &i->gid);
579 log_error_errno(r, "Failed to resolve group %s: %m", name);
585 case POLICY_ITEM_SEND:
586 case POLICY_ITEM_RECV:
588 if (streq(name, "*")) {
602 state = STATE_ALLOW_DENY;
604 log_error("Unexpected token (14) in %s:%u.", path, line);
610 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
612 if (t == XML_ATTRIBUTE_VALUE)
613 state = STATE_ALLOW_DENY;
615 log_error("Unexpected token (15) in %s:%u.", path, line);
623 if (t == XML_TAG_OPEN)
625 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
628 state = STATE_BUSCONFIG;
644 static const char *verdict_to_string(int v) {
658 struct policy_check_filter {
659 PolicyItemClass class;
664 const char *interface;
669 static int is_permissive(PolicyItem *i) {
673 return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
676 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
682 case POLICY_ITEM_SEND:
683 case POLICY_ITEM_RECV:
685 if (i->name && !streq_ptr(i->name, filter->name))
688 if ((i->message_type != 0) && (i->message_type != filter->message_type))
691 if (i->path && !streq_ptr(i->path, filter->path))
694 if (i->member && !streq_ptr(i->member, filter->member))
697 if (i->interface && !streq_ptr(i->interface, filter->interface))
700 return is_permissive(i);
702 case POLICY_ITEM_OWN:
703 assert(filter->name);
705 if (streq(i->name, "*") || streq(i->name, filter->name))
706 return is_permissive(i);
709 case POLICY_ITEM_OWN_PREFIX:
710 assert(filter->name);
712 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
713 return is_permissive(i);
716 case POLICY_ITEM_USER:
717 if (filter->uid != UID_INVALID)
718 if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
719 return is_permissive(i);
722 case POLICY_ITEM_GROUP:
723 if (filter->gid != GID_INVALID)
724 if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
725 return is_permissive(i);
728 case POLICY_ITEM_IGNORE:
736 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
743 /* Check all policies in a set - a broader one might be followed by a more specific one,
744 * and the order of rules in policy definitions matters */
745 LIST_FOREACH(items, i, items) {
748 if (i->class != filter->class &&
749 !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
752 v = check_policy_item(i, filter);
760 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
768 assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
771 * The policy check is implemented by the following logic:
773 * 1. Check default items
774 * 2. Check group items
775 * 3. Check user items
776 * 4. Check on/no_console items
777 * 5. Check mandatory items
779 * Later rules override earlier rules.
782 verdict = check_policy_items(p->default_items, filter);
784 if (filter->gid != GID_INVALID) {
785 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
787 v = check_policy_items(items, filter);
793 if (filter->uid != UID_INVALID) {
794 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
796 v = check_policy_items(items, filter);
802 if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0)
803 v = check_policy_items(p->on_console_items, filter);
805 v = check_policy_items(p->no_console_items, filter);
809 v = check_policy_items(p->mandatory_items, filter);
816 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
818 struct policy_check_filter filter = {
819 .class = POLICY_ITEM_OWN,
830 verdict = policy_check(p, &filter);
832 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
833 "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
834 uid, gid, strna(name), strna(verdict_to_string(verdict)));
836 return verdict == ALLOW;
839 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
841 struct policy_check_filter filter = {
849 filter.class = POLICY_ITEM_USER;
850 verdict = policy_check(p, &filter);
852 if (verdict != DENY) {
855 filter.class = POLICY_ITEM_GROUP;
856 v = policy_check(p, &filter);
861 log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
862 "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
863 uid, gid, strna(verdict_to_string(verdict)));
865 return verdict == ALLOW;
868 bool policy_check_one_recv(Policy *p,
874 const char *interface,
875 const char *member) {
877 struct policy_check_filter filter = {
878 .class = POLICY_ITEM_RECV,
881 .message_type = message_type,
883 .interface = interface,
890 return policy_check(p, &filter) == ALLOW;
893 bool policy_check_recv(Policy *p,
900 const char *interface,
902 bool dbus_to_kernel) {
904 char *n, **nv, *last = NULL;
910 if (set_isempty(names) && strv_isempty(namesv)) {
911 allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member);
913 SET_FOREACH(n, names, i) {
915 allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member);
920 STRV_FOREACH(nv, namesv) {
922 allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member);
929 log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
930 "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
931 dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
932 strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
937 bool policy_check_one_send(Policy *p,
943 const char *interface,
944 const char *member) {
946 struct policy_check_filter filter = {
947 .class = POLICY_ITEM_SEND,
950 .message_type = message_type,
952 .interface = interface,
959 return policy_check(p, &filter) == ALLOW;
962 bool policy_check_send(Policy *p,
969 const char *interface,
972 char **out_used_name) {
974 char *n, **nv, *last = NULL;
980 if (set_isempty(names) && strv_isempty(namesv)) {
981 allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member);
983 SET_FOREACH(n, names, i) {
985 allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member);
990 STRV_FOREACH(nv, namesv) {
992 allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member);
1000 *out_used_name = last;
1002 log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
1003 "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
1004 dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
1005 strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
1010 int policy_load(Policy *p, char **files) {
1016 STRV_FOREACH(i, files) {
1018 r = file_load(p, *i);
1020 _cleanup_strv_free_ char **l = NULL;
1023 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
1025 return log_error_errno(r, "Failed to get configuration file list: %m");
1031 /* We ignore all errors but EISDIR, and just proceed. */
1037 void policy_free(Policy *p) {
1038 PolicyItem *i, *first;
1043 while ((i = p->default_items)) {
1044 LIST_REMOVE(items, p->default_items, i);
1045 policy_item_free(i);
1048 while ((i = p->mandatory_items)) {
1049 LIST_REMOVE(items, p->mandatory_items, i);
1050 policy_item_free(i);
1053 while ((i = p->on_console_items)) {
1054 LIST_REMOVE(items, p->on_console_items, i);
1055 policy_item_free(i);
1058 while ((i = p->no_console_items)) {
1059 LIST_REMOVE(items, p->no_console_items, i);
1060 policy_item_free(i);
1063 while ((first = hashmap_steal_first(p->user_items))) {
1065 while ((i = first)) {
1066 LIST_REMOVE(items, first, i);
1067 policy_item_free(i);
1071 while ((first = hashmap_steal_first(p->group_items))) {
1073 while ((i = first)) {
1074 LIST_REMOVE(items, first, i);
1075 policy_item_free(i);
1079 hashmap_free(p->user_items);
1080 hashmap_free(p->group_items);
1082 p->user_items = p->group_items = NULL;
1085 static void dump_items(PolicyItem *items, const char *prefix) {
1095 LIST_FOREACH(items, i, items) {
1097 printf("%sType: %s\n"
1099 prefix, policy_item_type_to_string(i->type),
1100 prefix, policy_item_class_to_string(i->class));
1103 printf("%sInterface: %s\n",
1104 prefix, i->interface);
1107 printf("%sMember: %s\n",
1111 printf("%sError: %s\n",
1115 printf("%sPath: %s\n",
1119 printf("%sName: %s\n",
1122 if (i->message_type != 0)
1123 printf("%sMessage Type: %s\n",
1124 prefix, bus_message_type_to_string(i->message_type));
1127 _cleanup_free_ char *user;
1129 user = uid_to_name(i->uid);
1131 printf("%sUser: %s ("UID_FMT")\n",
1132 prefix, strna(user), i->uid);
1136 _cleanup_free_ char *group;
1138 group = gid_to_name(i->gid);
1140 printf("%sGroup: %s ("GID_FMT")\n",
1141 prefix, strna(group), i->gid);
1143 printf("%s-\n", prefix);
1147 static void dump_hashmap_items(Hashmap *h) {
1152 HASHMAP_FOREACH_KEY(i, k, h, j) {
1153 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1154 dump_items(i, "\t\t");
1158 void policy_dump(Policy *p) {
1160 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1161 dump_items(p->default_items, "\t");
1163 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1164 dump_hashmap_items(p->group_items);
1166 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1167 dump_hashmap_items(p->user_items);
1169 printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
1170 dump_items(p->on_console_items, "\t");
1172 printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
1173 dump_items(p->no_console_items, "\t");
1175 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1176 dump_items(p->mandatory_items, "\t");
1181 int shared_policy_new(SharedPolicy **out) {
1185 sp = new0(SharedPolicy, 1);
1189 r = pthread_mutex_init(&sp->lock, NULL);
1191 log_error_errno(r, "Cannot initialize shared policy mutex: %m");
1195 r = pthread_rwlock_init(&sp->rwlock, NULL);
1197 log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
1205 /* pthread lock destruction is not fail-safe... meh! */
1207 pthread_mutex_destroy(&sp->lock);
1213 SharedPolicy *shared_policy_free(SharedPolicy *sp) {
1217 policy_free(sp->policy);
1218 pthread_rwlock_destroy(&sp->rwlock);
1219 pthread_mutex_destroy(&sp->lock);
1220 strv_free(sp->configuration);
1226 static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
1227 Policy old, buffer = {};
1233 r = policy_load(&buffer, configuration);
1235 return log_error_errno(r, "Failed to load policy: %m");
1237 log_debug("Reloading configuration");
1238 /* policy_dump(&buffer); */
1240 pthread_rwlock_wrlock(&sp->rwlock);
1241 memcpy(&old, &sp->buffer, sizeof(old));
1242 memcpy(&sp->buffer, &buffer, sizeof(buffer));
1243 free_old = !!sp->policy;
1244 sp->policy = &sp->buffer;
1245 pthread_rwlock_unlock(&sp->rwlock);
1253 int shared_policy_reload(SharedPolicy *sp) {
1258 pthread_mutex_lock(&sp->lock);
1259 r = shared_policy_reload_unlocked(sp, sp->configuration);
1260 pthread_mutex_unlock(&sp->lock);
1265 int shared_policy_preload(SharedPolicy *sp, char **configuration) {
1266 _cleanup_strv_free_ char **conf = NULL;
1271 conf = strv_copy(configuration);
1275 pthread_mutex_lock(&sp->lock);
1277 r = shared_policy_reload_unlocked(sp, conf);
1279 sp->configuration = conf;
1283 pthread_mutex_unlock(&sp->lock);
1288 Policy *shared_policy_acquire(SharedPolicy *sp) {
1291 pthread_rwlock_rdlock(&sp->rwlock);
1294 pthread_rwlock_unlock(&sp->rwlock);
1299 void shared_policy_release(SharedPolicy *sp, Policy *p) {
1301 assert(!p || sp->policy == p);
1304 pthread_rwlock_unlock(&sp->rwlock);
1307 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1308 [_POLICY_ITEM_TYPE_UNSET] = "unset",
1309 [POLICY_ITEM_ALLOW] = "allow",
1310 [POLICY_ITEM_DENY] = "deny",
1312 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1314 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1315 [_POLICY_ITEM_CLASS_UNSET] = "unset",
1316 [POLICY_ITEM_SEND] = "send",
1317 [POLICY_ITEM_RECV] = "recv",
1318 [POLICY_ITEM_OWN] = "own",
1319 [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1320 [POLICY_ITEM_USER] = "user",
1321 [POLICY_ITEM_GROUP] = "group",
1322 [POLICY_ITEM_IGNORE] = "ignore",
1324 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);