1 | /* |
2 | * QEMU access control list authorization driver |
3 | * |
4 | * Copyright (c) 2018 Red Hat, Inc. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
18 | * |
19 | */ |
20 | |
21 | #include "qemu/osdep.h" |
22 | #include "authz/list.h" |
23 | #include "trace.h" |
24 | #include "qom/object_interfaces.h" |
25 | #include "qapi/qapi-visit-authz.h" |
26 | #include "qemu/module.h" |
27 | |
28 | static bool qauthz_list_is_allowed(QAuthZ *authz, |
29 | const char *identity, |
30 | Error **errp) |
31 | { |
32 | QAuthZList *lauthz = QAUTHZ_LIST(authz); |
33 | QAuthZListRuleList *rules = lauthz->rules; |
34 | |
35 | while (rules) { |
36 | QAuthZListRule *rule = rules->value; |
37 | QAuthZListFormat format = rule->has_format ? rule->format : |
38 | QAUTHZ_LIST_FORMAT_EXACT; |
39 | |
40 | trace_qauthz_list_check_rule(authz, rule->match, identity, |
41 | format, rule->policy); |
42 | switch (format) { |
43 | case QAUTHZ_LIST_FORMAT_EXACT: |
44 | if (g_str_equal(rule->match, identity)) { |
45 | return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; |
46 | } |
47 | break; |
48 | case QAUTHZ_LIST_FORMAT_GLOB: |
49 | if (g_pattern_match_simple(rule->match, identity)) { |
50 | return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; |
51 | } |
52 | break; |
53 | default: |
54 | g_warn_if_reached(); |
55 | return false; |
56 | } |
57 | rules = rules->next; |
58 | } |
59 | |
60 | trace_qauthz_list_default_policy(authz, identity, lauthz->policy); |
61 | return lauthz->policy == QAUTHZ_LIST_POLICY_ALLOW; |
62 | } |
63 | |
64 | |
65 | static void |
66 | qauthz_list_prop_set_policy(Object *obj, |
67 | int value, |
68 | Error **errp G_GNUC_UNUSED) |
69 | { |
70 | QAuthZList *lauthz = QAUTHZ_LIST(obj); |
71 | |
72 | lauthz->policy = value; |
73 | } |
74 | |
75 | |
76 | static int |
77 | qauthz_list_prop_get_policy(Object *obj, |
78 | Error **errp G_GNUC_UNUSED) |
79 | { |
80 | QAuthZList *lauthz = QAUTHZ_LIST(obj); |
81 | |
82 | return lauthz->policy; |
83 | } |
84 | |
85 | |
86 | static void |
87 | qauthz_list_prop_get_rules(Object *obj, Visitor *v, const char *name, |
88 | void *opaque, Error **errp) |
89 | { |
90 | QAuthZList *lauthz = QAUTHZ_LIST(obj); |
91 | |
92 | visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); |
93 | } |
94 | |
95 | static void |
96 | qauthz_list_prop_set_rules(Object *obj, Visitor *v, const char *name, |
97 | void *opaque, Error **errp) |
98 | { |
99 | QAuthZList *lauthz = QAUTHZ_LIST(obj); |
100 | QAuthZListRuleList *oldrules; |
101 | |
102 | oldrules = lauthz->rules; |
103 | visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); |
104 | |
105 | qapi_free_QAuthZListRuleList(oldrules); |
106 | } |
107 | |
108 | |
109 | static void |
110 | qauthz_list_finalize(Object *obj) |
111 | { |
112 | QAuthZList *lauthz = QAUTHZ_LIST(obj); |
113 | |
114 | qapi_free_QAuthZListRuleList(lauthz->rules); |
115 | } |
116 | |
117 | |
118 | static void |
119 | qauthz_list_class_init(ObjectClass *oc, void *data) |
120 | { |
121 | QAuthZClass *authz = QAUTHZ_CLASS(oc); |
122 | |
123 | object_class_property_add_enum(oc, "policy" , |
124 | "QAuthZListPolicy" , |
125 | &QAuthZListPolicy_lookup, |
126 | qauthz_list_prop_get_policy, |
127 | qauthz_list_prop_set_policy, |
128 | NULL); |
129 | |
130 | object_class_property_add(oc, "rules" , "QAuthZListRule" , |
131 | qauthz_list_prop_get_rules, |
132 | qauthz_list_prop_set_rules, |
133 | NULL, NULL, NULL); |
134 | |
135 | authz->is_allowed = qauthz_list_is_allowed; |
136 | } |
137 | |
138 | |
139 | QAuthZList *qauthz_list_new(const char *id, |
140 | QAuthZListPolicy policy, |
141 | Error **errp) |
142 | { |
143 | return QAUTHZ_LIST( |
144 | object_new_with_props(TYPE_QAUTHZ_LIST, |
145 | object_get_objects_root(), |
146 | id, errp, |
147 | "policy" , QAuthZListPolicy_str(policy), |
148 | NULL)); |
149 | } |
150 | |
151 | ssize_t qauthz_list_append_rule(QAuthZList *auth, |
152 | const char *match, |
153 | QAuthZListPolicy policy, |
154 | QAuthZListFormat format, |
155 | Error **errp) |
156 | { |
157 | QAuthZListRule *rule; |
158 | QAuthZListRuleList *rules, *tmp; |
159 | size_t i = 0; |
160 | |
161 | rule = g_new0(QAuthZListRule, 1); |
162 | rule->policy = policy; |
163 | rule->match = g_strdup(match); |
164 | rule->format = format; |
165 | rule->has_format = true; |
166 | |
167 | tmp = g_new0(QAuthZListRuleList, 1); |
168 | tmp->value = rule; |
169 | |
170 | rules = auth->rules; |
171 | if (rules) { |
172 | while (rules->next) { |
173 | i++; |
174 | rules = rules->next; |
175 | } |
176 | rules->next = tmp; |
177 | return i + 1; |
178 | } else { |
179 | auth->rules = tmp; |
180 | return 0; |
181 | } |
182 | } |
183 | |
184 | |
185 | ssize_t qauthz_list_insert_rule(QAuthZList *auth, |
186 | const char *match, |
187 | QAuthZListPolicy policy, |
188 | QAuthZListFormat format, |
189 | size_t index, |
190 | Error **errp) |
191 | { |
192 | QAuthZListRule *rule; |
193 | QAuthZListRuleList *rules, *tmp; |
194 | size_t i = 0; |
195 | |
196 | rule = g_new0(QAuthZListRule, 1); |
197 | rule->policy = policy; |
198 | rule->match = g_strdup(match); |
199 | rule->format = format; |
200 | rule->has_format = true; |
201 | |
202 | tmp = g_new0(QAuthZListRuleList, 1); |
203 | tmp->value = rule; |
204 | |
205 | rules = auth->rules; |
206 | if (rules && index > 0) { |
207 | while (rules->next && i < (index - 1)) { |
208 | i++; |
209 | rules = rules->next; |
210 | } |
211 | tmp->next = rules->next; |
212 | rules->next = tmp; |
213 | return i + 1; |
214 | } else { |
215 | tmp->next = auth->rules; |
216 | auth->rules = tmp; |
217 | return 0; |
218 | } |
219 | } |
220 | |
221 | |
222 | ssize_t qauthz_list_delete_rule(QAuthZList *auth, const char *match) |
223 | { |
224 | QAuthZListRule *rule; |
225 | QAuthZListRuleList *rules, *prev; |
226 | size_t i = 0; |
227 | |
228 | prev = NULL; |
229 | rules = auth->rules; |
230 | while (rules) { |
231 | rule = rules->value; |
232 | if (g_str_equal(rule->match, match)) { |
233 | if (prev) { |
234 | prev->next = rules->next; |
235 | } else { |
236 | auth->rules = rules->next; |
237 | } |
238 | rules->next = NULL; |
239 | qapi_free_QAuthZListRuleList(rules); |
240 | return i; |
241 | } |
242 | prev = rules; |
243 | rules = rules->next; |
244 | i++; |
245 | } |
246 | |
247 | return -1; |
248 | } |
249 | |
250 | |
251 | static const TypeInfo qauthz_list_info = { |
252 | .parent = TYPE_QAUTHZ, |
253 | .name = TYPE_QAUTHZ_LIST, |
254 | .instance_size = sizeof(QAuthZList), |
255 | .instance_finalize = qauthz_list_finalize, |
256 | .class_size = sizeof(QAuthZListClass), |
257 | .class_init = qauthz_list_class_init, |
258 | .interfaces = (InterfaceInfo[]) { |
259 | { TYPE_USER_CREATABLE }, |
260 | { } |
261 | } |
262 | }; |
263 | |
264 | |
265 | static void |
266 | qauthz_list_register_types(void) |
267 | { |
268 | type_register_static(&qauthz_list_info); |
269 | } |
270 | |
271 | |
272 | type_init(qauthz_list_register_types); |
273 | |