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