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