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