LCOV - code coverage report
Current view: top level - bus-proxyd - bus-xml-policy.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 386 663 58.2 %
Date: 2015-07-29 18:47:03 Functions: 22 31 71.0 %

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

Generated by: LCOV version 1.11