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