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