| /* | |
| * QEMU access control list authorization driver | |
| * | |
| * Copyright (c) 2018 Red Hat, Inc. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
| * | |
| */ | |
| #include "qemu/osdep.h" | |
| #include "authz/list.h" | |
| #include "trace.h" | |
| #include "qom/object_interfaces.h" | |
| #include "qapi/qapi-visit-authz.h" | |
| #include "qemu/module.h" | |
| static bool qauthz_list_is_allowed(QAuthZ *authz, | |
| const char *identity, | |
| Error **errp) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(authz); | |
| QAuthZListRuleList *rules = lauthz->rules; | |
| while (rules) { | |
| QAuthZListRule *rule = rules->value; | |
| QAuthZListFormat format = rule->has_format ? rule->format : | |
| QAUTHZ_LIST_FORMAT_EXACT; | |
| trace_qauthz_list_check_rule(authz, rule->match, identity, | |
| format, rule->policy); | |
| switch (format) { | |
| case QAUTHZ_LIST_FORMAT_EXACT: | |
| if (g_str_equal(rule->match, identity)) { | |
| return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; | |
| } | |
| break; | |
| case QAUTHZ_LIST_FORMAT_GLOB: | |
| if (g_pattern_match_simple(rule->match, identity)) { | |
| return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; | |
| } | |
| break; | |
| default: | |
| g_warn_if_reached(); | |
| return false; | |
| } | |
| rules = rules->next; | |
| } | |
| trace_qauthz_list_default_policy(authz, identity, lauthz->policy); | |
| return lauthz->policy == QAUTHZ_LIST_POLICY_ALLOW; | |
| } | |
| static void | |
| qauthz_list_prop_set_policy(Object *obj, | |
| int value, | |
| Error **errp G_GNUC_UNUSED) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(obj); | |
| lauthz->policy = value; | |
| } | |
| static int | |
| qauthz_list_prop_get_policy(Object *obj, | |
| Error **errp G_GNUC_UNUSED) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(obj); | |
| return lauthz->policy; | |
| } | |
| static void | |
| qauthz_list_prop_get_rules(Object *obj, Visitor *v, const char *name, | |
| void *opaque, Error **errp) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(obj); | |
| visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); | |
| } | |
| static void | |
| qauthz_list_prop_set_rules(Object *obj, Visitor *v, const char *name, | |
| void *opaque, Error **errp) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(obj); | |
| QAuthZListRuleList *oldrules; | |
| oldrules = lauthz->rules; | |
| visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); | |
| qapi_free_QAuthZListRuleList(oldrules); | |
| } | |
| static void | |
| qauthz_list_finalize(Object *obj) | |
| { | |
| QAuthZList *lauthz = QAUTHZ_LIST(obj); | |
| qapi_free_QAuthZListRuleList(lauthz->rules); | |
| } | |
| static void | |
| qauthz_list_class_init(ObjectClass *oc, const void *data) | |
| { | |
| QAuthZClass *authz = QAUTHZ_CLASS(oc); | |
| object_class_property_add_enum(oc, "policy", | |
| "QAuthZListPolicy", | |
| &QAuthZListPolicy_lookup, | |
| qauthz_list_prop_get_policy, | |
| qauthz_list_prop_set_policy); | |
| object_class_property_add(oc, "rules", "QAuthZListRule", | |
| qauthz_list_prop_get_rules, | |
| qauthz_list_prop_set_rules, | |
| NULL, NULL); | |
| authz->is_allowed = qauthz_list_is_allowed; | |
| } | |
| QAuthZList *qauthz_list_new(const char *id, | |
| QAuthZListPolicy policy, | |
| Error **errp) | |
| { | |
| return QAUTHZ_LIST( | |
| object_new_with_props(TYPE_QAUTHZ_LIST, | |
| object_get_objects_root(), | |
| id, errp, | |
| "policy", QAuthZListPolicy_str(policy), | |
| NULL)); | |
| } | |
| ssize_t qauthz_list_append_rule(QAuthZList *auth, | |
| const char *match, | |
| QAuthZListPolicy policy, | |
| QAuthZListFormat format, | |
| Error **errp) | |
| { | |
| QAuthZListRule *rule; | |
| QAuthZListRuleList *rules, *tmp; | |
| size_t i = 0; | |
| rule = g_new0(QAuthZListRule, 1); | |
| rule->policy = policy; | |
| rule->match = g_strdup(match); | |
| rule->format = format; | |
| rule->has_format = true; | |
| tmp = g_new0(QAuthZListRuleList, 1); | |
| tmp->value = rule; | |
| rules = auth->rules; | |
| if (rules) { | |
| while (rules->next) { | |
| i++; | |
| rules = rules->next; | |
| } | |
| rules->next = tmp; | |
| return i + 1; | |
| } else { | |
| auth->rules = tmp; | |
| return 0; | |
| } | |
| } | |
| ssize_t qauthz_list_insert_rule(QAuthZList *auth, | |
| const char *match, | |
| QAuthZListPolicy policy, | |
| QAuthZListFormat format, | |
| size_t index, | |
| Error **errp) | |
| { | |
| QAuthZListRule *rule; | |
| QAuthZListRuleList *rules, *tmp; | |
| size_t i = 0; | |
| rule = g_new0(QAuthZListRule, 1); | |
| rule->policy = policy; | |
| rule->match = g_strdup(match); | |
| rule->format = format; | |
| rule->has_format = true; | |
| tmp = g_new0(QAuthZListRuleList, 1); | |
| tmp->value = rule; | |
| rules = auth->rules; | |
| if (rules && index > 0) { | |
| while (rules->next && i < (index - 1)) { | |
| i++; | |
| rules = rules->next; | |
| } | |
| tmp->next = rules->next; | |
| rules->next = tmp; | |
| return i + 1; | |
| } else { | |
| tmp->next = auth->rules; | |
| auth->rules = tmp; | |
| return 0; | |
| } | |
| } | |
| ssize_t qauthz_list_delete_rule(QAuthZList *auth, const char *match) | |
| { | |
| QAuthZListRule *rule; | |
| QAuthZListRuleList *rules, *prev; | |
| size_t i = 0; | |
| prev = NULL; | |
| rules = auth->rules; | |
| while (rules) { | |
| rule = rules->value; | |
| if (g_str_equal(rule->match, match)) { | |
| if (prev) { | |
| prev->next = rules->next; | |
| } else { | |
| auth->rules = rules->next; | |
| } | |
| rules->next = NULL; | |
| qapi_free_QAuthZListRuleList(rules); | |
| return i; | |
| } | |
| prev = rules; | |
| rules = rules->next; | |
| i++; | |
| } | |
| return -1; | |
| } | |
| static const TypeInfo qauthz_list_info = { | |
| .parent = TYPE_QAUTHZ, | |
| .name = TYPE_QAUTHZ_LIST, | |
| .instance_size = sizeof(QAuthZList), | |
| .instance_finalize = qauthz_list_finalize, | |
| .class_init = qauthz_list_class_init, | |
| .interfaces = (const InterfaceInfo[]) { | |
| { TYPE_USER_CREATABLE }, | |
| { } | |
| } | |
| }; | |
| static void | |
| qauthz_list_register_types(void) | |
| { | |
| type_register_static(&qauthz_list_info); | |
| } | |
| type_init(qauthz_list_register_types); |