bus-policy.c revision f5d8989ce5fc4e6eb338ec7b1b2c6d6a74c44c63
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering This file is part of systemd.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Copyright 2013 Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (at your option) any later version.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is distributed in the hope that it will be useful, but
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Lesser General Public License for more details.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void policy_item_free(PolicyItem *i) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void item_append(PolicyItem *i, PolicyItem **list) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering LIST_INSERT_AFTER(items, *list, tail, i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int file_load(Policy *p, const char *path) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_(policy_item_freep) PolicyItem *i = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *q;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } policy_category = POLICY_CATEGORY_NONE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to load %s: %s", path, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering t = xml_tokenize(&q, &name, &xml_state, &line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("XML parse failure in %s: %s", path, strerror(-t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected tag %s at %s:%u.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_END)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (1) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_TAG_CLOSE_EMPTY ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (t == XML_TAG_CLOSE && streq(name, "busconfig")))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (2) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Attribute %s of <policy> tag unsupported at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_TAG_CLOSE_EMPTY ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (t == XML_TAG_CLOSE && streq(name, "policy")))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (t == XML_TAG_OPEN) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (3) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_category = POLICY_CATEGORY_DEFAULT;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_category = POLICY_CATEGORY_MANDATORY;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (4) at %s:%u.", path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_category = POLICY_CATEGORY_USER;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (5) in %s:%u.", path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_category = POLICY_CATEGORY_GROUP;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (6) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (7) in %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *u;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (streq(u, "sender") && ic == POLICY_ITEM_RECV))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_TAG_CLOSE_EMPTY ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (i->class == _POLICY_ITEM_CLASS_UNSET) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Policy not set at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (policy_category == POLICY_CATEGORY_DEFAULT)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (policy_category == POLICY_CATEGORY_MANDATORY)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (policy_category == POLICY_CATEGORY_USER) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *u = policy_user;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert_cc(sizeof(uid_t) == sizeof(uint32_t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_ensure_allocated(&p->user_items, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (policy_category == POLICY_CATEGORY_GROUP) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *g = policy_group;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert_cc(sizeof(gid_t) == sizeof(uint32_t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_ensure_allocated(&p->group_items, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (8) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Duplicate interface at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (9) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Duplicate member in %s:%u.", path, line);
return -EINVAL;
case STATE_ALLOW_DENY_ERROR:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->error) {
return -EINVAL;
return -EINVAL;
case STATE_ALLOW_DENY_PATH:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->path) {
return -EINVAL;
return -EINVAL;
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->message_type != 0) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
case STATE_ALLOW_DENY_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->name) {
return -EINVAL;
switch (i->class) {
case POLICY_ITEM_USER:
const char *u = name;
i->uid_valid = true;
case POLICY_ITEM_GROUP:
const char *g = name;
i->gid_valid = true;
return -EINVAL;
if (t == XML_ATTRIBUTE_VALUE)
return -EINVAL;
case STATE_OTHER:
if (t == XML_TAG_OPEN)
n_other++;
if (n_other == 0)
n_other--;
DENY,
struct policy_check_filter {
int class;
int message_type;
const char *name;
const char *interface;
const char *path;
const char *member;
assert(i);
assert(i);
switch (i->class) {
case POLICY_ITEM_SEND:
case POLICY_ITEM_RECV:
return is_permissive(i);
case POLICY_ITEM_OWN:
return is_permissive(i);
case POLICY_ITEM_OWN_PREFIX:
return is_permissive(i);
case POLICY_ITEM_USER:
return is_permissive(i);
case POLICY_ITEM_GROUP:
return is_permissive(i);
case POLICY_ITEM_IGNORE:
return DUNNO;
PolicyItem *i;
if (r != DUNNO)
ret = r;
return ret;
assert(p);
* 2. See if the passed ucred match against the user/group hashmaps. A matching entry is also decisive.
if (r != DUNNO)
if (items) {
if (r != DUNNO)
if (items) {
if (r != DUNNO)
int message_type,
const char *name,
const char *path,
const char *interface,
const char *member) {
int message_type,
const char *name,
const char *path,
const char *interface,
const char *member) {
assert(p);
r = file_load(p, *i);
if (r == -EISDIR) {
STRV_FOREACH(j, l)
file_load(p, *j);
while ((i = p->default_items)) {
policy_item_free(i);
while ((i = p->mandatory_items)) {
policy_item_free(i);
while ((i = first)) {
policy_item_free(i);
while ((i = first)) {
policy_item_free(i);
PolicyItem *i;
if (!items)
if (!prefix)
if (i->interface)
if (i->member)
if (i->error)
if (i->path)
if (i->name)
if (i->message_type != 0)
if (i->uid_valid) {
if (i->gid_valid) {
PolicyItem *i;
Iterator j;
HASHMAP_FOREACH_KEY(i, k, h, j) {