Branch data Line data Source code
1 : : /*
2 : : SSSD
3 : :
4 : : IPA Backend Module -- Access control
5 : :
6 : : Authors:
7 : : Sumit Bose <sbose@redhat.com>
8 : : Stephen Gallagher <sgallagh@redhat.com>
9 : :
10 : : Copyright (C) 2011 Red Hat
11 : :
12 : : This program is free software; you can redistribute it and/or modify
13 : : it under the terms of the GNU General Public License as published by
14 : : the Free Software Foundation; either version 3 of the License, or
15 : : (at your option) any later version.
16 : :
17 : : This program is distributed in the hope that it will be useful,
18 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : GNU General Public License for more details.
21 : :
22 : : You should have received a copy of the GNU General Public License
23 : : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <stdlib.h>
27 : : #include <string.h>
28 : : #include <errno.h>
29 : : #include "providers/ipa/ipa_hbac.h"
30 : : #include "util/sss_utf8.h"
31 : :
32 : : #ifndef HAVE_ERRNO_T
33 : : #define HAVE_ERRNO_T
34 : : typedef int errno_t;
35 : : #endif
36 : :
37 : : #ifndef EOK
38 : : #define EOK 0
39 : : #endif
40 : :
41 : : /* Placeholder structure for future HBAC time-based
42 : : * evaluation rules
43 : : */
44 : : struct hbac_time_rules {
45 : : int not_yet_implemented;
46 : : };
47 : :
48 : : enum hbac_eval_result_int {
49 : : HBAC_EVAL_MATCH_ERROR = -1,
50 : : HBAC_EVAL_MATCHED,
51 : : HBAC_EVAL_UNMATCHED
52 : : };
53 : :
54 : 76 : static bool hbac_rule_element_is_complete(struct hbac_rule_element *el)
55 : : {
56 [ + + ]: 76 : if (el == NULL) return false;
57 [ + + ]: 72 : if (el->category == HBAC_CATEGORY_ALL) return true;
58 : :
59 [ + + ][ + - ]: 30 : if (el->names == NULL && el->groups == NULL) return false;
60 : :
61 [ + + ][ + + ]: 30 : if ((el->names && el->names[0] != NULL)
62 [ + - ][ + + ]: 12 : || (el->groups && el->groups[0] != NULL))
63 : : return true;
64 : :
65 : : /* If other categories are added, handle them here */
66 : :
67 : 76 : return false;
68 : : }
69 : :
70 : 19 : bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
71 : : {
72 : 19 : bool complete = true;
73 : :
74 : 19 : *missing_attrs = 0;
75 : :
76 [ + - ]: 19 : if (rule == NULL) {
77 : : /* No rule passed in? */
78 : : return false;
79 : : }
80 : :
81 : : /* Make sure we have all elements */
82 [ + + ]: 19 : if (!hbac_rule_element_is_complete(rule->users)) {
83 : 2 : complete = false;
84 : 2 : *missing_attrs |= HBAC_RULE_ELEMENT_USERS;
85 : : }
86 : :
87 [ + + ]: 19 : if (!hbac_rule_element_is_complete(rule->services)) {
88 : 2 : complete = false;
89 : 2 : *missing_attrs |= HBAC_RULE_ELEMENT_SERVICES;
90 : : }
91 : :
92 [ + + ]: 19 : if (!hbac_rule_element_is_complete(rule->targethosts)) {
93 : 3 : complete = false;
94 : 3 : *missing_attrs |= HBAC_RULE_ELEMENT_TARGETHOSTS;
95 : : }
96 : :
97 [ + + ]: 19 : if (!hbac_rule_element_is_complete(rule->srchosts)) {
98 : 3 : complete = false;
99 : 3 : *missing_attrs |= HBAC_RULE_ELEMENT_SOURCEHOSTS;
100 : : }
101 : :
102 : 19 : return complete;
103 : : }
104 : :
105 : : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
106 : : struct hbac_eval_req *hbac_req,
107 : : enum hbac_error_code *error);
108 : :
109 : 19 : enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules,
110 : : struct hbac_eval_req *hbac_req,
111 : : struct hbac_info **info)
112 : : {
113 : : enum hbac_error_code ret;
114 : 19 : enum hbac_eval_result result = HBAC_EVAL_DENY;
115 : : enum hbac_eval_result_int intermediate_result;
116 : :
117 [ + - ]: 19 : if (info) {
118 : 19 : *info = malloc(sizeof(struct hbac_info));
119 [ + - ]: 19 : if (!*info) {
120 : : return HBAC_EVAL_OOM;
121 : : }
122 : 19 : (*info)->code = HBAC_ERROR_UNKNOWN;
123 : 19 : (*info)->rule_name = NULL;
124 : : }
125 : : uint32_t i;
126 : :
127 [ + + ]: 38 : for (i = 0; rules[i]; i++) {
128 : 19 : intermediate_result = hbac_evaluate_rule(rules[i], hbac_req, &ret);
129 [ + + ]: 19 : if (intermediate_result == HBAC_EVAL_UNMATCHED) {
130 : : /* This rule did not match at all. Skip it */
131 : 9 : continue;
132 [ + - ]: 10 : } else if (intermediate_result == HBAC_EVAL_MATCHED) {
133 : : /* This request matched an ALLOW rule
134 : : * Set the result to ALLOW but continue checking
135 : : * the other rules in case a DENY rule trumps it.
136 : : */
137 : 10 : result = HBAC_EVAL_ALLOW;
138 [ + - ]: 10 : if (info) {
139 : 10 : (*info)->code = HBAC_SUCCESS;
140 : 10 : (*info)->rule_name = strdup(rules[i]->name);
141 [ - + ]: 10 : if (!(*info)->rule_name) {
142 : 0 : result = HBAC_EVAL_ERROR;
143 : 0 : (*info)->code = HBAC_ERROR_OUT_OF_MEMORY;
144 : : }
145 : : }
146 : : break;
147 : : } else {
148 : : /* An error occurred processing this rule */
149 : 0 : result = HBAC_EVAL_ERROR;
150 [ # # ]: 0 : if (info) {
151 : 0 : (*info)->code = ret;
152 : 0 : (*info)->rule_name = strdup(rules[i]->name);
153 : : }
154 : : /* Explicitly not checking the result of strdup(), since if
155 : : * it's NULL, we can't do anything anyway.
156 : : */
157 : : goto done;
158 : : }
159 : : }
160 : :
161 : : /* If we've reached the end of the loop, we have either set the
162 : : * result to ALLOW explicitly or we'll stick with the default DENY.
163 : : */
164 : : done:
165 : :
166 : : return result;
167 : : }
168 : :
169 : : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
170 : : struct hbac_request_element *req_el,
171 : : bool *matched);
172 : :
173 : 19 : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
174 : : struct hbac_eval_req *hbac_req,
175 : : enum hbac_error_code *error)
176 : : {
177 : : errno_t ret;
178 : : bool matched;
179 : :
180 [ + - ]: 19 : if (!rule->enabled) return HBAC_EVAL_UNMATCHED;
181 : :
182 : : /* Make sure we have all elements */
183 [ + - ]: 19 : if (!rule->users
184 [ + - ]: 19 : || !rule->services
185 [ + - ]: 19 : || !rule->targethosts
186 [ - + ]: 19 : || !rule->srchosts) {
187 : 0 : *error = HBAC_ERROR_UNPARSEABLE_RULE;
188 : : return HBAC_EVAL_MATCH_ERROR;
189 : : }
190 : :
191 : : /* Check users */
192 : 19 : ret = hbac_evaluate_element(rule->users,
193 : : hbac_req->user,
194 : : &matched);
195 [ - + ]: 19 : if (ret != EOK) {
196 : 0 : *error = HBAC_ERROR_UNPARSEABLE_RULE;
197 : : return HBAC_EVAL_MATCH_ERROR;
198 [ + + ]: 19 : } else if (!matched) {
199 : : return HBAC_EVAL_UNMATCHED;
200 : : }
201 : :
202 : : /* Check services */
203 : 14 : ret = hbac_evaluate_element(rule->services,
204 : : hbac_req->service,
205 : : &matched);
206 [ - + ]: 14 : if (ret != EOK) {
207 : 0 : *error = HBAC_ERROR_UNPARSEABLE_RULE;
208 : : return HBAC_EVAL_MATCH_ERROR;
209 [ + + ]: 14 : } else if (!matched) {
210 : : return HBAC_EVAL_UNMATCHED;
211 : : }
212 : :
213 : : /* Check target hosts */
214 : 12 : ret = hbac_evaluate_element(rule->targethosts,
215 : : hbac_req->targethost,
216 : : &matched);
217 [ - + ]: 12 : if (ret != EOK) {
218 : 0 : *error = HBAC_ERROR_UNPARSEABLE_RULE;
219 : : return HBAC_EVAL_MATCH_ERROR;
220 [ + - ]: 12 : } else if (!matched) {
221 : : return HBAC_EVAL_UNMATCHED;
222 : : }
223 : :
224 : : /* Check source hosts */
225 : 12 : ret = hbac_evaluate_element(rule->srchosts,
226 : : hbac_req->srchost,
227 : : &matched);
228 [ - + ]: 12 : if (ret != EOK) {
229 : 0 : *error = HBAC_ERROR_UNPARSEABLE_RULE;
230 : : return HBAC_EVAL_MATCH_ERROR;
231 [ + + ]: 19 : } else if (!matched) {
232 : : return HBAC_EVAL_UNMATCHED;
233 : : }
234 : : return HBAC_EVAL_MATCHED;
235 : : }
236 : :
237 : 57 : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
238 : : struct hbac_request_element *req_el,
239 : : bool *matched)
240 : : {
241 : : size_t i, j;
242 : : const uint8_t *rule_name;
243 : : const uint8_t *req_name;
244 : : int ret;
245 : :
246 [ + + ]: 57 : if (rule_el->category & HBAC_CATEGORY_ALL) {
247 : 32 : *matched = true;
248 : 32 : return EOK;
249 : : }
250 : :
251 : : /* First check the name list */
252 [ + + ]: 25 : if (rule_el->names) {
253 [ + + ]: 25 : for (i = 0; rule_el->names[i]; i++) {
254 [ + - ]: 19 : if (req_el->name != NULL) {
255 : 19 : rule_name = (const uint8_t *) rule_el->names[i];
256 : 19 : req_name = (const uint8_t *) req_el->name;
257 : :
258 : : /* Do a case-insensitive comparison. */
259 : 19 : ret = sss_utf8_case_eq(rule_name, req_name);
260 [ + - ]: 19 : if (ret != EOK && ret != ENOMATCH) {
261 : : return ret;
262 [ + + ]: 19 : } else if (ret == EOK) {
263 : 13 : *matched = true;
264 : 13 : return EOK;
265 : : }
266 : : }
267 : : }
268 : : }
269 : :
270 [ + + ]: 12 : if (rule_el->groups) {
271 : : /* Not found in the name list
272 : : * Check for group membership
273 : : */
274 [ + + ]: 10 : for (i = 0; rule_el->groups[i]; i++) {
275 : : rule_name = (const uint8_t *) rule_el->groups[i];
276 : :
277 [ + + ]: 12 : for (j = 0; req_el->groups[j]; j++) {
278 : 9 : req_name = (const uint8_t *) req_el->groups[j];
279 : :
280 : : /* Do a case-insensitive comparison. */
281 : 9 : ret = sss_utf8_case_eq(rule_name, req_name);
282 [ + - ]: 9 : if (ret != EOK && ret != ENOMATCH) {
283 : : return ret;
284 [ + + ]: 9 : } else if (ret == EOK) {
285 : 3 : *matched = true;
286 : 3 : return EOK;
287 : : }
288 : : }
289 : : }
290 : : }
291 : :
292 : : /* Not found in groups either */
293 : 9 : *matched = false;
294 : 57 : return EOK;
295 : : }
296 : :
297 : 35 : const char *hbac_result_string(enum hbac_eval_result result)
298 : : {
299 [ + + - - : 35 : switch(result) {
+ ]
300 : : case HBAC_EVAL_ALLOW:
301 : : return "HBAC_EVAL_ALLOW";
302 : : case HBAC_EVAL_DENY:
303 : 17 : return "HBAC_EVAL_DENY";
304 : : case HBAC_EVAL_ERROR:
305 : 1 : return "HBAC_EVAL_ERROR";
306 : : case HBAC_EVAL_OOM:
307 : 0 : return "Could not allocate memory for hbac_info object";
308 : : }
309 : 35 : return "HBAC_EVAL_ERROR";
310 : : }
311 : :
312 : 7 : void hbac_free_info(struct hbac_info *info)
313 : : {
314 [ + + ]: 10 : if (info == NULL) return;
315 : :
316 : 3 : free(info->rule_name);
317 : 3 : free(info);
318 : 3 : info = NULL;
319 : : }
320 : :
321 : 21 : const char *hbac_error_string(enum hbac_error_code code)
322 : : {
323 [ + + + + : 21 : switch(code) {
+ ]
324 : : case HBAC_SUCCESS:
325 : : return "Success";
326 : : case HBAC_ERROR_NOT_IMPLEMENTED:
327 : 1 : return "Function is not yet implemented";
328 : : case HBAC_ERROR_OUT_OF_MEMORY:
329 : 1 : return "Out of memory";
330 : : case HBAC_ERROR_UNPARSEABLE_RULE:
331 : 1 : return "Rule could not be evaluated";
332 : : case HBAC_ERROR_UNKNOWN:
333 : : default:
334 : 21 : return "Unknown error code";
335 : : }
336 : : }
|