chiark / gitweb /
bus-proxy: make sure sure eavesdrop= XML attributes are properly handled
[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                                         ic = POLICY_ITEM_RECV; /* eavesdrop is a type of receive attribute match! */
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 (i->class == _POLICY_ITEM_CLASS_UNSET) {
333                                         log_error("Policy not set at %s:%u.", path, line);
334                                         return -EINVAL;
335                                 }
336
337                                 if (policy_category == POLICY_CATEGORY_DEFAULT)
338                                         item_append(i, &p->default_items);
339                                 else if (policy_category == POLICY_CATEGORY_MANDATORY)
340                                         item_append(i, &p->mandatory_items);
341                                 else if (policy_category == POLICY_CATEGORY_USER) {
342                                         const char *u = policy_user;
343
344                                         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
345
346                                         r = hashmap_ensure_allocated(&p->user_items, NULL);
347                                         if (r < 0)
348                                                 return log_oom();
349
350                                         if (!u) {
351                                                 log_error("User policy without name");
352                                                 return -EINVAL;
353                                         }
354
355                                         r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
356                                         if (r < 0) {
357                                                 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
358                                                 free(i);
359                                         } else {
360                                                 PolicyItem *first;
361
362                                                 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
363                                                 item_append(i, &first);
364                                                 i->uid_valid = true;
365
366                                                 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
367                                                 if (r < 0) {
368                                                         LIST_REMOVE(items, first, i);
369                                                         return log_oom();
370                                                 }
371                                         }
372
373                                 } else if (policy_category == POLICY_CATEGORY_GROUP) {
374                                         const char *g = policy_group;
375
376                                         assert_cc(sizeof(gid_t) == sizeof(uint32_t));
377
378                                         r = hashmap_ensure_allocated(&p->group_items, NULL);
379                                         if (r < 0)
380                                                 return log_oom();
381
382                                         if (!g) {
383                                                 log_error("Group policy without name");
384                                                 return -EINVAL;
385                                         }
386
387                                         r = get_group_creds(&g, &i->gid);
388                                         if (r < 0) {
389                                                 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
390                                                 free(i);
391                                         } else {
392                                                 PolicyItem *first;
393
394                                                 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
395                                                 item_append(i, &first);
396                                                 i->gid_valid = true;
397
398                                                 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
399                                                 if (r < 0) {
400                                                         LIST_REMOVE(items, first, i);
401                                                         return log_oom();
402                                                 }
403                                         }
404                                 }
405
406                                 state = STATE_POLICY;
407                                 i = NULL;
408
409                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
410                                 log_error("Unexpected token (8) at %s:%u.", path, line);
411                                 return -EINVAL;
412                         }
413
414                         break;
415
416                 case STATE_ALLOW_DENY_INTERFACE:
417
418                         if (t == XML_ATTRIBUTE_VALUE) {
419                                 assert(i);
420                                 if (i->interface) {
421                                         log_error("Duplicate interface at %s:%u.", path, line);
422                                         return -EINVAL;
423                                 }
424
425                                 i->interface = name;
426                                 name = NULL;
427                                 state = STATE_ALLOW_DENY;
428                         } else {
429                                 log_error("Unexpected token (9) at %s:%u.", path, line);
430                                 return -EINVAL;
431                         }
432
433                         break;
434
435                 case STATE_ALLOW_DENY_MEMBER:
436
437                         if (t == XML_ATTRIBUTE_VALUE) {
438                                 assert(i);
439                                 if (i->member) {
440                                         log_error("Duplicate member in %s:%u.", path, line);
441                                         return -EINVAL;
442                                 }
443
444                                 i->member = name;
445                                 name = NULL;
446                                 state = STATE_ALLOW_DENY;
447                         } else {
448                                 log_error("Unexpected token (10) in %s:%u.", path, line);
449                                 return -EINVAL;
450                         }
451
452                         break;
453
454                 case STATE_ALLOW_DENY_ERROR:
455
456                         if (t == XML_ATTRIBUTE_VALUE) {
457                                 assert(i);
458                                 if (i->error) {
459                                         log_error("Duplicate error in %s:%u.", path, line);
460                                         return -EINVAL;
461                                 }
462
463                                 i->error = name;
464                                 name = NULL;
465                                 state = STATE_ALLOW_DENY;
466                         } else {
467                                 log_error("Unexpected token (11) in %s:%u.", path, line);
468                                 return -EINVAL;
469                         }
470
471                         break;
472
473                 case STATE_ALLOW_DENY_PATH:
474
475                         if (t == XML_ATTRIBUTE_VALUE) {
476                                 assert(i);
477                                 if (i->path) {
478                                         log_error("Duplicate path in %s:%u.", path, line);
479                                         return -EINVAL;
480                                 }
481
482                                 i->path = name;
483                                 name = NULL;
484                                 state = STATE_ALLOW_DENY;
485                         } else {
486                                 log_error("Unexpected token (12) in %s:%u.", path, line);
487                                 return -EINVAL;
488                         }
489
490                         break;
491
492                 case STATE_ALLOW_DENY_MESSAGE_TYPE:
493
494                         if (t == XML_ATTRIBUTE_VALUE) {
495                                 assert(i);
496
497                                 if (i->message_type != 0) {
498                                         log_error("Duplicate message type in %s:%u.", path, line);
499                                         return -EINVAL;
500                                 }
501
502                                 r = bus_message_type_from_string(name, &i->message_type);
503                                 if (r < 0) {
504                                         log_error("Invalid message type in %s:%u.", path, line);
505                                         return -EINVAL;
506                                 }
507
508                                 state = STATE_ALLOW_DENY;
509                         } else {
510                                 log_error("Unexpected token (13) in %s:%u.", path, line);
511                                 return -EINVAL;
512                         }
513
514                         break;
515
516                 case STATE_ALLOW_DENY_NAME:
517
518                         if (t == XML_ATTRIBUTE_VALUE) {
519                                 assert(i);
520                                 if (i->name) {
521                                         log_error("Duplicate name in %s:%u.", path, line);
522                                         return -EINVAL;
523                                 }
524
525                                 switch (i->class) {
526                                 case POLICY_ITEM_USER:
527                                         if (!streq(name, "*")) {
528                                                 const char *u = name;
529
530                                                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
531                                                 if (r < 0)
532                                                         log_error_errno(r, "Failed to resolve user %s: %m", name);
533                                                 else
534                                                         i->uid_valid = true;
535                                         }
536                                         break;
537                                 case POLICY_ITEM_GROUP:
538                                         if (!streq(name, "*")) {
539                                                 const char *g = name;
540
541                                                 r = get_group_creds(&g, &i->gid);
542                                                 if (r < 0)
543                                                         log_error_errno(r, "Failed to resolve group %s: %m", name);
544                                                 else
545                                                         i->gid_valid = true;
546                                         }
547                                         break;
548                                 default:
549                                         break;
550                                 }
551
552                                 i->name = name;
553                                 name = NULL;
554
555                                 state = STATE_ALLOW_DENY;
556                         } else {
557                                 log_error("Unexpected token (14) in %s:%u.", path, line);
558                                 return -EINVAL;
559                         }
560
561                         break;
562
563                 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
564
565                         if (t == XML_ATTRIBUTE_VALUE)
566                                 state = STATE_ALLOW_DENY;
567                         else {
568                                 log_error("Unexpected token (15) in %s:%u.", path, line);
569                                 return -EINVAL;
570                         }
571
572                         break;
573
574                 case STATE_OTHER:
575
576                         if (t == XML_TAG_OPEN)
577                                 n_other++;
578                         else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
579
580                                 if (n_other == 0)
581                                         state = STATE_BUSCONFIG;
582                                 else
583                                         n_other--;
584                         }
585
586                         break;
587                 }
588         }
589 }
590
591 enum {
592         DENY,
593         ALLOW,
594         DUNNO,
595 };
596
597 static const char *verdict_to_string(int v) {
598         switch (v) {
599
600         case DENY:
601                 return "DENY";
602         case ALLOW:
603                 return "ALLOW";
604         case DUNNO:
605                 return "DUNNO";
606         }
607
608         return NULL;
609 }
610
611 struct policy_check_filter {
612         PolicyItemClass class;
613         uid_t uid;
614         gid_t gid;
615         int message_type;
616         const char *name;
617         const char *interface;
618         const char *path;
619         const char *member;
620 };
621
622 static int is_permissive(PolicyItem *i) {
623
624         assert(i);
625
626         return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
627 }
628
629 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
630
631         assert(i);
632         assert(filter);
633
634         switch (i->class) {
635         case POLICY_ITEM_SEND:
636         case POLICY_ITEM_RECV:
637
638                 if (i->name && !streq_ptr(i->name, filter->name))
639                         break;
640
641                 if ((i->message_type != 0) && (i->message_type != filter->message_type))
642                         break;
643
644                 if (i->path && !streq_ptr(i->path, filter->path))
645                         break;
646
647                 if (i->member && !streq_ptr(i->member, filter->member))
648                         break;
649
650                 if (i->interface && !streq_ptr(i->interface, filter->interface))
651                         break;
652
653                 return is_permissive(i);
654
655         case POLICY_ITEM_OWN:
656                 assert(filter->name);
657
658                 if (streq(i->name, "*") || streq(i->name, filter->name))
659                         return is_permissive(i);
660                 break;
661
662         case POLICY_ITEM_OWN_PREFIX:
663                 assert(filter->name);
664
665                 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
666                         return is_permissive(i);
667                 break;
668
669         case POLICY_ITEM_USER:
670                 if (filter->uid != UID_INVALID)
671                         if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
672                                 return is_permissive(i);
673                 break;
674
675         case POLICY_ITEM_GROUP:
676                 if (filter->gid != GID_INVALID)
677                         if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
678                                 return is_permissive(i);
679                 break;
680
681         case POLICY_ITEM_IGNORE:
682         default:
683                 break;
684         }
685
686         return DUNNO;
687 }
688
689 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
690
691         PolicyItem *i;
692         int verdict = DUNNO;
693
694         assert(filter);
695
696         /* Check all policies in a set - a broader one might be followed by a more specific one,
697          * and the order of rules in policy definitions matters */
698         LIST_FOREACH(items, i, items) {
699                 int v;
700
701                 if (i->class != filter->class &&
702                     !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
703                         continue;
704
705                 v = check_policy_item(i, filter);
706                 if (v != DUNNO)
707                         verdict = v;
708         }
709
710         return verdict;
711 }
712
713 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
714
715         PolicyItem *items;
716         int verdict, v;
717
718         assert(p);
719         assert(filter);
720
721         assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
722
723         /*
724          * The policy check is implemented by the following logic:
725          *
726          *  1. Check default items
727          *  2. Check group items
728          *  3. Check user items
729          *  4. Check mandatory items
730          *
731          *  Later rules override earlier rules.
732          */
733
734         verdict = check_policy_items(p->default_items, filter);
735
736         if (filter->gid != GID_INVALID) {
737                 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
738                 if (items) {
739                         v = check_policy_items(items, filter);
740                         if (v != DUNNO)
741                                 verdict = v;
742                 }
743         }
744
745         if (filter->uid != UID_INVALID) {
746                 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
747                 if (items) {
748                         v = check_policy_items(items, filter);
749                         if (v != DUNNO)
750                                 verdict = v;
751                 }
752         }
753
754         v = check_policy_items(p->mandatory_items, filter);
755         if (v != DUNNO)
756                 verdict = v;
757
758         return verdict;
759 }
760
761 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
762
763         struct policy_check_filter filter = {
764                 .class = POLICY_ITEM_OWN,
765                 .uid   = uid,
766                 .gid   = gid,
767                 .name  = name,
768         };
769
770         int verdict;
771
772         assert(p);
773         assert(name);
774
775         verdict = policy_check(p, &filter);
776
777         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
778                  "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
779                  uid, gid, strna(name), strna(verdict_to_string(verdict)));
780
781         return verdict == ALLOW;
782 }
783
784 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
785
786         struct policy_check_filter filter = {
787                 .uid = uid,
788                 .gid = gid,
789         };
790         int verdict;
791
792         assert(p);
793
794         filter.class = POLICY_ITEM_USER;
795         verdict = policy_check(p, &filter);
796
797         if (verdict != DENY) {
798                 int v;
799
800                 filter.class = POLICY_ITEM_GROUP;
801                 v = policy_check(p, &filter);
802                 if (v != DUNNO)
803                         verdict = v;
804         }
805
806         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
807                  "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
808                  uid, gid, strna(verdict_to_string(verdict)));
809
810         return verdict == ALLOW;
811 }
812
813 bool policy_check_recv(Policy *p,
814                        uid_t uid,
815                        gid_t gid,
816                        int message_type,
817                        const char *name,
818                        const char *path,
819                        const char *interface,
820                        const char *member) {
821
822         struct policy_check_filter filter = {
823                 .class        = POLICY_ITEM_RECV,
824                 .uid          = uid,
825                 .gid          = gid,
826                 .message_type = message_type,
827                 .name         = name,
828                 .interface    = interface,
829                 .path         = path,
830                 .member       = member,
831         };
832
833         int verdict;
834
835         assert(p);
836
837         verdict = policy_check(p, &filter);
838
839         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
840                  "Receive permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
841                  uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
842
843         return verdict == ALLOW;
844 }
845
846 bool policy_check_send(Policy *p,
847                        uid_t uid,
848                        gid_t gid,
849                        int message_type,
850                        const char *name,
851                        const char *path,
852                        const char *interface,
853                        const char *member) {
854
855         struct policy_check_filter filter = {
856                 .class        = POLICY_ITEM_SEND,
857                 .uid          = uid,
858                 .gid          = gid,
859                 .message_type = message_type,
860                 .name         = name,
861                 .interface    = interface,
862                 .path         = path,
863                 .member       = member,
864         };
865
866         int verdict;
867
868         assert(p);
869
870         verdict = policy_check(p, &filter);
871
872         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
873                  "Send permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
874                  uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
875
876         return verdict == ALLOW;
877 }
878
879 int policy_load(Policy *p, char **files) {
880         char **i;
881         int r;
882
883         assert(p);
884
885         STRV_FOREACH(i, files) {
886
887                 r = file_load(p, *i);
888                 if (r == -EISDIR) {
889                         _cleanup_strv_free_ char **l = NULL;
890                         char **j;
891
892                         r = conf_files_list(&l, ".conf", NULL, *i, NULL);
893                         if (r < 0)
894                                 return log_error_errno(r, "Failed to get configuration file list: %m");
895
896                         STRV_FOREACH(j, l)
897                                 file_load(p, *j);
898                 }
899
900                 /* We ignore all errors but EISDIR, and just proceed. */
901         }
902
903         return 0;
904 }
905
906 void policy_free(Policy *p) {
907         PolicyItem *i, *first;
908
909         if (!p)
910                 return;
911
912         while ((i = p->default_items)) {
913                 LIST_REMOVE(items, p->default_items, i);
914                 policy_item_free(i);
915         }
916
917         while ((i = p->mandatory_items)) {
918                 LIST_REMOVE(items, p->mandatory_items, i);
919                 policy_item_free(i);
920         }
921
922         while ((first = hashmap_steal_first(p->user_items))) {
923
924                 while ((i = first)) {
925                         LIST_REMOVE(items, first, i);
926                         policy_item_free(i);
927                 }
928         }
929
930         while ((first = hashmap_steal_first(p->group_items))) {
931
932                 while ((i = first)) {
933                         LIST_REMOVE(items, first, i);
934                         policy_item_free(i);
935                 }
936         }
937
938         hashmap_free(p->user_items);
939         hashmap_free(p->group_items);
940
941         p->user_items = p->group_items = NULL;
942 }
943
944 static void dump_items(PolicyItem *items, const char *prefix) {
945
946         PolicyItem *i;
947
948         if (!items)
949                 return;
950
951         if (!prefix)
952                 prefix = "";
953
954         LIST_FOREACH(items, i, items) {
955
956                 printf("%sType: %s\n"
957                        "%sClass: %s\n",
958                        prefix, policy_item_type_to_string(i->type),
959                        prefix, policy_item_class_to_string(i->class));
960
961                 if (i->interface)
962                         printf("%sInterface: %s\n",
963                                prefix, i->interface);
964
965                 if (i->member)
966                         printf("%sMember: %s\n",
967                                prefix, i->member);
968
969                 if (i->error)
970                         printf("%sError: %s\n",
971                                prefix, i->error);
972
973                 if (i->path)
974                         printf("%sPath: %s\n",
975                                prefix, i->path);
976
977                 if (i->name)
978                         printf("%sName: %s\n",
979                                prefix, i->name);
980
981                 if (i->message_type != 0)
982                         printf("%sMessage Type: %s\n",
983                                prefix, bus_message_type_to_string(i->message_type));
984
985                 if (i->uid_valid) {
986                         _cleanup_free_ char *user;
987
988                         user = uid_to_name(i->uid);
989
990                         printf("%sUser: %s (%d)\n",
991                                prefix, strna(user), i->uid);
992                 }
993
994                 if (i->gid_valid) {
995                         _cleanup_free_ char *group;
996
997                         group = gid_to_name(i->gid);
998
999                         printf("%sGroup: %s (%d)\n",
1000                                prefix, strna(group), i->gid);
1001                 }
1002                 printf("%s-\n", prefix);
1003         }
1004 }
1005
1006 static void dump_hashmap_items(Hashmap *h) {
1007         PolicyItem *i;
1008         Iterator j;
1009         void *k;
1010
1011         HASHMAP_FOREACH_KEY(i, k, h, j) {
1012                 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1013                 dump_items(i, "\t\t");
1014         }
1015 }
1016
1017 void policy_dump(Policy *p) {
1018
1019         printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1020         dump_items(p->default_items, "\t");
1021
1022         printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1023         dump_hashmap_items(p->group_items);
1024
1025         printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1026         dump_hashmap_items(p->user_items);
1027
1028         printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1029         dump_items(p->mandatory_items, "\t");
1030 }
1031
1032 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1033         [_POLICY_ITEM_TYPE_UNSET] = "unset",
1034         [POLICY_ITEM_ALLOW] = "allow",
1035         [POLICY_ITEM_DENY] = "deny",
1036 };
1037 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1038
1039 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1040         [_POLICY_ITEM_CLASS_UNSET] = "unset",
1041         [POLICY_ITEM_SEND] = "send",
1042         [POLICY_ITEM_RECV] = "recv",
1043         [POLICY_ITEM_OWN] = "own",
1044         [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1045         [POLICY_ITEM_USER] = "user",
1046         [POLICY_ITEM_GROUP] = "group",
1047         [POLICY_ITEM_IGNORE] = "ignore",
1048 };
1049 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);