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