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