]> git.proxmox.com Git - systemd.git/blob - src/bus-proxyd/bus-xml-policy.c
Imported Upstream version 220
[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 #include "formats-util.h"
31
32 static void policy_item_free(PolicyItem *i) {
33 assert(i);
34
35 free(i->interface);
36 free(i->member);
37 free(i->error);
38 free(i->name);
39 free(i->path);
40 free(i);
41 }
42
43 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
44
45 static void item_append(PolicyItem *i, PolicyItem **list) {
46
47 PolicyItem *tail;
48
49 LIST_FIND_TAIL(items, *list, tail);
50 LIST_INSERT_AFTER(items, *list, tail, i);
51 }
52
53 static int file_load(Policy *p, const char *path) {
54
55 _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
56 _cleanup_(policy_item_freep) PolicyItem *i = NULL;
57 void *xml_state = NULL;
58 unsigned n_other = 0;
59 const char *q;
60 int r;
61
62 enum {
63 STATE_OUTSIDE,
64 STATE_BUSCONFIG,
65 STATE_POLICY,
66 STATE_POLICY_CONTEXT,
67 STATE_POLICY_CONSOLE,
68 STATE_POLICY_USER,
69 STATE_POLICY_GROUP,
70 STATE_POLICY_OTHER_ATTRIBUTE,
71 STATE_ALLOW_DENY,
72 STATE_ALLOW_DENY_INTERFACE,
73 STATE_ALLOW_DENY_MEMBER,
74 STATE_ALLOW_DENY_ERROR,
75 STATE_ALLOW_DENY_PATH,
76 STATE_ALLOW_DENY_MESSAGE_TYPE,
77 STATE_ALLOW_DENY_NAME,
78 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
79 STATE_OTHER,
80 } state = STATE_OUTSIDE;
81
82 enum {
83 POLICY_CATEGORY_NONE,
84 POLICY_CATEGORY_DEFAULT,
85 POLICY_CATEGORY_MANDATORY,
86 POLICY_CATEGORY_ON_CONSOLE,
87 POLICY_CATEGORY_NO_CONSOLE,
88 POLICY_CATEGORY_USER,
89 POLICY_CATEGORY_GROUP
90 } policy_category = POLICY_CATEGORY_NONE;
91
92 unsigned line = 0;
93
94 assert(p);
95
96 r = read_full_file(path, &c, NULL);
97 if (r < 0) {
98 if (r == -ENOENT)
99 return 0;
100 if (r == -EISDIR)
101 return r;
102
103 return log_error_errno(r, "Failed to load %s: %m", path);
104 }
105
106 q = c;
107 for (;;) {
108 _cleanup_free_ char *name = NULL;
109 int t;
110
111 t = xml_tokenize(&q, &name, &xml_state, &line);
112 if (t < 0)
113 return log_error_errno(t, "XML parse failure in %s: %m", path);
114
115 switch (state) {
116
117 case STATE_OUTSIDE:
118
119 if (t == XML_TAG_OPEN) {
120 if (streq(name, "busconfig"))
121 state = STATE_BUSCONFIG;
122 else {
123 log_error("Unexpected tag %s at %s:%u.", name, path, line);
124 return -EINVAL;
125 }
126
127 } else if (t == XML_END)
128 return 0;
129 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
130 log_error("Unexpected token (1) at %s:%u.", path, line);
131 return -EINVAL;
132 }
133
134 break;
135
136 case STATE_BUSCONFIG:
137
138 if (t == XML_TAG_OPEN) {
139 if (streq(name, "policy")) {
140 state = STATE_POLICY;
141 policy_category = POLICY_CATEGORY_NONE;
142 free(policy_user);
143 free(policy_group);
144 policy_user = policy_group = NULL;
145 } else {
146 state = STATE_OTHER;
147 n_other = 0;
148 }
149 } else if (t == XML_TAG_CLOSE_EMPTY ||
150 (t == XML_TAG_CLOSE && streq(name, "busconfig")))
151 state = STATE_OUTSIDE;
152 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
153 log_error("Unexpected token (2) at %s:%u.", path, line);
154 return -EINVAL;
155 }
156
157 break;
158
159 case STATE_POLICY:
160
161 if (t == XML_ATTRIBUTE_NAME) {
162 if (streq(name, "context"))
163 state = STATE_POLICY_CONTEXT;
164 else if (streq(name, "at_console"))
165 state = STATE_POLICY_CONSOLE;
166 else if (streq(name, "user"))
167 state = STATE_POLICY_USER;
168 else if (streq(name, "group"))
169 state = STATE_POLICY_GROUP;
170 else {
171 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
172 state = STATE_POLICY_OTHER_ATTRIBUTE;
173 }
174 } else if (t == XML_TAG_CLOSE_EMPTY ||
175 (t == XML_TAG_CLOSE && streq(name, "policy")))
176 state = STATE_BUSCONFIG;
177 else if (t == XML_TAG_OPEN) {
178 PolicyItemType it;
179
180 if (streq(name, "allow"))
181 it = POLICY_ITEM_ALLOW;
182 else if (streq(name, "deny"))
183 it = POLICY_ITEM_DENY;
184 else {
185 log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
186 return -EINVAL;
187 }
188
189 assert(!i);
190 i = new0(PolicyItem, 1);
191 if (!i)
192 return log_oom();
193
194 i->type = it;
195 state = STATE_ALLOW_DENY;
196
197 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
198 log_error("Unexpected token (3) at %s:%u.", path, line);
199 return -EINVAL;
200 }
201
202 break;
203
204 case STATE_POLICY_CONTEXT:
205
206 if (t == XML_ATTRIBUTE_VALUE) {
207 if (streq(name, "default")) {
208 policy_category = POLICY_CATEGORY_DEFAULT;
209 state = STATE_POLICY;
210 } else if (streq(name, "mandatory")) {
211 policy_category = POLICY_CATEGORY_MANDATORY;
212 state = STATE_POLICY;
213 } else {
214 log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
215 return -EINVAL;
216 }
217 } else {
218 log_error("Unexpected token (4) at %s:%u.", path, line);
219 return -EINVAL;
220 }
221
222 break;
223
224 case STATE_POLICY_CONSOLE:
225
226 if (t == XML_ATTRIBUTE_VALUE) {
227 if (streq(name, "true")) {
228 policy_category = POLICY_CATEGORY_ON_CONSOLE;
229 state = STATE_POLICY;
230 } else if (streq(name, "false")) {
231 policy_category = POLICY_CATEGORY_NO_CONSOLE;
232 state = STATE_POLICY;
233 } else {
234 log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
235 return -EINVAL;
236 }
237 } else {
238 log_error("Unexpected token (4.1) at %s:%u.", path, line);
239 return -EINVAL;
240 }
241
242 break;
243
244 case STATE_POLICY_USER:
245
246 if (t == XML_ATTRIBUTE_VALUE) {
247 free(policy_user);
248 policy_user = name;
249 name = NULL;
250 policy_category = POLICY_CATEGORY_USER;
251 state = STATE_POLICY;
252 } else {
253 log_error("Unexpected token (5) in %s:%u.", path, line);
254 return -EINVAL;
255 }
256
257 break;
258
259 case STATE_POLICY_GROUP:
260
261 if (t == XML_ATTRIBUTE_VALUE) {
262 free(policy_group);
263 policy_group = name;
264 name = NULL;
265 policy_category = POLICY_CATEGORY_GROUP;
266 state = STATE_POLICY;
267 } else {
268 log_error("Unexpected token (6) at %s:%u.", path, line);
269 return -EINVAL;
270 }
271
272 break;
273
274 case STATE_POLICY_OTHER_ATTRIBUTE:
275
276 if (t == XML_ATTRIBUTE_VALUE)
277 state = STATE_POLICY;
278 else {
279 log_error("Unexpected token (7) in %s:%u.", path, line);
280 return -EINVAL;
281 }
282
283 break;
284
285 case STATE_ALLOW_DENY:
286
287 assert(i);
288
289 if (t == XML_ATTRIBUTE_NAME) {
290 PolicyItemClass ic;
291
292 if (startswith(name, "send_"))
293 ic = POLICY_ITEM_SEND;
294 else if (startswith(name, "receive_"))
295 ic = POLICY_ITEM_RECV;
296 else if (streq(name, "own"))
297 ic = POLICY_ITEM_OWN;
298 else if (streq(name, "own_prefix"))
299 ic = POLICY_ITEM_OWN_PREFIX;
300 else if (streq(name, "user"))
301 ic = POLICY_ITEM_USER;
302 else if (streq(name, "group"))
303 ic = POLICY_ITEM_GROUP;
304 else if (streq(name, "eavesdrop")) {
305 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
306 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
307 break;
308 } else {
309 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
310 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
311 break;
312 }
313
314 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
315 log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
316 return -EINVAL;
317 }
318
319 i->class = ic;
320
321 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
322 const char *u;
323
324 u = strchr(name, '_');
325 assert(u);
326
327 u++;
328
329 if (streq(u, "interface"))
330 state = STATE_ALLOW_DENY_INTERFACE;
331 else if (streq(u, "member"))
332 state = STATE_ALLOW_DENY_MEMBER;
333 else if (streq(u, "error"))
334 state = STATE_ALLOW_DENY_ERROR;
335 else if (streq(u, "path"))
336 state = STATE_ALLOW_DENY_PATH;
337 else if (streq(u, "type"))
338 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
339 else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
340 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
341 state = STATE_ALLOW_DENY_NAME;
342 else {
343 if (streq(u, "requested_reply"))
344 log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
345 else
346 log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
347 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
348 break;
349 }
350 } else
351 state = STATE_ALLOW_DENY_NAME;
352
353 } else if (t == XML_TAG_CLOSE_EMPTY ||
354 (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
355
356 /* If the tag is fully empty so far, we consider it a recv */
357 if (i->class == _POLICY_ITEM_CLASS_UNSET)
358 i->class = POLICY_ITEM_RECV;
359
360 if (policy_category == POLICY_CATEGORY_DEFAULT)
361 item_append(i, &p->default_items);
362 else if (policy_category == POLICY_CATEGORY_MANDATORY)
363 item_append(i, &p->mandatory_items);
364 else if (policy_category == POLICY_CATEGORY_ON_CONSOLE)
365 item_append(i, &p->on_console_items);
366 else if (policy_category == POLICY_CATEGORY_NO_CONSOLE)
367 item_append(i, &p->no_console_items);
368 else if (policy_category == POLICY_CATEGORY_USER) {
369 const char *u = policy_user;
370
371 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
372
373 r = hashmap_ensure_allocated(&p->user_items, NULL);
374 if (r < 0)
375 return log_oom();
376
377 if (!u) {
378 log_error("User policy without name");
379 return -EINVAL;
380 }
381
382 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
383 if (r < 0) {
384 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
385 free(i);
386 } else {
387 PolicyItem *first;
388
389 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
390 item_append(i, &first);
391 i->uid_valid = true;
392
393 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
394 if (r < 0) {
395 LIST_REMOVE(items, first, i);
396 return log_oom();
397 }
398 }
399
400 } else if (policy_category == POLICY_CATEGORY_GROUP) {
401 const char *g = policy_group;
402
403 assert_cc(sizeof(gid_t) == sizeof(uint32_t));
404
405 r = hashmap_ensure_allocated(&p->group_items, NULL);
406 if (r < 0)
407 return log_oom();
408
409 if (!g) {
410 log_error("Group policy without name");
411 return -EINVAL;
412 }
413
414 r = get_group_creds(&g, &i->gid);
415 if (r < 0) {
416 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
417 free(i);
418 } else {
419 PolicyItem *first;
420
421 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
422 item_append(i, &first);
423 i->gid_valid = true;
424
425 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
426 if (r < 0) {
427 LIST_REMOVE(items, first, i);
428 return log_oom();
429 }
430 }
431 }
432
433 state = STATE_POLICY;
434 i = NULL;
435
436 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
437 log_error("Unexpected token (8) at %s:%u.", path, line);
438 return -EINVAL;
439 }
440
441 break;
442
443 case STATE_ALLOW_DENY_INTERFACE:
444
445 if (t == XML_ATTRIBUTE_VALUE) {
446 assert(i);
447 if (i->interface) {
448 log_error("Duplicate interface at %s:%u.", path, line);
449 return -EINVAL;
450 }
451
452 if (!streq(name, "*")) {
453 i->interface = name;
454 name = NULL;
455 }
456 state = STATE_ALLOW_DENY;
457 } else {
458 log_error("Unexpected token (9) at %s:%u.", path, line);
459 return -EINVAL;
460 }
461
462 break;
463
464 case STATE_ALLOW_DENY_MEMBER:
465
466 if (t == XML_ATTRIBUTE_VALUE) {
467 assert(i);
468 if (i->member) {
469 log_error("Duplicate member in %s:%u.", path, line);
470 return -EINVAL;
471 }
472
473 if (!streq(name, "*")) {
474 i->member = name;
475 name = NULL;
476 }
477 state = STATE_ALLOW_DENY;
478 } else {
479 log_error("Unexpected token (10) in %s:%u.", path, line);
480 return -EINVAL;
481 }
482
483 break;
484
485 case STATE_ALLOW_DENY_ERROR:
486
487 if (t == XML_ATTRIBUTE_VALUE) {
488 assert(i);
489 if (i->error) {
490 log_error("Duplicate error in %s:%u.", path, line);
491 return -EINVAL;
492 }
493
494 if (!streq(name, "*")) {
495 i->error = name;
496 name = NULL;
497 }
498 state = STATE_ALLOW_DENY;
499 } else {
500 log_error("Unexpected token (11) in %s:%u.", path, line);
501 return -EINVAL;
502 }
503
504 break;
505
506 case STATE_ALLOW_DENY_PATH:
507
508 if (t == XML_ATTRIBUTE_VALUE) {
509 assert(i);
510 if (i->path) {
511 log_error("Duplicate path in %s:%u.", path, line);
512 return -EINVAL;
513 }
514
515 if (!streq(name, "*")) {
516 i->path = name;
517 name = NULL;
518 }
519 state = STATE_ALLOW_DENY;
520 } else {
521 log_error("Unexpected token (12) in %s:%u.", path, line);
522 return -EINVAL;
523 }
524
525 break;
526
527 case STATE_ALLOW_DENY_MESSAGE_TYPE:
528
529 if (t == XML_ATTRIBUTE_VALUE) {
530 assert(i);
531
532 if (i->message_type != 0) {
533 log_error("Duplicate message type in %s:%u.", path, line);
534 return -EINVAL;
535 }
536
537 if (!streq(name, "*")) {
538 r = bus_message_type_from_string(name, &i->message_type);
539 if (r < 0) {
540 log_error("Invalid message type in %s:%u.", path, line);
541 return -EINVAL;
542 }
543 }
544
545 state = STATE_ALLOW_DENY;
546 } else {
547 log_error("Unexpected token (13) in %s:%u.", path, line);
548 return -EINVAL;
549 }
550
551 break;
552
553 case STATE_ALLOW_DENY_NAME:
554
555 if (t == XML_ATTRIBUTE_VALUE) {
556 assert(i);
557 if (i->name) {
558 log_error("Duplicate name in %s:%u.", path, line);
559 return -EINVAL;
560 }
561
562 switch (i->class) {
563 case POLICY_ITEM_USER:
564 if (!streq(name, "*")) {
565 const char *u = name;
566
567 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
568 if (r < 0)
569 log_error_errno(r, "Failed to resolve user %s: %m", name);
570 else
571 i->uid_valid = true;
572 }
573 break;
574 case POLICY_ITEM_GROUP:
575 if (!streq(name, "*")) {
576 const char *g = name;
577
578 r = get_group_creds(&g, &i->gid);
579 if (r < 0)
580 log_error_errno(r, "Failed to resolve group %s: %m", name);
581 else
582 i->gid_valid = true;
583 }
584 break;
585
586 case POLICY_ITEM_SEND:
587 case POLICY_ITEM_RECV:
588
589 if (streq(name, "*")) {
590 free(name);
591 name = NULL;
592 }
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 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 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);