bus-policy.c revision f5d8989ce5fc4e6eb338ec7b1b2c6d6a74c44c63
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/***
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering This file is part of systemd.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Copyright 2013 Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart 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
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
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 Poettering***/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger#include "xml.h"
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger#include "fileio.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "strv.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "conf-files.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "bus-internal.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "bus-message.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "bus-policy.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void policy_item_free(PolicyItem *i) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i->interface);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i->member);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i->error);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i->name);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i->path);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering}
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void item_append(PolicyItem *i, PolicyItem **list) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering PolicyItem *tail;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering LIST_FIND_TAIL(items, *list, tail);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering LIST_INSERT_AFTER(items, *list, tail, i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering}
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int file_load(Policy *p, const char *path) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_(policy_item_freep) PolicyItem *i = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering void *xml_state = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering unsigned n_other = 0;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *q;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering int r;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering enum {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_OUTSIDE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_BUSCONFIG,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_POLICY,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_POLICY_CONTEXT,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_POLICY_USER,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_POLICY_GROUP,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_POLICY_OTHER_ATTRIBUTE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_INTERFACE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_MEMBER,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_ERROR,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_PATH,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_MESSAGE_TYPE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_NAME,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering STATE_OTHER,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } state = STATE_OUTSIDE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering enum {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering POLICY_CATEGORY_NONE,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering POLICY_CATEGORY_DEFAULT,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering POLICY_CATEGORY_MANDATORY,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering POLICY_CATEGORY_USER,
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering POLICY_CATEGORY_GROUP
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } policy_category = POLICY_CATEGORY_NONE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering unsigned line = 0;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(p);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = read_full_file(path, &c, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r == -ENOENT)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return 0;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r == -EISDIR)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return r;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to load %s: %s", path, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return r;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering q = c;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering for (;;) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_free_ char *name = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering int t;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering t = xml_tokenize(&q, &name, &xml_state, &line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("XML parse failure in %s: %s", path, strerror(-t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return t;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering switch (state) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_OUTSIDE:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_TAG_OPEN) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "busconfig"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_BUSCONFIG;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected tag %s at %s:%u.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_END)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return 0;
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 return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_BUSCONFIG:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_TAG_OPEN) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "policy")) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_category = POLICY_CATEGORY_NONE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(policy_user);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(policy_group);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_user = policy_group = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_OTHER;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering n_other = 0;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_TAG_CLOSE_EMPTY ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (t == XML_TAG_CLOSE && streq(name, "busconfig")))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_OUTSIDE;
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 return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_POLICY:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_NAME) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "context"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY_CONTEXT;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "user"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY_USER;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "group"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY_GROUP;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "at_console"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Attribute %s of <policy> tag unsupported at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (t == XML_TAG_CLOSE_EMPTY ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (t == XML_TAG_CLOSE && streq(name, "policy")))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_BUSCONFIG;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (t == XML_TAG_OPEN) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering PolicyItemType it;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "allow"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering it = POLICY_ITEM_ALLOW;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "deny"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering it = POLICY_ITEM_DENY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(!i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i = new0(PolicyItem, 1);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (!i)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return log_oom();
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->type = it;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
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 return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_POLICY_CONTEXT:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_VALUE) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(name, "default")) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_category = POLICY_CATEGORY_DEFAULT;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (streq(name, "mandatory")) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering policy_category = POLICY_CATEGORY_MANDATORY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger } else {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger return -EINVAL;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger }
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger } else {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (4) at %s:%u.", path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger return -EINVAL;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger }
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger break;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger case STATE_POLICY_USER:
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger if (t == XML_ATTRIBUTE_VALUE) {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger free(policy_user);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_user = name;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger name = NULL;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_category = POLICY_CATEGORY_USER;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger state = STATE_POLICY;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger } else {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (5) in %s:%u.", path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger return -EINVAL;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger }
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger break;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger case STATE_POLICY_GROUP:
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger if (t == XML_ATTRIBUTE_VALUE) {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger free(policy_group);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_group = name;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger name = NULL;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger policy_category = POLICY_CATEGORY_GROUP;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger state = STATE_POLICY;
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger } else {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Unexpected token (6) at %s:%u.", path, line);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_POLICY_OTHER_ATTRIBUTE:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_VALUE)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (7) in %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_ALLOW_DENY:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_NAME) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering PolicyItemClass ic;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (startswith(name, "send_"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_SEND;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (startswith(name, "receive_"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_RECV;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "own"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_OWN;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "own_prefix"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_OWN_PREFIX;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "user"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_USER;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "group"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering ic = POLICY_ITEM_GROUP;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(name, "eavesdrop")) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->class = POLICY_ITEM_IGNORE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
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 return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->class = ic;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *u;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering u = strchr(name, '_');
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(u);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering u++;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(u, "interface"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_INTERFACE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(u, "member"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_MEMBER;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(u, "error"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_ERROR;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(u, "path"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_PATH;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (streq(u, "type"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_MESSAGE_TYPE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (streq(u, "sender") && ic == POLICY_ITEM_RECV))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_NAME;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (streq(u, "requested_reply"))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY_NAME;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
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
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (i->class == _POLICY_ITEM_CLASS_UNSET) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Policy not set at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (policy_category == POLICY_CATEGORY_DEFAULT)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering item_append(i, &p->default_items);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (policy_category == POLICY_CATEGORY_MANDATORY)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering item_append(i, &p->mandatory_items);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering else if (policy_category == POLICY_CATEGORY_USER) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *u = policy_user;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert_cc(sizeof(uid_t) == sizeof(uint32_t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_ensure_allocated(&p->user_items, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return log_oom();
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (!u) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("User policy without name");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering PolicyItem *first;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering item_append(i, &first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->uid_valid = true;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering LIST_REMOVE(items, first, i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return log_oom();
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (policy_category == POLICY_CATEGORY_GROUP) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *g = policy_group;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert_cc(sizeof(gid_t) == sizeof(uint32_t));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_ensure_allocated(&p->group_items, NULL);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return log_oom();
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (!g) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Group policy without name");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = get_group_creds(&g, &i->gid);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering free(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering PolicyItem *first;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering item_append(i, &first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->gid_valid = true;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (r < 0) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering LIST_REMOVE(items, first, i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return log_oom();
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_POLICY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
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 return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_ALLOW_DENY_INTERFACE:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_VALUE) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (i->interface) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Duplicate interface at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering i->interface = name;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering name = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering state = STATE_ALLOW_DENY;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Unexpected token (9) at %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering break;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering case STATE_ALLOW_DENY_MEMBER:
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (t == XML_ATTRIBUTE_VALUE) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering assert(i);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (i->member) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Duplicate member in %s:%u.", path, line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering return -EINVAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering }
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
i->member = name;
name = NULL;
state = STATE_ALLOW_DENY;
} else {
log_error("Unexpected token (10) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_ALLOW_DENY_ERROR:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->error) {
log_error("Duplicate error in %s:%u.", path, line);
return -EINVAL;
}
i->error = name;
name = NULL;
state = STATE_ALLOW_DENY;
} else {
log_error("Unexpected token (11) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_ALLOW_DENY_PATH:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->path) {
log_error("Duplicate path in %s:%u.", path, line);
return -EINVAL;
}
i->path = name;
name = NULL;
state = STATE_ALLOW_DENY;
} else {
log_error("Unexpected token (12) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_ALLOW_DENY_MESSAGE_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->message_type != 0) {
log_error("Duplicate message type in %s:%u.", path, line);
return -EINVAL;
}
r = bus_message_type_from_string(name, &i->message_type);
if (r < 0) {
log_error("Invalid message type in %s:%u.", path, line);
return -EINVAL;
}
state = STATE_ALLOW_DENY;
} else {
log_error("Unexpected token (13) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_ALLOW_DENY_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
assert(i);
if (i->name) {
log_error("Duplicate name in %s:%u.", path, line);
return -EINVAL;
}
switch (i->class) {
case POLICY_ITEM_USER:
if (!streq(name, "*")) {
const char *u = name;
r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
if (r < 0)
log_error("Failed to resolve user %s: %s", name, strerror(-r));
else
i->uid_valid = true;
}
break;
case POLICY_ITEM_GROUP:
if (!streq(name, "*")) {
const char *g = name;
r = get_group_creds(&g, &i->gid);
if (r < 0)
log_error("Failed to resolve group %s: %s", name, strerror(-r));
else
i->gid_valid = true;
}
break;
default:
break;
}
i->name = name;
name = NULL;
state = STATE_ALLOW_DENY;
} else {
log_error("Unexpected token (14) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
if (t == XML_ATTRIBUTE_VALUE)
state = STATE_ALLOW_DENY;
else {
log_error("Unexpected token (15) in %s:%u.", path, line);
return -EINVAL;
}
break;
case STATE_OTHER:
if (t == XML_TAG_OPEN)
n_other++;
else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
if (n_other == 0)
state = STATE_BUSCONFIG;
else
n_other--;
}
break;
}
}
}
enum {
ALLOW,
DUNNO,
DENY,
};
struct policy_check_filter {
int class;
const struct ucred *ucred;
int message_type;
const char *name;
const char *interface;
const char *path;
const char *member;
};
static int is_permissive(PolicyItem *i) {
assert(i);
return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
}
static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
assert(i);
assert(filter);
switch (i->class) {
case POLICY_ITEM_SEND:
case POLICY_ITEM_RECV:
if (i->name && !streq_ptr(i->name, filter->name))
break;
if ((i->message_type != _POLICY_ITEM_CLASS_UNSET) && (i->message_type != filter->message_type))
break;
if (i->path && !streq_ptr(i->path, filter->path))
break;
if (i->member && !streq_ptr(i->member, filter->member))
break;
if (i->interface && !streq_ptr(i->interface, filter->interface))
break;
return is_permissive(i);
case POLICY_ITEM_OWN:
assert(filter->name);
if (streq(i->name, "*") || streq(i->name, filter->name))
return is_permissive(i);
break;
case POLICY_ITEM_OWN_PREFIX:
assert(filter->name);
if (streq(i->name, "*") || service_name_startswith(i->name, filter->name))
return is_permissive(i);
break;
case POLICY_ITEM_USER:
assert(filter->ucred);
if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->ucred->uid)))
return is_permissive(i);
break;
case POLICY_ITEM_GROUP:
assert(filter->ucred);
if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->ucred->gid)))
return is_permissive(i);
break;
case POLICY_ITEM_IGNORE:
default:
break;
}
return DUNNO;
}
static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
PolicyItem *i;
int r, ret = DUNNO;
assert(filter);
/* Check all policies in a set - a broader one might be followed by a more specific one,
* and the order of rules in policy definitions matters */
LIST_FOREACH(items, i, items) {
if (i->class != filter->class)
continue;
r = check_policy_item(i, filter);
if (r != DUNNO)
ret = r;
}
return ret;
}
static int policy_check(Policy *p, const struct policy_check_filter *filter) {
PolicyItem *items;
int r;
assert(p);
assert(filter);
/*
* The policy check is implemented by the following logic:
*
* 1. Check mandatory items. If the message matches any of these, it is decisive.
* 2. See if the passed ucred match against the user/group hashmaps. A matching entry is also decisive.
* 3. Consult the defaults if non of the above matched with a more specific rule.
* 4. If the message isn't caught be the defaults either, reject it.
*/
r = check_policy_items(p->mandatory_items, filter);
if (r != DUNNO)
return r;
if (filter->ucred) {
items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->ucred->uid));
if (items) {
r = check_policy_items(items, filter);
if (r != DUNNO)
return r;
}
items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->ucred->gid));
if (items) {
r = check_policy_items(items, filter);
if (r != DUNNO)
return r;
}
}
return check_policy_items(p->default_items, filter);
}
bool policy_check_own(Policy *p, const struct ucred *ucred, const char *name) {
struct policy_check_filter filter = {
.class = POLICY_ITEM_OWN,
.ucred = ucred,
.name = name,
};
return policy_check(p, &filter) == ALLOW;
}
bool policy_check_hello(Policy *p, const struct ucred *ucred) {
struct policy_check_filter filter = {
.ucred = ucred,
};
int user, group;
filter.class = POLICY_ITEM_USER;
user = policy_check(p, &filter);
if (user == DENY)
return false;
filter.class = POLICY_ITEM_GROUP;
group = policy_check(p, &filter);
if (group == DENY)
return false;
return !(user == DUNNO && group == DUNNO);
}
bool policy_check_recv(Policy *p,
const struct ucred *ucred,
int message_type,
const char *name,
const char *path,
const char *interface,
const char *member) {
struct policy_check_filter filter = {
.class = POLICY_ITEM_RECV,
.ucred = ucred,
.message_type = message_type,
.name = name,
.interface = interface,
.path = path,
.member = member,
};
return policy_check(p, &filter) == ALLOW;
}
bool policy_check_send(Policy *p,
const struct ucred *ucred,
int message_type,
const char *name,
const char *path,
const char *interface,
const char *member) {
struct policy_check_filter filter = {
.class = POLICY_ITEM_SEND,
.ucred = ucred,
.message_type = message_type,
.name = name,
.interface = interface,
.path = path,
.member = member,
};
return policy_check(p, &filter) == ALLOW;
}
int policy_load(Policy *p, char **files) {
char **i;
int r;
assert(p);
STRV_FOREACH(i, files) {
r = file_load(p, *i);
if (r == -EISDIR) {
_cleanup_strv_free_ char **l = NULL;
char **j;
r = conf_files_list(&l, ".conf", NULL, *i, NULL);
if (r < 0) {
log_error("Failed to get configuration file list: %s", strerror(-r));
return r;
}
STRV_FOREACH(j, l)
file_load(p, *j);
}
/* We ignore all errors but EISDIR, and just proceed. */
}
return 0;
}
void policy_free(Policy *p) {
PolicyItem *i, *first;
if (!p)
return;
while ((i = p->default_items)) {
LIST_REMOVE(items, p->default_items, i);
policy_item_free(i);
}
while ((i = p->mandatory_items)) {
LIST_REMOVE(items, p->mandatory_items, i);
policy_item_free(i);
}
while ((first = hashmap_steal_first(p->user_items))) {
while ((i = first)) {
LIST_REMOVE(items, first, i);
policy_item_free(i);
}
}
while ((first = hashmap_steal_first(p->group_items))) {
while ((i = first)) {
LIST_REMOVE(items, first, i);
policy_item_free(i);
}
}
hashmap_free(p->user_items);
hashmap_free(p->group_items);
p->user_items = p->group_items = NULL;
}
static void dump_items(PolicyItem *items, const char *prefix) {
PolicyItem *i;
if (!items)
return;
if (!prefix)
prefix = "";
LIST_FOREACH(items, i, items) {
printf("%sType: %s\n"
"%sClass: %s\n",
prefix, policy_item_type_to_string(i->type),
prefix, policy_item_class_to_string(i->class));
if (i->interface)
printf("%sInterface: %s\n",
prefix, i->interface);
if (i->member)
printf("%sMember: %s\n",
prefix, i->member);
if (i->error)
printf("%sError: %s\n",
prefix, i->error);
if (i->path)
printf("%sPath: %s\n",
prefix, i->path);
if (i->name)
printf("%sName: %s\n",
prefix, i->name);
if (i->message_type != 0)
printf("%sMessage Type: %s\n",
prefix, bus_message_type_to_string(i->message_type));
if (i->uid_valid) {
_cleanup_free_ char *user;
user = uid_to_name(i->uid);
printf("%sUser: %s (%d)\n",
prefix, strna(user), i->uid);
}
if (i->gid_valid) {
_cleanup_free_ char *group;
group = gid_to_name(i->gid);
printf("%sGroup: %s (%d)\n",
prefix, strna(group), i->gid);
}
}
}
static void dump_hashmap_items(Hashmap *h) {
PolicyItem *i;
Iterator j;
void *k;
HASHMAP_FOREACH_KEY(i, k, h, j) {
printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
dump_items(i, "\t\t");
}
}
void policy_dump(Policy *p) {
printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
dump_items(p->default_items, "\t");
printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
dump_hashmap_items(p->group_items);
printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
dump_hashmap_items(p->user_items);
printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
dump_items(p->mandatory_items, "\t");
}
static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
[_POLICY_ITEM_TYPE_UNSET] = "unset",
[POLICY_ITEM_ALLOW] = "allow",
[POLICY_ITEM_DENY] = "deny",
};
DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
[_POLICY_ITEM_CLASS_UNSET] = "unset",
[POLICY_ITEM_SEND] = "send",
[POLICY_ITEM_RECV] = "recv",
[POLICY_ITEM_OWN] = "own",
[POLICY_ITEM_OWN_PREFIX] = "own-prefix",
[POLICY_ITEM_USER] = "user",
[POLICY_ITEM_GROUP] = "group",
[POLICY_ITEM_IGNORE] = "ignore",
};
DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);