]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/bus-xml-policy.c
remove unused includes
[thirdparty/systemd.git] / src / bus-proxyd / bus-xml-policy.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include "xml.h"
23 #include "fileio.h"
24 #include "strv.h"
25 #include "set.h"
26 #include "conf-files.h"
27 #include "bus-internal.h"
28 #include "bus-xml-policy.h"
29 #include "sd-login.h"
30
31 static void policy_item_free(PolicyItem *i) {
32 assert(i);
33
34 free(i->interface);
35 free(i->member);
36 free(i->error);
37 free(i->name);
38 free(i->path);
39 free(i);
40 }
41
42 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
43
44 static void item_append(PolicyItem *i, PolicyItem **list) {
45
46 PolicyItem *tail;
47
48 LIST_FIND_TAIL(items, *list, tail);
49 LIST_INSERT_AFTER(items, *list, tail, i);
50 }
51
52 static int file_load(Policy *p, const char *path) {
53
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;
57 unsigned n_other = 0;
58 const char *q;
59 int r;
60
61 enum {
62 STATE_OUTSIDE,
63 STATE_BUSCONFIG,
64 STATE_POLICY,
65 STATE_POLICY_CONTEXT,
66 STATE_POLICY_CONSOLE,
67 STATE_POLICY_USER,
68 STATE_POLICY_GROUP,
69 STATE_POLICY_OTHER_ATTRIBUTE,
70 STATE_ALLOW_DENY,
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,
78 STATE_OTHER,
79 } state = STATE_OUTSIDE;
80
81 enum {
82 POLICY_CATEGORY_NONE,
83 POLICY_CATEGORY_DEFAULT,
84 POLICY_CATEGORY_MANDATORY,
85 POLICY_CATEGORY_ON_CONSOLE,
86 POLICY_CATEGORY_NO_CONSOLE,
87 POLICY_CATEGORY_USER,
88 POLICY_CATEGORY_GROUP
89 } policy_category = POLICY_CATEGORY_NONE;
90
91 unsigned line = 0;
92
93 assert(p);
94
95 r = read_full_file(path, &c, NULL);
96 if (r < 0) {
97 if (r == -ENOENT)
98 return 0;
99 if (r == -EISDIR)
100 return r;
101
102 return log_error_errno(r, "Failed to load %s: %m", path);
103 }
104
105 q = c;
106 for (;;) {
107 _cleanup_free_ char *name = NULL;
108 int t;
109
110 t = xml_tokenize(&q, &name, &xml_state, &line);
111 if (t < 0)
112 return log_error_errno(t, "XML parse failure in %s: %m", path);
113
114 switch (state) {
115
116 case STATE_OUTSIDE:
117
118 if (t == XML_TAG_OPEN) {
119 if (streq(name, "busconfig"))
120 state = STATE_BUSCONFIG;
121 else {
122 log_error("Unexpected tag %s at %s:%u.", name, path, line);
123 return -EINVAL;
124 }
125
126 } else if (t == XML_END)
127 return 0;
128 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
129 log_error("Unexpected token (1) at %s:%u.", path, line);
130 return -EINVAL;
131 }
132
133 break;
134
135 case STATE_BUSCONFIG:
136
137 if (t == XML_TAG_OPEN) {
138 if (streq(name, "policy")) {
139 state = STATE_POLICY;
140 policy_category = POLICY_CATEGORY_NONE;
141 free(policy_user);
142 free(policy_group);
143 policy_user = policy_group = NULL;
144 } else {
145 state = STATE_OTHER;
146 n_other = 0;
147 }
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);
153 return -EINVAL;
154 }
155
156 break;
157
158 case STATE_POLICY:
159
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;
169 else {
170 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
171 state = STATE_POLICY_OTHER_ATTRIBUTE;
172 }
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) {
177 PolicyItemType it;
178
179 if (streq(name, "allow"))
180 it = POLICY_ITEM_ALLOW;
181 else if (streq(name, "deny"))
182 it = POLICY_ITEM_DENY;
183 else {
184 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
185 return -EINVAL;
186 }
187
188 assert(!i);
189 i = new0(PolicyItem, 1);
190 if (!i)
191 return log_oom();
192
193 i->type = it;
194 state = STATE_ALLOW_DENY;
195
196 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
197 log_error("Unexpected token (3) at %s:%u.", path, line);
198 return -EINVAL;
199 }
200
201 break;
202
203 case STATE_POLICY_CONTEXT:
204
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;
212 } else {
213 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
214 return -EINVAL;
215 }
216 } else {
217 log_error("Unexpected token (4) at %s:%u.", path, line);
218 return -EINVAL;
219 }
220
221 break;
222
223 case STATE_POLICY_CONSOLE:
224
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;
232 } else {
233 log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
234 return -EINVAL;
235 }
236 } else {
237 log_error("Unexpected token (4.1) at %s:%u.", path, line);
238 return -EINVAL;
239 }
240
241 break;
242
243 case STATE_POLICY_USER:
244
245 if (t == XML_ATTRIBUTE_VALUE) {
246 free(policy_user);
247 policy_user = name;
248 name = NULL;
249 policy_category = POLICY_CATEGORY_USER;
250 state = STATE_POLICY;
251 } else {
252 log_error("Unexpected token (5) in %s:%u.", path, line);
253 return -EINVAL;
254 }
255
256 break;
257
258 case STATE_POLICY_GROUP:
259
260 if (t == XML_ATTRIBUTE_VALUE) {
261 free(policy_group);
262 policy_group = name;
263 name = NULL;
264 policy_category = POLICY_CATEGORY_GROUP;
265 state = STATE_POLICY;
266 } else {
267 log_error("Unexpected token (6) at %s:%u.", path, line);
268 return -EINVAL;
269 }
270
271 break;
272
273 case STATE_POLICY_OTHER_ATTRIBUTE:
274
275 if (t == XML_ATTRIBUTE_VALUE)
276 state = STATE_POLICY;
277 else {
278 log_error("Unexpected token (7) in %s:%u.", path, line);
279 return -EINVAL;
280 }
281
282 break;
283
284 case STATE_ALLOW_DENY:
285
286 assert(i);
287
288 if (t == XML_ATTRIBUTE_NAME) {
289 PolicyItemClass ic;
290
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;
306 break;
307 } else {
308 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
309 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
310 break;
311 }
312
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);
315 return -EINVAL;
316 }
317
318 i->class = ic;
319
320 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
321 const char *u;
322
323 u = strchr(name, '_');
324 assert(u);
325
326 u++;
327
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;
341 else {
342 if (streq(u, "requested_reply"))
343 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
344 else
345 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
346 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
347 break;
348 }
349 } else
350 state = STATE_ALLOW_DENY_NAME;
351
352 } else if (t == XML_TAG_CLOSE_EMPTY ||
353 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
354
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;
358
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;
369
370 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
371
372 r = hashmap_ensure_allocated(&p->user_items, NULL);
373 if (r < 0)
374 return log_oom();
375
376 if (!u) {
377 log_error("User policy without name");
378 return -EINVAL;
379 }
380
381 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
382 if (r < 0) {
383 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
384 free(i);
385 } else {
386 PolicyItem *first;
387
388 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
389 item_append(i, &first);
390 i->uid_valid = true;
391
392 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
393 if (r < 0) {
394 LIST_REMOVE(items, first, i);
395 return log_oom();
396 }
397 }
398
399 } else if (policy_category == POLICY_CATEGORY_GROUP) {
400 const char *g = policy_group;
401
402 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
403
404 r = hashmap_ensure_allocated(&p->group_items, NULL);
405 if (r < 0)
406 return log_oom();
407
408 if (!g) {
409 log_error("Group policy without name");
410 return -EINVAL;
411 }
412
413 r = get_group_creds(&g, &i->gid);
414 if (r < 0) {
415 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
416 free(i);
417 } else {
418 PolicyItem *first;
419
420 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
421 item_append(i, &first);
422 i->gid_valid = true;
423
424 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
425 if (r < 0) {
426 LIST_REMOVE(items, first, i);
427 return log_oom();
428 }
429 }
430 }
431
432 state = STATE_POLICY;
433 i = NULL;
434
435 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
436 log_error("Unexpected token (8) at %s:%u.", path, line);
437 return -EINVAL;
438 }
439
440 break;
441
442 case STATE_ALLOW_DENY_INTERFACE:
443
444 if (t == XML_ATTRIBUTE_VALUE) {
445 assert(i);
446 if (i->interface) {
447 log_error("Duplicate interface at %s:%u.", path, line);
448 return -EINVAL;
449 }
450
451 if (!streq(name, "*")) {
452 i->interface = name;
453 name = NULL;
454 }
455 state = STATE_ALLOW_DENY;
456 } else {
457 log_error("Unexpected token (9) at %s:%u.", path, line);
458 return -EINVAL;
459 }
460
461 break;
462
463 case STATE_ALLOW_DENY_MEMBER:
464
465 if (t == XML_ATTRIBUTE_VALUE) {
466 assert(i);
467 if (i->member) {
468 log_error("Duplicate member in %s:%u.", path, line);
469 return -EINVAL;
470 }
471
472 if (!streq(name, "*")) {
473 i->member = name;
474 name = NULL;
475 }
476 state = STATE_ALLOW_DENY;
477 } else {
478 log_error("Unexpected token (10) in %s:%u.", path, line);
479 return -EINVAL;
480 }
481
482 break;
483
484 case STATE_ALLOW_DENY_ERROR:
485
486 if (t == XML_ATTRIBUTE_VALUE) {
487 assert(i);
488 if (i->error) {
489 log_error("Duplicate error in %s:%u.", path, line);
490 return -EINVAL;
491 }
492
493 if (!streq(name, "*")) {
494 i->error = name;
495 name = NULL;
496 }
497 state = STATE_ALLOW_DENY;
498 } else {
499 log_error("Unexpected token (11) in %s:%u.", path, line);
500 return -EINVAL;
501 }
502
503 break;
504
505 case STATE_ALLOW_DENY_PATH:
506
507 if (t == XML_ATTRIBUTE_VALUE) {
508 assert(i);
509 if (i->path) {
510 log_error("Duplicate path in %s:%u.", path, line);
511 return -EINVAL;
512 }
513
514 if (!streq(name, "*")) {
515 i->path = name;
516 name = NULL;
517 }
518 state = STATE_ALLOW_DENY;
519 } else {
520 log_error("Unexpected token (12) in %s:%u.", path, line);
521 return -EINVAL;
522 }
523
524 break;
525
526 case STATE_ALLOW_DENY_MESSAGE_TYPE:
527
528 if (t == XML_ATTRIBUTE_VALUE) {
529 assert(i);
530
531 if (i->message_type != 0) {
532 log_error("Duplicate message type in %s:%u.", path, line);
533 return -EINVAL;
534 }
535
536 if (!streq(name, "*")) {
537 r = bus_message_type_from_string(name, &i->message_type);
538 if (r < 0) {
539 log_error("Invalid message type in %s:%u.", path, line);
540 return -EINVAL;
541 }
542 }
543
544 state = STATE_ALLOW_DENY;
545 } else {
546 log_error("Unexpected token (13) in %s:%u.", path, line);
547 return -EINVAL;
548 }
549
550 break;
551
552 case STATE_ALLOW_DENY_NAME:
553
554 if (t == XML_ATTRIBUTE_VALUE) {
555 assert(i);
556 if (i->name) {
557 log_error("Duplicate name in %s:%u.", path, line);
558 return -EINVAL;
559 }
560
561 switch (i->class) {
562 case POLICY_ITEM_USER:
563 if (!streq(name, "*")) {
564 const char *u = name;
565
566 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
567 if (r < 0)
568 log_error_errno(r, "Failed to resolve user %s: %m", name);
569 else
570 i->uid_valid = true;
571 }
572 break;
573 case POLICY_ITEM_GROUP:
574 if (!streq(name, "*")) {
575 const char *g = name;
576
577 r = get_group_creds(&g, &i->gid);
578 if (r < 0)
579 log_error_errno(r, "Failed to resolve group %s: %m", name);
580 else
581 i->gid_valid = true;
582 }
583 break;
584
585 case POLICY_ITEM_SEND:
586 case POLICY_ITEM_RECV:
587
588 if (streq(name, "*")) {
589 free(name);
590 name = NULL;
591 }
592 break;
593
594
595 default:
596 break;
597 }
598
599 i->name = name;
600 name = NULL;
601
602 state = STATE_ALLOW_DENY;
603 } else {
604 log_error("Unexpected token (14) in %s:%u.", path, line);
605 return -EINVAL;
606 }
607
608 break;
609
610 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
611
612 if (t == XML_ATTRIBUTE_VALUE)
613 state = STATE_ALLOW_DENY;
614 else {
615 log_error("Unexpected token (15) in %s:%u.", path, line);
616 return -EINVAL;
617 }
618
619 break;
620
621 case STATE_OTHER:
622
623 if (t == XML_TAG_OPEN)
624 n_other++;
625 else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
626
627 if (n_other == 0)
628 state = STATE_BUSCONFIG;
629 else
630 n_other--;
631 }
632
633 break;
634 }
635 }
636 }
637
638 enum {
639 DENY,
640 ALLOW,
641 DUNNO,
642 };
643
644 static const char *verdict_to_string(int v) {
645 switch (v) {
646
647 case DENY:
648 return "DENY";
649 case ALLOW:
650 return "ALLOW";
651 case DUNNO:
652 return "DUNNO";
653 }
654
655 return NULL;
656 }
657
658 struct policy_check_filter {
659 PolicyItemClass class;
660 uid_t uid;
661 gid_t gid;
662 int message_type;
663 const char *name;
664 const char *interface;
665 const char *path;
666 const char *member;
667 };
668
669 static int is_permissive(PolicyItem *i) {
670
671 assert(i);
672
673 return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
674 }
675
676 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
677
678 assert(i);
679 assert(filter);
680
681 switch (i->class) {
682 case POLICY_ITEM_SEND:
683 case POLICY_ITEM_RECV:
684
685 if (i->name && !streq_ptr(i->name, filter->name))
686 break;
687
688 if ((i->message_type != 0) && (i->message_type != filter->message_type))
689 break;
690
691 if (i->path && !streq_ptr(i->path, filter->path))
692 break;
693
694 if (i->member && !streq_ptr(i->member, filter->member))
695 break;
696
697 if (i->interface && !streq_ptr(i->interface, filter->interface))
698 break;
699
700 return is_permissive(i);
701
702 case POLICY_ITEM_OWN:
703 assert(filter->name);
704
705 if (streq(i->name, "*") || streq(i->name, filter->name))
706 return is_permissive(i);
707 break;
708
709 case POLICY_ITEM_OWN_PREFIX:
710 assert(filter->name);
711
712 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
713 return is_permissive(i);
714 break;
715
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);
720 break;
721
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);
726 break;
727
728 case POLICY_ITEM_IGNORE:
729 default:
730 break;
731 }
732
733 return DUNNO;
734 }
735
736 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
737
738 PolicyItem *i;
739 int verdict = DUNNO;
740
741 assert(filter);
742
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) {
746 int v;
747
748 if (i->class != filter->class &&
749 !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
750 continue;
751
752 v = check_policy_item(i, filter);
753 if (v != DUNNO)
754 verdict = v;
755 }
756
757 return verdict;
758 }
759
760 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
761
762 PolicyItem *items;
763 int verdict, v;
764
765 assert(p);
766 assert(filter);
767
768 assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
769
770 /*
771 * The policy check is implemented by the following logic:
772 *
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
778 *
779 * Later rules override earlier rules.
780 */
781
782 verdict = check_policy_items(p->default_items, filter);
783
784 if (filter->gid != GID_INVALID) {
785 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
786 if (items) {
787 v = check_policy_items(items, filter);
788 if (v != DUNNO)
789 verdict = v;
790 }
791 }
792
793 if (filter->uid != UID_INVALID) {
794 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
795 if (items) {
796 v = check_policy_items(items, filter);
797 if (v != DUNNO)
798 verdict = v;
799 }
800 }
801
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);
804 else
805 v = check_policy_items(p->no_console_items, filter);
806 if (v != DUNNO)
807 verdict = v;
808
809 v = check_policy_items(p->mandatory_items, filter);
810 if (v != DUNNO)
811 verdict = v;
812
813 return verdict;
814 }
815
816 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
817
818 struct policy_check_filter filter = {
819 .class = POLICY_ITEM_OWN,
820 .uid = uid,
821 .gid = gid,
822 .name = name,
823 };
824
825 int verdict;
826
827 assert(p);
828 assert(name);
829
830 verdict = policy_check(p, &filter);
831
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)));
835
836 return verdict == ALLOW;
837 }
838
839 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
840
841 struct policy_check_filter filter = {
842 .uid = uid,
843 .gid = gid,
844 };
845 int verdict;
846
847 assert(p);
848
849 filter.class = POLICY_ITEM_USER;
850 verdict = policy_check(p, &filter);
851
852 if (verdict != DENY) {
853 int v;
854
855 filter.class = POLICY_ITEM_GROUP;
856 v = policy_check(p, &filter);
857 if (v != DUNNO)
858 verdict = v;
859 }
860
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)));
864
865 return verdict == ALLOW;
866 }
867
868 bool policy_check_one_recv(Policy *p,
869 uid_t uid,
870 gid_t gid,
871 int message_type,
872 const char *name,
873 const char *path,
874 const char *interface,
875 const char *member) {
876
877 struct policy_check_filter filter = {
878 .class = POLICY_ITEM_RECV,
879 .uid = uid,
880 .gid = gid,
881 .message_type = message_type,
882 .name = name,
883 .interface = interface,
884 .path = path,
885 .member = member,
886 };
887
888 assert(p);
889
890 return policy_check(p, &filter) == ALLOW;
891 }
892
893 bool policy_check_recv(Policy *p,
894 uid_t uid,
895 gid_t gid,
896 int message_type,
897 Set *names,
898 char **namesv,
899 const char *path,
900 const char *interface,
901 const char *member,
902 bool dbus_to_kernel) {
903
904 char *n, **nv, *last = NULL;
905 bool allow = false;
906 Iterator i;
907
908 assert(p);
909
910 if (set_isempty(names) && strv_isempty(namesv)) {
911 allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member);
912 } else {
913 SET_FOREACH(n, names, i) {
914 last = n;
915 allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member);
916 if (allow)
917 break;
918 }
919 if (!allow) {
920 STRV_FOREACH(nv, namesv) {
921 last = *nv;
922 allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member);
923 if (allow)
924 break;
925 }
926 }
927 }
928
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");
933
934 return allow;
935 }
936
937 bool policy_check_one_send(Policy *p,
938 uid_t uid,
939 gid_t gid,
940 int message_type,
941 const char *name,
942 const char *path,
943 const char *interface,
944 const char *member) {
945
946 struct policy_check_filter filter = {
947 .class = POLICY_ITEM_SEND,
948 .uid = uid,
949 .gid = gid,
950 .message_type = message_type,
951 .name = name,
952 .interface = interface,
953 .path = path,
954 .member = member,
955 };
956
957 assert(p);
958
959 return policy_check(p, &filter) == ALLOW;
960 }
961
962 bool policy_check_send(Policy *p,
963 uid_t uid,
964 gid_t gid,
965 int message_type,
966 Set *names,
967 char **namesv,
968 const char *path,
969 const char *interface,
970 const char *member,
971 bool dbus_to_kernel,
972 char **out_used_name) {
973
974 char *n, **nv, *last = NULL;
975 bool allow = false;
976 Iterator i;
977
978 assert(p);
979
980 if (set_isempty(names) && strv_isempty(namesv)) {
981 allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member);
982 } else {
983 SET_FOREACH(n, names, i) {
984 last = n;
985 allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member);
986 if (allow)
987 break;
988 }
989 if (!allow) {
990 STRV_FOREACH(nv, namesv) {
991 last = *nv;
992 allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member);
993 if (allow)
994 break;
995 }
996 }
997 }
998
999 if (out_used_name)
1000 *out_used_name = last;
1001
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");
1006
1007 return allow;
1008 }
1009
1010 int policy_load(Policy *p, char **files) {
1011 char **i;
1012 int r;
1013
1014 assert(p);
1015
1016 STRV_FOREACH(i, files) {
1017
1018 r = file_load(p, *i);
1019 if (r == -EISDIR) {
1020 _cleanup_strv_free_ char **l = NULL;
1021 char **j;
1022
1023 r = conf_files_list(&l, ".conf", NULL, *i, NULL);
1024 if (r < 0)
1025 return log_error_errno(r, "Failed to get configuration file list: %m");
1026
1027 STRV_FOREACH(j, l)
1028 file_load(p, *j);
1029 }
1030
1031 /* We ignore all errors but EISDIR, and just proceed. */
1032 }
1033
1034 return 0;
1035 }
1036
1037 void policy_free(Policy *p) {
1038 PolicyItem *i, *first;
1039
1040 if (!p)
1041 return;
1042
1043 while ((i = p->default_items)) {
1044 LIST_REMOVE(items, p->default_items, i);
1045 policy_item_free(i);
1046 }
1047
1048 while ((i = p->mandatory_items)) {
1049 LIST_REMOVE(items, p->mandatory_items, i);
1050 policy_item_free(i);
1051 }
1052
1053 while ((i = p->on_console_items)) {
1054 LIST_REMOVE(items, p->on_console_items, i);
1055 policy_item_free(i);
1056 }
1057
1058 while ((i = p->no_console_items)) {
1059 LIST_REMOVE(items, p->no_console_items, i);
1060 policy_item_free(i);
1061 }
1062
1063 while ((first = hashmap_steal_first(p->user_items))) {
1064
1065 while ((i = first)) {
1066 LIST_REMOVE(items, first, i);
1067 policy_item_free(i);
1068 }
1069 }
1070
1071 while ((first = hashmap_steal_first(p->group_items))) {
1072
1073 while ((i = first)) {
1074 LIST_REMOVE(items, first, i);
1075 policy_item_free(i);
1076 }
1077 }
1078
1079 hashmap_free(p->user_items);
1080 hashmap_free(p->group_items);
1081
1082 p->user_items = p->group_items = NULL;
1083 }
1084
1085 static void dump_items(PolicyItem *items, const char *prefix) {
1086
1087 PolicyItem *i;
1088
1089 if (!items)
1090 return;
1091
1092 if (!prefix)
1093 prefix = "";
1094
1095 LIST_FOREACH(items, i, items) {
1096
1097 printf("%sType: %s\n"
1098 "%sClass: %s\n",
1099 prefix, policy_item_type_to_string(i->type),
1100 prefix, policy_item_class_to_string(i->class));
1101
1102 if (i->interface)
1103 printf("%sInterface: %s\n",
1104 prefix, i->interface);
1105
1106 if (i->member)
1107 printf("%sMember: %s\n",
1108 prefix, i->member);
1109
1110 if (i->error)
1111 printf("%sError: %s\n",
1112 prefix, i->error);
1113
1114 if (i->path)
1115 printf("%sPath: %s\n",
1116 prefix, i->path);
1117
1118 if (i->name)
1119 printf("%sName: %s\n",
1120 prefix, i->name);
1121
1122 if (i->message_type != 0)
1123 printf("%sMessage Type: %s\n",
1124 prefix, bus_message_type_to_string(i->message_type));
1125
1126 if (i->uid_valid) {
1127 _cleanup_free_ char *user;
1128
1129 user = uid_to_name(i->uid);
1130
1131 printf("%sUser: %s ("UID_FMT")\n",
1132 prefix, strna(user), i->uid);
1133 }
1134
1135 if (i->gid_valid) {
1136 _cleanup_free_ char *group;
1137
1138 group = gid_to_name(i->gid);
1139
1140 printf("%sGroup: %s ("GID_FMT")\n",
1141 prefix, strna(group), i->gid);
1142 }
1143 printf("%s-\n", prefix);
1144 }
1145 }
1146
1147 static void dump_hashmap_items(Hashmap *h) {
1148 PolicyItem *i;
1149 Iterator j;
1150 void *k;
1151
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");
1155 }
1156 }
1157
1158 void policy_dump(Policy *p) {
1159
1160 printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1161 dump_items(p->default_items, "\t");
1162
1163 printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1164 dump_hashmap_items(p->group_items);
1165
1166 printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1167 dump_hashmap_items(p->user_items);
1168
1169 printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
1170 dump_items(p->on_console_items, "\t");
1171
1172 printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
1173 dump_items(p->no_console_items, "\t");
1174
1175 printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1176 dump_items(p->mandatory_items, "\t");
1177
1178 fflush(stdout);
1179 }
1180
1181 int shared_policy_new(SharedPolicy **out) {
1182 SharedPolicy *sp;
1183 int r;
1184
1185 sp = new0(SharedPolicy, 1);
1186 if (!sp)
1187 return log_oom();
1188
1189 r = pthread_mutex_init(&sp->lock, NULL);
1190 if (r < 0) {
1191 log_error_errno(r, "Cannot initialize shared policy mutex: %m");
1192 goto exit_free;
1193 }
1194
1195 r = pthread_rwlock_init(&sp->rwlock, NULL);
1196 if (r < 0) {
1197 log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
1198 goto exit_mutex;
1199 }
1200
1201 *out = sp;
1202 sp = NULL;
1203 return 0;
1204
1205 /* pthread lock destruction is not fail-safe... meh! */
1206 exit_mutex:
1207 pthread_mutex_destroy(&sp->lock);
1208 exit_free:
1209 free(sp);
1210 return r;
1211 }
1212
1213 SharedPolicy *shared_policy_free(SharedPolicy *sp) {
1214 if (!sp)
1215 return NULL;
1216
1217 policy_free(sp->policy);
1218 pthread_rwlock_destroy(&sp->rwlock);
1219 pthread_mutex_destroy(&sp->lock);
1220 strv_free(sp->configuration);
1221 free(sp);
1222
1223 return NULL;
1224 }
1225
1226 static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
1227 Policy old, buffer = {};
1228 bool free_old;
1229 int r;
1230
1231 assert(sp);
1232
1233 r = policy_load(&buffer, configuration);
1234 if (r < 0)
1235 return log_error_errno(r, "Failed to load policy: %m");
1236
1237 log_debug("Reloading configuration");
1238 /* policy_dump(&buffer); */
1239
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);
1246
1247 if (free_old)
1248 policy_free(&old);
1249
1250 return 0;
1251 }
1252
1253 int shared_policy_reload(SharedPolicy *sp) {
1254 int r;
1255
1256 assert(sp);
1257
1258 pthread_mutex_lock(&sp->lock);
1259 r = shared_policy_reload_unlocked(sp, sp->configuration);
1260 pthread_mutex_unlock(&sp->lock);
1261
1262 return r;
1263 }
1264
1265 int shared_policy_preload(SharedPolicy *sp, char **configuration) {
1266 _cleanup_strv_free_ char **conf = NULL;
1267 int r = 0;
1268
1269 assert(sp);
1270
1271 conf = strv_copy(configuration);
1272 if (!conf)
1273 return log_oom();
1274
1275 pthread_mutex_lock(&sp->lock);
1276 if (!sp->policy) {
1277 r = shared_policy_reload_unlocked(sp, conf);
1278 if (r >= 0) {
1279 sp->configuration = conf;
1280 conf = NULL;
1281 }
1282 }
1283 pthread_mutex_unlock(&sp->lock);
1284
1285 return r;
1286 }
1287
1288 Policy *shared_policy_acquire(SharedPolicy *sp) {
1289 assert(sp);
1290
1291 pthread_rwlock_rdlock(&sp->rwlock);
1292 if (sp->policy)
1293 return sp->policy;
1294 pthread_rwlock_unlock(&sp->rwlock);
1295
1296 return NULL;
1297 }
1298
1299 void shared_policy_release(SharedPolicy *sp, Policy *p) {
1300 assert(sp);
1301 assert(!p || sp->policy == p);
1302
1303 if (p)
1304 pthread_rwlock_unlock(&sp->rwlock);
1305 }
1306
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",
1311 };
1312 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1313
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",
1323 };
1324 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);