chiark / gitweb /
remove unused includes
[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 "set.h"
26 #include "conf-files.h"
27 #include "bus-internal.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_one_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
877         struct policy_check_filter filter = {
878                 .class        = POLICY_ITEM_RECV,
879                 .uid          = uid,
880                 .gid          = gid,
881                 .message_type = message_type,
882                 .name         = name,
883                 .interface    = interface,
884                 .path         = path,
885                 .member       = member,
886         };
887
888         assert(p);
889
890         return policy_check(p, &filter) == ALLOW;
891 }
892
893 bool policy_check_recv(Policy *p,
894                        uid_t uid,
895                        gid_t gid,
896                        int message_type,
897                        Set *names,
898                        char **namesv,
899                        const char *path,
900                        const char *interface,
901                        const char *member,
902                        bool dbus_to_kernel) {
903
904         char *n, **nv, *last = NULL;
905         bool allow = false;
906         Iterator i;
907
908         assert(p);
909
910         if (set_isempty(names) && strv_isempty(namesv)) {
911                 allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member);
912         } else {
913                 SET_FOREACH(n, names, i) {
914                         last = n;
915                         allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member);
916                         if (allow)
917                                 break;
918                 }
919                 if (!allow) {
920                         STRV_FOREACH(nv, namesv) {
921                                 last = *nv;
922                                 allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member);
923                                 if (allow)
924                                         break;
925                         }
926                 }
927         }
928
929         log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
930                  "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
931                  dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
932                  strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
933
934         return allow;
935 }
936
937 bool policy_check_one_send(Policy *p,
938                            uid_t uid,
939                            gid_t gid,
940                            int message_type,
941                            const char *name,
942                            const char *path,
943                            const char *interface,
944                            const char *member) {
945
946         struct policy_check_filter filter = {
947                 .class        = POLICY_ITEM_SEND,
948                 .uid          = uid,
949                 .gid          = gid,
950                 .message_type = message_type,
951                 .name         = name,
952                 .interface    = interface,
953                 .path         = path,
954                 .member       = member,
955         };
956
957         assert(p);
958
959         return policy_check(p, &filter) == ALLOW;
960 }
961
962 bool policy_check_send(Policy *p,
963                        uid_t uid,
964                        gid_t gid,
965                        int message_type,
966                        Set *names,
967                        char **namesv,
968                        const char *path,
969                        const char *interface,
970                        const char *member,
971                        bool dbus_to_kernel,
972                        char **out_used_name) {
973
974         char *n, **nv, *last = NULL;
975         bool allow = false;
976         Iterator i;
977
978         assert(p);
979
980         if (set_isempty(names) && strv_isempty(namesv)) {
981                 allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member);
982         } else {
983                 SET_FOREACH(n, names, i) {
984                         last = n;
985                         allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member);
986                         if (allow)
987                                 break;
988                 }
989                 if (!allow) {
990                         STRV_FOREACH(nv, namesv) {
991                                 last = *nv;
992                                 allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member);
993                                 if (allow)
994                                         break;
995                         }
996                 }
997         }
998
999         if (out_used_name)
1000                 *out_used_name = last;
1001
1002         log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
1003                  "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
1004                  dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
1005                  strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
1006
1007         return allow;
1008 }
1009
1010 int policy_load(Policy *p, char **files) {
1011         char **i;
1012         int r;
1013
1014         assert(p);
1015
1016         STRV_FOREACH(i, files) {
1017
1018                 r = file_load(p, *i);
1019                 if (r == -EISDIR) {
1020                         _cleanup_strv_free_ char **l = NULL;
1021                         char **j;
1022
1023                         r = conf_files_list(&l, ".conf", NULL, *i, NULL);
1024                         if (r < 0)
1025                                 return log_error_errno(r, "Failed to get configuration file list: %m");
1026
1027                         STRV_FOREACH(j, l)
1028                                 file_load(p, *j);
1029                 }
1030
1031                 /* We ignore all errors but EISDIR, and just proceed. */
1032         }
1033
1034         return 0;
1035 }
1036
1037 void policy_free(Policy *p) {
1038         PolicyItem *i, *first;
1039
1040         if (!p)
1041                 return;
1042
1043         while ((i = p->default_items)) {
1044                 LIST_REMOVE(items, p->default_items, i);
1045                 policy_item_free(i);
1046         }
1047
1048         while ((i = p->mandatory_items)) {
1049                 LIST_REMOVE(items, p->mandatory_items, i);
1050                 policy_item_free(i);
1051         }
1052
1053         while ((i = p->on_console_items)) {
1054                 LIST_REMOVE(items, p->on_console_items, i);
1055                 policy_item_free(i);
1056         }
1057
1058         while ((i = p->no_console_items)) {
1059                 LIST_REMOVE(items, p->no_console_items, i);
1060                 policy_item_free(i);
1061         }
1062
1063         while ((first = hashmap_steal_first(p->user_items))) {
1064
1065                 while ((i = first)) {
1066                         LIST_REMOVE(items, first, i);
1067                         policy_item_free(i);
1068                 }
1069         }
1070
1071         while ((first = hashmap_steal_first(p->group_items))) {
1072
1073                 while ((i = first)) {
1074                         LIST_REMOVE(items, first, i);
1075                         policy_item_free(i);
1076                 }
1077         }
1078
1079         hashmap_free(p->user_items);
1080         hashmap_free(p->group_items);
1081
1082         p->user_items = p->group_items = NULL;
1083 }
1084
1085 static void dump_items(PolicyItem *items, const char *prefix) {
1086
1087         PolicyItem *i;
1088
1089         if (!items)
1090                 return;
1091
1092         if (!prefix)
1093                 prefix = "";
1094
1095         LIST_FOREACH(items, i, items) {
1096
1097                 printf("%sType: %s\n"
1098                        "%sClass: %s\n",
1099                        prefix, policy_item_type_to_string(i->type),
1100                        prefix, policy_item_class_to_string(i->class));
1101
1102                 if (i->interface)
1103                         printf("%sInterface: %s\n",
1104                                prefix, i->interface);
1105
1106                 if (i->member)
1107                         printf("%sMember: %s\n",
1108                                prefix, i->member);
1109
1110                 if (i->error)
1111                         printf("%sError: %s\n",
1112                                prefix, i->error);
1113
1114                 if (i->path)
1115                         printf("%sPath: %s\n",
1116                                prefix, i->path);
1117
1118                 if (i->name)
1119                         printf("%sName: %s\n",
1120                                prefix, i->name);
1121
1122                 if (i->message_type != 0)
1123                         printf("%sMessage Type: %s\n",
1124                                prefix, bus_message_type_to_string(i->message_type));
1125
1126                 if (i->uid_valid) {
1127                         _cleanup_free_ char *user;
1128
1129                         user = uid_to_name(i->uid);
1130
1131                         printf("%sUser: %s ("UID_FMT")\n",
1132                                prefix, strna(user), i->uid);
1133                 }
1134
1135                 if (i->gid_valid) {
1136                         _cleanup_free_ char *group;
1137
1138                         group = gid_to_name(i->gid);
1139
1140                         printf("%sGroup: %s ("GID_FMT")\n",
1141                                prefix, strna(group), i->gid);
1142                 }
1143                 printf("%s-\n", prefix);
1144         }
1145 }
1146
1147 static void dump_hashmap_items(Hashmap *h) {
1148         PolicyItem *i;
1149         Iterator j;
1150         void *k;
1151
1152         HASHMAP_FOREACH_KEY(i, k, h, j) {
1153                 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
1154                 dump_items(i, "\t\t");
1155         }
1156 }
1157
1158 void policy_dump(Policy *p) {
1159
1160         printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
1161         dump_items(p->default_items, "\t");
1162
1163         printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
1164         dump_hashmap_items(p->group_items);
1165
1166         printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
1167         dump_hashmap_items(p->user_items);
1168
1169         printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
1170         dump_items(p->on_console_items, "\t");
1171
1172         printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
1173         dump_items(p->no_console_items, "\t");
1174
1175         printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
1176         dump_items(p->mandatory_items, "\t");
1177
1178         fflush(stdout);
1179 }
1180
1181 int shared_policy_new(SharedPolicy **out) {
1182         SharedPolicy *sp;
1183         int r;
1184
1185         sp = new0(SharedPolicy, 1);
1186         if (!sp)
1187                 return log_oom();
1188
1189         r = pthread_mutex_init(&sp->lock, NULL);
1190         if (r < 0) {
1191                 log_error_errno(r, "Cannot initialize shared policy mutex: %m");
1192                 goto exit_free;
1193         }
1194
1195         r = pthread_rwlock_init(&sp->rwlock, NULL);
1196         if (r < 0) {
1197                 log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
1198                 goto exit_mutex;
1199         }
1200
1201         *out = sp;
1202         sp = NULL;
1203         return 0;
1204
1205         /* pthread lock destruction is not fail-safe... meh! */
1206 exit_mutex:
1207         pthread_mutex_destroy(&sp->lock);
1208 exit_free:
1209         free(sp);
1210         return r;
1211 }
1212
1213 SharedPolicy *shared_policy_free(SharedPolicy *sp) {
1214         if (!sp)
1215                 return NULL;
1216
1217         policy_free(sp->policy);
1218         pthread_rwlock_destroy(&sp->rwlock);
1219         pthread_mutex_destroy(&sp->lock);
1220         strv_free(sp->configuration);
1221         free(sp);
1222
1223         return NULL;
1224 }
1225
1226 static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
1227         Policy old, buffer = {};
1228         bool free_old;
1229         int r;
1230
1231         assert(sp);
1232
1233         r = policy_load(&buffer, configuration);
1234         if (r < 0)
1235                 return log_error_errno(r, "Failed to load policy: %m");
1236
1237         log_debug("Reloading configuration");
1238         /* policy_dump(&buffer); */
1239
1240         pthread_rwlock_wrlock(&sp->rwlock);
1241         memcpy(&old, &sp->buffer, sizeof(old));
1242         memcpy(&sp->buffer, &buffer, sizeof(buffer));
1243         free_old = !!sp->policy;
1244         sp->policy = &sp->buffer;
1245         pthread_rwlock_unlock(&sp->rwlock);
1246
1247         if (free_old)
1248                 policy_free(&old);
1249
1250         return 0;
1251 }
1252
1253 int shared_policy_reload(SharedPolicy *sp) {
1254         int r;
1255
1256         assert(sp);
1257
1258         pthread_mutex_lock(&sp->lock);
1259         r = shared_policy_reload_unlocked(sp, sp->configuration);
1260         pthread_mutex_unlock(&sp->lock);
1261
1262         return r;
1263 }
1264
1265 int shared_policy_preload(SharedPolicy *sp, char **configuration) {
1266         _cleanup_strv_free_ char **conf = NULL;
1267         int r = 0;
1268
1269         assert(sp);
1270
1271         conf = strv_copy(configuration);
1272         if (!conf)
1273                 return log_oom();
1274
1275         pthread_mutex_lock(&sp->lock);
1276         if (!sp->policy) {
1277                 r = shared_policy_reload_unlocked(sp, conf);
1278                 if (r >= 0) {
1279                         sp->configuration = conf;
1280                         conf = NULL;
1281                 }
1282         }
1283         pthread_mutex_unlock(&sp->lock);
1284
1285         return r;
1286 }
1287
1288 Policy *shared_policy_acquire(SharedPolicy *sp) {
1289         assert(sp);
1290
1291         pthread_rwlock_rdlock(&sp->rwlock);
1292         if (sp->policy)
1293                 return sp->policy;
1294         pthread_rwlock_unlock(&sp->rwlock);
1295
1296         return NULL;
1297 }
1298
1299 void shared_policy_release(SharedPolicy *sp, Policy *p) {
1300         assert(sp);
1301         assert(!p || sp->policy == p);
1302
1303         if (p)
1304                 pthread_rwlock_unlock(&sp->rwlock);
1305 }
1306
1307 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
1308         [_POLICY_ITEM_TYPE_UNSET] = "unset",
1309         [POLICY_ITEM_ALLOW] = "allow",
1310         [POLICY_ITEM_DENY] = "deny",
1311 };
1312 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
1313
1314 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
1315         [_POLICY_ITEM_CLASS_UNSET] = "unset",
1316         [POLICY_ITEM_SEND] = "send",
1317         [POLICY_ITEM_RECV] = "recv",
1318         [POLICY_ITEM_OWN] = "own",
1319         [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
1320         [POLICY_ITEM_USER] = "user",
1321         [POLICY_ITEM_GROUP] = "group",
1322         [POLICY_ITEM_IGNORE] = "ignore",
1323 };
1324 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);