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