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