| /* |
| * 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 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, 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 = (InterfaceInfo[]) { |
| { TYPE_USER_CREATABLE }, |
| { } |
| } |
| }; |
| |
| |
| static void |
| qauthz_list_register_types(void) |
| { |
| type_register_static(&qauthz_list_info); |
| } |
| |
| |
| type_init(qauthz_list_register_types); |