chiark / gitweb /
bus-proxy: share policy between threads
[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 #include "sd-login.h"
30
31 static void policy_item_free(PolicyItem *i) {
32         assert(i);
33
34         free(i->interface);
35         free(i->member);
36         free(i->error);
37         free(i->name);
38         free(i->path);
39         free(i);
40 }
41
42 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
43
44 static void item_append(PolicyItem *i, PolicyItem **list) {
45
46         PolicyItem *tail;
47
48         LIST_FIND_TAIL(items, *list, tail);
49         LIST_INSERT_AFTER(items, *list, tail, i);
50 }
51
52 static int file_load(Policy *p, const char *path) {
53
54         _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
55         _cleanup_(policy_item_freep) PolicyItem *i = NULL;
56         void *xml_state = NULL;
57         unsigned n_other = 0;
58         const char *q;
59         int r;
60
61         enum {
62                 STATE_OUTSIDE,
63                 STATE_BUSCONFIG,
64                 STATE_POLICY,
65                 STATE_POLICY_CONTEXT,
66                 STATE_POLICY_CONSOLE,
67                 STATE_POLICY_USER,
68                 STATE_POLICY_GROUP,
69                 STATE_POLICY_OTHER_ATTRIBUTE,
70                 STATE_ALLOW_DENY,
71                 STATE_ALLOW_DENY_INTERFACE,
72                 STATE_ALLOW_DENY_MEMBER,
73                 STATE_ALLOW_DENY_ERROR,
74                 STATE_ALLOW_DENY_PATH,
75                 STATE_ALLOW_DENY_MESSAGE_TYPE,
76                 STATE_ALLOW_DENY_NAME,
77                 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
78                 STATE_OTHER,
79         } state = STATE_OUTSIDE;
80
81         enum {
82                 POLICY_CATEGORY_NONE,
83                 POLICY_CATEGORY_DEFAULT,
84                 POLICY_CATEGORY_MANDATORY,
85                 POLICY_CATEGORY_ON_CONSOLE,
86                 POLICY_CATEGORY_NO_CONSOLE,
87                 POLICY_CATEGORY_USER,
88                 POLICY_CATEGORY_GROUP
89         } policy_category = POLICY_CATEGORY_NONE;
90
91         unsigned line = 0;
92
93         assert(p);
94
95         r = read_full_file(path, &c, NULL);
96         if (r < 0) {
97                 if (r == -ENOENT)
98                         return 0;
99                 if (r == -EISDIR)
100                         return r;
101
102                 return log_error_errno(r, "Failed to load %s: %m", path);
103         }
104
105         q = c;
106         for (;;) {
107                 _cleanup_free_ char *name = NULL;
108                 int t;
109
110                 t = xml_tokenize(&q, &name, &xml_state, &line);
111                 if (t < 0)
112                         return log_error_errno(t, "XML parse failure in %s: %m", path);
113
114                 switch (state) {
115
116                 case STATE_OUTSIDE:
117
118                         if (t == XML_TAG_OPEN) {
119                                 if (streq(name, "busconfig"))
120                                         state = STATE_BUSCONFIG;
121                                 else {
122                                         log_error("Unexpected tag %s at %s:%u.", name, path, line);
123                                         return -EINVAL;
124                                 }
125
126                         } else if (t == XML_END)
127                                 return 0;
128                         else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
129                                 log_error("Unexpected token (1) at %s:%u.", path, line);
130                                 return -EINVAL;
131                         }
132
133                         break;
134
135                 case STATE_BUSCONFIG:
136
137                         if (t == XML_TAG_OPEN) {
138                                 if (streq(name, "policy")) {
139                                         state = STATE_POLICY;
140                                         policy_category = POLICY_CATEGORY_NONE;
141                                         free(policy_user);
142                                         free(policy_group);
143                                         policy_user = policy_group = NULL;
144                                 } else {
145                                         state = STATE_OTHER;
146                                         n_other = 0;
147                                 }
148                         } else if (t == XML_TAG_CLOSE_EMPTY ||
149                                    (t == XML_TAG_CLOSE && streq(name, "busconfig")))
150                                 state = STATE_OUTSIDE;
151                         else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
152                                 log_error("Unexpected token (2) at %s:%u.", path, line);
153                                 return -EINVAL;
154                         }
155
156                         break;
157
158                 case STATE_POLICY:
159
160                         if (t == XML_ATTRIBUTE_NAME) {
161                                 if (streq(name, "context"))
162                                         state = STATE_POLICY_CONTEXT;
163                                 else if (streq(name, "at_console"))
164                                         state = STATE_POLICY_CONSOLE;
165                                 else if (streq(name, "user"))
166                                         state = STATE_POLICY_USER;
167                                 else if (streq(name, "group"))
168                                         state = STATE_POLICY_GROUP;
169                                 else {
170                                         log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
171                                         state = STATE_POLICY_OTHER_ATTRIBUTE;
172                                 }
173                         } else if (t == XML_TAG_CLOSE_EMPTY ||
174                                    (t == XML_TAG_CLOSE && streq(name, "policy")))
175                                 state = STATE_BUSCONFIG;
176                         else if (t == XML_TAG_OPEN) {
177                                 PolicyItemType it;
178
179                                 if (streq(name, "allow"))
180                                         it = POLICY_ITEM_ALLOW;
181                                 else if (streq(name, "deny"))
182                                         it = POLICY_ITEM_DENY;
183                                 else {
184                                         log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
185                                         return -EINVAL;
186                                 }
187
188                                 assert(!i);
189                                 i = new0(PolicyItem, 1);
190                                 if (!i)
191                                         return log_oom();
192
193                                 i->type = it;
194                                 state = STATE_ALLOW_DENY;
195
196                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
197                                 log_error("Unexpected token (3) at %s:%u.", path, line);
198                                 return -EINVAL;
199                         }
200
201                         break;
202
203                 case STATE_POLICY_CONTEXT:
204
205                         if (t == XML_ATTRIBUTE_VALUE) {
206                                 if (streq(name, "default")) {
207                                         policy_category = POLICY_CATEGORY_DEFAULT;
208                                         state = STATE_POLICY;
209                                 } else if (streq(name, "mandatory")) {
210                                         policy_category = POLICY_CATEGORY_MANDATORY;
211                                         state = STATE_POLICY;
212                                 } else {
213                                         log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
214                                         return -EINVAL;
215                                 }
216                         } else {
217                                 log_error("Unexpected token (4) at %s:%u.", path, line);
218                                 return -EINVAL;
219                         }
220
221                         break;
222
223                 case STATE_POLICY_CONSOLE:
224
225                         if (t == XML_ATTRIBUTE_VALUE) {
226                                 if (streq(name, "true")) {
227                                         policy_category = POLICY_CATEGORY_ON_CONSOLE;
228                                         state = STATE_POLICY;
229                                 } else if (streq(name, "false")) {
230                                         policy_category = POLICY_CATEGORY_NO_CONSOLE;
231                                         state = STATE_POLICY;
232                                 } else {
233                                         log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
234                                         return -EINVAL;
235                                 }
236                         } else {
237                                 log_error("Unexpected token (4.1) at %s:%u.", path, line);
238                                 return -EINVAL;
239                         }
240
241                         break;
242
243                 case STATE_POLICY_USER:
244
245                         if (t == XML_ATTRIBUTE_VALUE) {
246                                 free(policy_user);
247                                 policy_user = name;
248                                 name = NULL;
249                                 policy_category = POLICY_CATEGORY_USER;
250                                 state = STATE_POLICY;
251                         } else {
252                                 log_error("Unexpected token (5) in %s:%u.", path, line);
253                                 return -EINVAL;
254                         }
255
256                         break;
257
258                 case STATE_POLICY_GROUP:
259
260                         if (t == XML_ATTRIBUTE_VALUE) {
261                                 free(policy_group);
262                                 policy_group = name;
263                                 name = NULL;
264                                 policy_category = POLICY_CATEGORY_GROUP;
265                                 state = STATE_POLICY;
266                         } else {
267                                 log_error("Unexpected token (6) at %s:%u.", path, line);
268                                 return -EINVAL;
269                         }
270
271                         break;
272
273                 case STATE_POLICY_OTHER_ATTRIBUTE:
274
275                         if (t == XML_ATTRIBUTE_VALUE)
276                                 state = STATE_POLICY;
277                         else {
278                                 log_error("Unexpected token (7) in %s:%u.", path, line);
279                                 return -EINVAL;
280                         }
281
282                         break;
283
284                 case STATE_ALLOW_DENY:
285
286                         assert(i);
287
288                         if (t == XML_ATTRIBUTE_NAME) {
289                                 PolicyItemClass ic;
290
291                                 if (startswith(name, "send_"))
292                                         ic = POLICY_ITEM_SEND;
293                                 else if (startswith(name, "receive_"))
294                                         ic = POLICY_ITEM_RECV;
295                                 else if (streq(name, "own"))
296                                         ic = POLICY_ITEM_OWN;
297                                 else if (streq(name, "own_prefix"))
298                                         ic = POLICY_ITEM_OWN_PREFIX;
299                                 else if (streq(name, "user"))
300                                         ic = POLICY_ITEM_USER;
301                                 else if (streq(name, "group"))
302                                         ic = POLICY_ITEM_GROUP;
303                                 else if (streq(name, "eavesdrop")) {
304                                         log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
305                                         state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
306                                         break;
307                                 } else {
308                                         log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
309                                         state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
310                                         break;
311                                 }
312
313                                 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
314                                         log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
315                                         return -EINVAL;
316                                 }
317
318                                 i->class = ic;
319
320                                 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
321                                         const char *u;
322
323                                         u = strchr(name, '_');
324                                         assert(u);
325
326                                         u++;
327
328                                         if (streq(u, "interface"))
329                                                 state = STATE_ALLOW_DENY_INTERFACE;
330                                         else if (streq(u, "member"))
331                                                 state = STATE_ALLOW_DENY_MEMBER;
332                                         else if (streq(u, "error"))
333                                                 state = STATE_ALLOW_DENY_ERROR;
334                                         else if (streq(u, "path"))
335                                                 state = STATE_ALLOW_DENY_PATH;
336                                         else if (streq(u, "type"))
337                                                 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
338                                         else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
339                                                  (streq(u, "sender") && ic == POLICY_ITEM_RECV))
340                                                 state = STATE_ALLOW_DENY_NAME;
341                                         else {
342                                                 if (streq(u, "requested_reply"))
343                                                         log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
344                                                 else
345                                                         log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
346                                                 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
347                                                 break;
348                                         }
349                                 } else
350                                         state = STATE_ALLOW_DENY_NAME;
351
352                         } else if (t == XML_TAG_CLOSE_EMPTY ||
353                                    (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
354
355                                 /* If the tag is fully empty so far, we consider it a recv */
356                                 if (i->class == _POLICY_ITEM_CLASS_UNSET)
357                                         i->class = POLICY_ITEM_RECV;
358
359                                 if (policy_category == POLICY_CATEGORY_DEFAULT)
360                                         item_append(i, &p->default_items);
361                                 else if (policy_category == POLICY_CATEGORY_MANDATORY)
362                                         item_append(i, &p->mandatory_items);
363                                 else if (policy_category == POLICY_CATEGORY_ON_CONSOLE)
364                                         item_append(i, &p->on_console_items);
365                                 else if (policy_category == POLICY_CATEGORY_NO_CONSOLE)
366                                         item_append(i, &p->no_console_items);
367                                 else if (policy_category == POLICY_CATEGORY_USER) {
368                                         const char *u = policy_user;
369
370                                         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
371
372                                         r = hashmap_ensure_allocated(&p->user_items, NULL);
373                                         if (r < 0)
374                                                 return log_oom();
375
376                                         if (!u) {
377                                                 log_error("User policy without name");
378                                                 return -EINVAL;
379                                         }
380
381                                         r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
382                                         if (r < 0) {
383                                                 log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
384                                                 free(i);
385                                         } else {
386                                                 PolicyItem *first;
387
388                                                 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
389                                                 item_append(i, &first);
390                                                 i->uid_valid = true;
391
392                                                 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
393                                                 if (r < 0) {
394                                                         LIST_REMOVE(items, first, i);
395                                                         return log_oom();
396                                                 }
397                                         }
398
399                                 } else if (policy_category == POLICY_CATEGORY_GROUP) {
400                                         const char *g = policy_group;
401
402                                         assert_cc(sizeof(gid_t) == sizeof(uint32_t));
403
404                                         r = hashmap_ensure_allocated(&p->group_items, NULL);
405                                         if (r < 0)
406                                                 return log_oom();
407
408                                         if (!g) {
409                                                 log_error("Group policy without name");
410                                                 return -EINVAL;
411                                         }
412
413                                         r = get_group_creds(&g, &i->gid);
414                                         if (r < 0) {
415                                                 log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
416                                                 free(i);
417                                         } else {
418                                                 PolicyItem *first;
419
420                                                 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
421                                                 item_append(i, &first);
422                                                 i->gid_valid = true;
423
424                                                 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
425                                                 if (r < 0) {
426                                                         LIST_REMOVE(items, first, i);
427                                                         return log_oom();
428                                                 }
429                                         }
430                                 }
431
432                                 state = STATE_POLICY;
433                                 i = NULL;
434
435                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
436                                 log_error("Unexpected token (8) at %s:%u.", path, line);
437                                 return -EINVAL;
438                         }
439
440                         break;
441
442                 case STATE_ALLOW_DENY_INTERFACE:
443
444                         if (t == XML_ATTRIBUTE_VALUE) {
445                                 assert(i);
446                                 if (i->interface) {
447                                         log_error("Duplicate interface at %s:%u.", path, line);
448                                         return -EINVAL;
449                                 }
450
451                                 if (!streq(name, "*")) {
452                                         i->interface = name;
453                                         name = NULL;
454                                 }
455                                 state = STATE_ALLOW_DENY;
456                         } else {
457                                 log_error("Unexpected token (9) at %s:%u.", path, line);
458                                 return -EINVAL;
459                         }
460
461                         break;
462
463                 case STATE_ALLOW_DENY_MEMBER:
464
465                         if (t == XML_ATTRIBUTE_VALUE) {
466                                 assert(i);
467                                 if (i->member) {
468                                         log_error("Duplicate member in %s:%u.", path, line);
469                                         return -EINVAL;
470                                 }
471
472                                 if (!streq(name, "*")) {
473                                         i->member = name;
474                                         name = NULL;
475                                 }
476                                 state = STATE_ALLOW_DENY;
477                         } else {
478                                 log_error("Unexpected token (10) in %s:%u.", path, line);
479                                 return -EINVAL;
480                         }
481
482                         break;
483
484                 case STATE_ALLOW_DENY_ERROR:
485
486                         if (t == XML_ATTRIBUTE_VALUE) {
487                                 assert(i);
488                                 if (i->error) {
489                                         log_error("Duplicate error in %s:%u.", path, line);
490                                         return -EINVAL;
491                                 }
492
493                                 if (!streq(name, "*")) {
494                                         i->error = name;
495                                         name = NULL;
496                                 }
497                                 state = STATE_ALLOW_DENY;
498                         } else {
499                                 log_error("Unexpected token (11) in %s:%u.", path, line);
500                                 return -EINVAL;
501                         }
502
503                         break;
504
505                 case STATE_ALLOW_DENY_PATH:
506
507                         if (t == XML_ATTRIBUTE_VALUE) {
508                                 assert(i);
509                                 if (i->path) {
510                                         log_error("Duplicate path in %s:%u.", path, line);
511                                         return -EINVAL;
512                                 }
513
514                                 if (!streq(name, "*")) {
515                                         i->path = name;
516                                         name = NULL;
517                                 }
518                                 state = STATE_ALLOW_DENY;
519                         } else {
520                                 log_error("Unexpected token (12) in %s:%u.", path, line);
521                                 return -EINVAL;
522                         }
523
524                         break;
525
526                 case STATE_ALLOW_DENY_MESSAGE_TYPE:
527
528                         if (t == XML_ATTRIBUTE_VALUE) {
529                                 assert(i);
530
531                                 if (i->message_type != 0) {
532                                         log_error("Duplicate message type in %s:%u.", path, line);
533                                         return -EINVAL;
534                                 }
535
536                                 if (!streq(name, "*")) {
537                                         r = bus_message_type_from_string(name, &i->message_type);
538                                         if (r < 0) {
539                                                 log_error("Invalid message type in %s:%u.", path, line);
540                                                 return -EINVAL;
541                                         }
542                                 }
543
544                                 state = STATE_ALLOW_DENY;
545                         } else {
546                                 log_error("Unexpected token (13) in %s:%u.", path, line);
547                                 return -EINVAL;
548                         }
549
550                         break;
551
552                 case STATE_ALLOW_DENY_NAME:
553
554                         if (t == XML_ATTRIBUTE_VALUE) {
555                                 assert(i);
556                                 if (i->name) {
557                                         log_error("Duplicate name in %s:%u.", path, line);
558                                         return -EINVAL;
559                                 }
560
561                                 switch (i->class) {
562                                 case POLICY_ITEM_USER:
563                                         if (!streq(name, "*")) {
564                                                 const char *u = name;
565
566                                                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
567                                                 if (r < 0)
568                                                         log_error_errno(r, "Failed to resolve user %s: %m", name);
569                                                 else
570                                                         i->uid_valid = true;
571                                         }
572                                         break;
573                                 case POLICY_ITEM_GROUP:
574                                         if (!streq(name, "*")) {
575                                                 const char *g = name;
576
577                                                 r = get_group_creds(&g, &i->gid);
578                                                 if (r < 0)
579                                                         log_error_errno(r, "Failed to resolve group %s: %m", name);
580                                                 else
581                                                         i->gid_valid = true;
582                                         }
583                                         break;
584
585                                 case POLICY_ITEM_SEND:
586                                 case POLICY_ITEM_RECV:
587
588                                         if (streq(name, "*")) {
589                                                 free(name);
590                                                 name = NULL;
591                                         }
592                                         break;
593
594
595                                 default:
596                                         break;
597                                 }
598
599                                 i->name = name;
600                                 name = NULL;
601
602                                 state = STATE_ALLOW_DENY;
603                         } else {
604                                 log_error("Unexpected token (14) in %s:%u.", path, line);
605                                 return -EINVAL;
606                         }
607
608                         break;
609
610                 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
611
612                         if (t == XML_ATTRIBUTE_VALUE)
613                                 state = STATE_ALLOW_DENY;
614                         else {
615                                 log_error("Unexpected token (15) in %s:%u.", path, line);
616                                 return -EINVAL;
617                         }
618
619                         break;
620
621                 case STATE_OTHER:
622
623                         if (t == XML_TAG_OPEN)
624                                 n_other++;
625                         else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
626
627                                 if (n_other == 0)
628                                         state = STATE_BUSCONFIG;
629                                 else
630                                         n_other--;
631                         }
632
633                         break;
634                 }
635         }
636 }
637
638 enum {
639         DENY,
640         ALLOW,
641         DUNNO,
642 };
643
644 static const char *verdict_to_string(int v) {
645         switch (v) {
646
647         case DENY:
648                 return "DENY";
649         case ALLOW:
650                 return "ALLOW";
651         case DUNNO:
652                 return "DUNNO";
653         }
654
655         return NULL;
656 }
657
658 struct policy_check_filter {
659         PolicyItemClass class;
660         uid_t uid;
661         gid_t gid;
662         int message_type;
663         const char *name;
664         const char *interface;
665         const char *path;
666         const char *member;
667 };
668
669 static int is_permissive(PolicyItem *i) {
670
671         assert(i);
672
673         return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
674 }
675
676 static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
677
678         assert(i);
679         assert(filter);
680
681         switch (i->class) {
682         case POLICY_ITEM_SEND:
683         case POLICY_ITEM_RECV:
684
685                 if (i->name && !streq_ptr(i->name, filter->name))
686                         break;
687
688                 if ((i->message_type != 0) && (i->message_type != filter->message_type))
689                         break;
690
691                 if (i->path && !streq_ptr(i->path, filter->path))
692                         break;
693
694                 if (i->member && !streq_ptr(i->member, filter->member))
695                         break;
696
697                 if (i->interface && !streq_ptr(i->interface, filter->interface))
698                         break;
699
700                 return is_permissive(i);
701
702         case POLICY_ITEM_OWN:
703                 assert(filter->name);
704
705                 if (streq(i->name, "*") || streq(i->name, filter->name))
706                         return is_permissive(i);
707                 break;
708
709         case POLICY_ITEM_OWN_PREFIX:
710                 assert(filter->name);
711
712                 if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
713                         return is_permissive(i);
714                 break;
715
716         case POLICY_ITEM_USER:
717                 if (filter->uid != UID_INVALID)
718                         if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
719                                 return is_permissive(i);
720                 break;
721
722         case POLICY_ITEM_GROUP:
723                 if (filter->gid != GID_INVALID)
724                         if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
725                                 return is_permissive(i);
726                 break;
727
728         case POLICY_ITEM_IGNORE:
729         default:
730                 break;
731         }
732
733         return DUNNO;
734 }
735
736 static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
737
738         PolicyItem *i;
739         int verdict = DUNNO;
740
741         assert(filter);
742
743         /* Check all policies in a set - a broader one might be followed by a more specific one,
744          * and the order of rules in policy definitions matters */
745         LIST_FOREACH(items, i, items) {
746                 int v;
747
748                 if (i->class != filter->class &&
749                     !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
750                         continue;
751
752                 v = check_policy_item(i, filter);
753                 if (v != DUNNO)
754                         verdict = v;
755         }
756
757         return verdict;
758 }
759
760 static int policy_check(Policy *p, const struct policy_check_filter *filter) {
761
762         PolicyItem *items;
763         int verdict, v;
764
765         assert(p);
766         assert(filter);
767
768         assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
769
770         /*
771          * The policy check is implemented by the following logic:
772          *
773          *  1. Check default items
774          *  2. Check group items
775          *  3. Check user items
776          *  4. Check on/no_console items
777          *  5. Check mandatory items
778          *
779          *  Later rules override earlier rules.
780          */
781
782         verdict = check_policy_items(p->default_items, filter);
783
784         if (filter->gid != GID_INVALID) {
785                 items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
786                 if (items) {
787                         v = check_policy_items(items, filter);
788                         if (v != DUNNO)
789                                 verdict = v;
790                 }
791         }
792
793         if (filter->uid != UID_INVALID) {
794                 items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
795                 if (items) {
796                         v = check_policy_items(items, filter);
797                         if (v != DUNNO)
798                                 verdict = v;
799                 }
800         }
801
802         if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0)
803                 v = check_policy_items(p->on_console_items, filter);
804         else
805                 v = check_policy_items(p->no_console_items, filter);
806         if (v != DUNNO)
807                 verdict = v;
808
809         v = check_policy_items(p->mandatory_items, filter);
810         if (v != DUNNO)
811                 verdict = v;
812
813         return verdict;
814 }
815
816 bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
817
818         struct policy_check_filter filter = {
819                 .class = POLICY_ITEM_OWN,
820                 .uid   = uid,
821                 .gid   = gid,
822                 .name  = name,
823         };
824
825         int verdict;
826
827         assert(p);
828         assert(name);
829
830         verdict = policy_check(p, &filter);
831
832         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
833                  "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
834                  uid, gid, strna(name), strna(verdict_to_string(verdict)));
835
836         return verdict == ALLOW;
837 }
838
839 bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
840
841         struct policy_check_filter filter = {
842                 .uid = uid,
843                 .gid = gid,
844         };
845         int verdict;
846
847         assert(p);
848
849         filter.class = POLICY_ITEM_USER;
850         verdict = policy_check(p, &filter);
851
852         if (verdict != DENY) {
853                 int v;
854
855                 filter.class = POLICY_ITEM_GROUP;
856                 v = policy_check(p, &filter);
857                 if (v != DUNNO)
858                         verdict = v;
859         }
860
861         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
862                  "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
863                  uid, gid, strna(verdict_to_string(verdict)));
864
865         return verdict == ALLOW;
866 }
867
868 bool policy_check_recv(Policy *p,
869                        uid_t uid,
870                        gid_t gid,
871                        int message_type,
872                        const char *name,
873                        const char *path,
874                        const char *interface,
875                        const char *member,
876                        bool dbus_to_kernel) {
877
878         struct policy_check_filter filter = {
879                 .class        = POLICY_ITEM_RECV,
880                 .uid          = uid,
881                 .gid          = gid,
882                 .message_type = message_type,
883                 .name         = name,
884                 .interface    = interface,
885                 .path         = path,
886                 .member       = member,
887         };
888
889         int verdict;
890
891         assert(p);
892
893         verdict = policy_check(p, &filter);
894
895         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
896                  "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
897                  dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(name),
898                  strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
899
900         return verdict == ALLOW;
901 }
902
903 bool policy_check_send(Policy *p,
904                        uid_t uid,
905                        gid_t gid,
906                        int message_type,
907                        const char *name,
908                        const char *path,
909                        const char *interface,
910                        const char *member,
911                        bool dbus_to_kernel) {
912
913         struct policy_check_filter filter = {
914                 .class        = POLICY_ITEM_SEND,
915                 .uid          = uid,
916                 .gid          = gid,
917                 .message_type = message_type,
918                 .name         = name,
919                 .interface    = interface,
920                 .path         = path,
921                 .member       = member,
922         };
923
924         int verdict;
925
926         assert(p);
927
928         verdict = policy_check(p, &filter);
929
930         log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
931                  "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
932                  dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(name),
933                  strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
934
935         return verdict == ALLOW;
936 }
937
938 int policy_load(Policy *p, char **files) {
939         char **i;
940         int r;
941
942         assert(p);
943
944         STRV_FOREACH(i, files) {
945
946                 r = file_load(p, *i);
947                 if (r == -EISDIR) {
948                         _cleanup_strv_free_ char **l = NULL;
949                         char **j;
950
951                         r = conf_files_list(&l, ".conf", NULL, *i, NULL);
952                         if (r < 0)
953                                 return log_error_errno(r, "Failed to get configuration file list: %m");
954
955                         STRV_FOREACH(j, l)
956                                 file_load(p, *j);
957                 }
958
959                 /* We ignore all errors but EISDIR, and just proceed. */
960         }
961
962         return 0;
963 }
964
965 void policy_free(Policy *p) {
966         PolicyItem *i, *first;
967
968         if (!p)
969                 return;
970
971         while ((i = p->default_items)) {
972                 LIST_REMOVE(items, p->default_items, i);
973                 policy_item_free(i);
974         }
975
976         while ((i = p->mandatory_items)) {
977                 LIST_REMOVE(items, p->mandatory_items, i);
978                 policy_item_free(i);
979         }
980
981         while ((i = p->on_console_items)) {
982                 LIST_REMOVE(items, p->on_console_items, i);
983                 policy_item_free(i);
984         }
985
986         while ((i = p->no_console_items)) {
987                 LIST_REMOVE(items, p->no_console_items, i);
988                 policy_item_free(i);
989         }
990
991         while ((first = hashmap_steal_first(p->user_items))) {
992
993                 while ((i = first)) {
994                         LIST_REMOVE(items, first, i);
995                         policy_item_free(i);
996                 }
997         }
998
999         while ((first = hashmap_steal_first(p->group_items))) {
1000
1001                 while ((i = first)) {
1002                         LIST_REMOVE(items, first, i);
1003                         policy_item_free(i);
1004                 }
1005         }
1006
1007         hashmap_free(p->user_items);
1008         hashmap_free(p->group_items);
1009
1010         p->user_items = p->group_items = NULL;
1011 }
1012
1013 static void dump_items(PolicyItem *items, const char *prefix) {
1014
1015         PolicyItem *i;
1016
1017         if (!items)
1018                 return;
1019
1020         if (!prefix)
1021                 prefix = "";
1022
1023         LIST_FOREACH(items, i, items) {
1024
1025                 printf("%sType: %s\n"
1026                        "%sClass: %s\n",
1027                        prefix, policy_item_type_to_string(i->type),
1028                        prefix, policy_item_class_to_string(i->class));
1029
1030                 if (i->interface)
1031                         printf("%sInterface: %s\n",
1032                                prefix, i->interface);
1033
1034                 if (i->member)
1035                         printf("%sMember: %s\n",
1036                                prefix, i->member);
1037
1038                 if (i->error)
1039                         printf("%sError: %s\n",
1040                                prefix, i->error);
1041
1042                 if (i->path)
1043                         printf("%sPath: %s\n",
1044                                prefix, i->path);
1045
1046                 if (i->name)
1047                         printf("%sName: %s\n",
1048                                prefix, i->name);
1049
1050                 if (i->message_type != 0)
1051                         printf("%sMessage Type: %s\n",
1052                                prefix, bus_message_type_to_string(i->message_type));
1053
1054                 if (i->uid_valid) {
1055                         _cleanup_free_ char *user;
1056
1057                         user = uid_to_name(i->uid);
1058
1059                         printf("%sUser: %s (%d)\n",
1060                                prefix, strna(user), i->uid);
1061                 }
1062
1063                 if (i->gid_valid) {
1064                         _cleanup_free_ char *group;
1065
1066                         group = gid_to_name(i->gid);
1067
1068                         printf("%sGroup: %s (%d)\n",
1069                                prefix, strna(group), i->gid);
1070                 }
1071                 printf("%s-\n", prefix);
1072         }
1073 }
1074
1075 static void dump_hashmap_items(Hashmap *h) {
1076         PolicyItem *i;
1077         Iterator j;
1078         void *k;
1079
1080         HASHMAP_FOREACH_KEY(i, k, h, j) {
1081                 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1082                 dump_items(i, "\t\t");
1083         }
1084 }
1085
1086 void policy_dump(Policy *p) {
1087
1088         printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1089         dump_items(p->default_items, "\t");
1090
1091         printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1092         dump_hashmap_items(p->group_items);
1093
1094         printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1095         dump_hashmap_items(p->user_items);
1096
1097         printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
1098         dump_items(p->on_console_items, "\t");
1099
1100         printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
1101         dump_items(p->no_console_items, "\t");
1102
1103         printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1104         dump_items(p->mandatory_items, "\t");
1105
1106         fflush(stdout);
1107 }
1108
1109 int shared_policy_new(SharedPolicy **out) {
1110         SharedPolicy *sp;
1111         int r;
1112
1113         sp = new0(SharedPolicy, 1);
1114         if (!sp)
1115                 return log_oom();
1116
1117         r = pthread_mutex_init(&sp->lock, NULL);
1118         if (r < 0) {
1119                 log_error_errno(r, "Cannot initialize shared policy mutex: %m");
1120                 goto exit_free;
1121         }
1122
1123         r = pthread_rwlock_init(&sp->rwlock, NULL);
1124         if (r < 0) {
1125                 log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
1126                 goto exit_mutex;
1127         }
1128
1129         *out = sp;
1130         sp = NULL;
1131         return 0;
1132
1133         /* pthread lock destruction is not fail-safe... meh! */
1134 exit_mutex:
1135         pthread_mutex_destroy(&sp->lock);
1136 exit_free:
1137         free(sp);
1138         return r;
1139 }
1140
1141 SharedPolicy *shared_policy_free(SharedPolicy *sp) {
1142         if (!sp)
1143                 return NULL;
1144
1145         policy_free(sp->policy);
1146         pthread_rwlock_destroy(&sp->rwlock);
1147         pthread_mutex_destroy(&sp->lock);
1148         free(sp);
1149
1150         return NULL;
1151 }
1152
1153 static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
1154         Policy old, buffer = {};
1155         bool free_old;
1156         int r;
1157
1158         assert(sp);
1159
1160         r = policy_load(&buffer, configuration);
1161         if (r < 0)
1162                 return log_error_errno(r, "Failed to load policy: %m");
1163
1164         /* policy_dump(&buffer); */
1165
1166         pthread_rwlock_wrlock(&sp->rwlock);
1167         memcpy(&old, &sp->buffer, sizeof(old));
1168         memcpy(&sp->buffer, &buffer, sizeof(buffer));
1169         free_old = !!sp->policy;
1170         sp->policy = &sp->buffer;
1171         pthread_rwlock_unlock(&sp->rwlock);
1172
1173         if (free_old)
1174                 policy_free(&old);
1175
1176         return 0;
1177 }
1178
1179 int shared_policy_reload(SharedPolicy *sp, char **configuration) {
1180         int r;
1181
1182         assert(sp);
1183
1184         pthread_mutex_lock(&sp->lock);
1185         r = shared_policy_reload_unlocked(sp, configuration);
1186         pthread_mutex_unlock(&sp->lock);
1187
1188         return r;
1189 }
1190
1191 int shared_policy_preload(SharedPolicy *sp, char **configuration) {
1192         int r;
1193
1194         assert(sp);
1195
1196         pthread_mutex_lock(&sp->lock);
1197         if (!sp->policy)
1198                 r = shared_policy_reload_unlocked(sp, configuration);
1199         else
1200                 r = 0;
1201         pthread_mutex_unlock(&sp->lock);
1202
1203         return r;
1204 }
1205
1206 Policy *shared_policy_acquire(SharedPolicy *sp) {
1207         assert(sp);
1208
1209         pthread_rwlock_rdlock(&sp->rwlock);
1210         if (sp->policy)
1211                 return sp->policy;
1212         pthread_rwlock_unlock(&sp->rwlock);
1213
1214         return NULL;
1215 }
1216
1217 void shared_policy_release(SharedPolicy *sp, Policy *p) {
1218         assert(sp);
1219         assert(!p || sp->policy == p);
1220
1221         if (p)
1222                 pthread_rwlock_unlock(&sp->rwlock);
1223 }
1224
1225 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1226         [_POLICY_ITEM_TYPE_UNSET] = "unset",
1227         [POLICY_ITEM_ALLOW] = "allow",
1228         [POLICY_ITEM_DENY] = "deny",
1229 };
1230 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1231
1232 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1233         [_POLICY_ITEM_CLASS_UNSET] = "unset",
1234         [POLICY_ITEM_SEND] = "send",
1235         [POLICY_ITEM_RECV] = "recv",
1236         [POLICY_ITEM_OWN] = "own",
1237         [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1238         [POLICY_ITEM_USER] = "user",
1239         [POLICY_ITEM_GROUP] = "group",
1240         [POLICY_ITEM_IGNORE] = "ignore",
1241 };
1242 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);