Line data Source code
1 : /*
2 : SSSD
3 :
4 : Authors:
5 : Stephen Gallagher <sgallagh@redhat.com>
6 :
7 : Copyright (C) 2011 Red Hat
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "providers/ipa/ipa_hbac_private.h"
24 : #include "providers/ipa/ipa_hbac.h"
25 : #include "providers/ipa/ipa_common.h"
26 :
27 : static errno_t
28 0 : ipa_hbac_save_list(struct sss_domain_info *domain,
29 : bool delete_subdir, const char *subdir,
30 : const char *naming_attribute, size_t count,
31 : struct sysdb_attrs **list)
32 : {
33 : int ret;
34 : size_t c;
35 : struct ldb_dn *base_dn;
36 : const char *object_name;
37 : struct ldb_message_element *el;
38 : TALLOC_CTX *tmp_ctx;
39 :
40 0 : tmp_ctx = talloc_new(NULL);
41 0 : if (tmp_ctx == NULL) {
42 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
43 0 : return ENOMEM;
44 : }
45 :
46 0 : if (delete_subdir) {
47 0 : base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, subdir);
48 0 : if (base_dn == NULL) {
49 0 : ret = ENOMEM;
50 0 : goto done;
51 : }
52 :
53 0 : ret = sysdb_delete_recursive(domain->sysdb, base_dn, true);
54 0 : if (ret != EOK) {
55 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n");
56 0 : goto done;
57 : }
58 : }
59 :
60 0 : for (c = 0; c < count; c++) {
61 0 : ret = sysdb_attrs_get_el(list[c], naming_attribute, &el);
62 0 : if (ret != EOK) {
63 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n");
64 0 : goto done;
65 : }
66 0 : if (el->num_values == 0) {
67 0 : DEBUG(SSSDBG_CRIT_FAILURE, "[%s] not found.\n", naming_attribute);
68 0 : ret = EINVAL;
69 0 : goto done;
70 : }
71 0 : object_name = talloc_strndup(tmp_ctx, (const char *)el->values[0].data,
72 0 : el->values[0].length);
73 0 : if (object_name == NULL) {
74 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
75 0 : ret = ENOMEM;
76 0 : goto done;
77 : }
78 0 : DEBUG(SSSDBG_TRACE_ALL, "Object name: [%s].\n", object_name);
79 :
80 0 : ret = sysdb_store_custom(domain, object_name, subdir, list[c]);
81 0 : if (ret != EOK) {
82 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_store_custom failed.\n");
83 0 : goto done;
84 : }
85 : }
86 :
87 0 : ret = EOK;
88 :
89 : done:
90 0 : talloc_free(tmp_ctx);
91 0 : return ret;
92 : }
93 :
94 : errno_t
95 0 : ipa_hbac_sysdb_save(struct sss_domain_info *domain,
96 : const char *primary_subdir, const char *attr_name,
97 : size_t primary_count, struct sysdb_attrs **primary,
98 : const char *group_subdir, const char *groupattr_name,
99 : size_t group_count, struct sysdb_attrs **groups)
100 : {
101 : errno_t ret, sret;
102 0 : bool in_transaction = false;
103 :
104 0 : if ((primary_count == 0 || primary == NULL)
105 0 : || (group_count > 0 && groups == NULL)) {
106 : /* There always has to be at least one
107 : * primary entry.
108 : */
109 0 : return EINVAL;
110 : }
111 :
112 : /* Save the entries and groups to the cache */
113 0 : ret = sysdb_transaction_start(domain->sysdb);
114 0 : if (ret != EOK) {
115 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
116 0 : goto done;
117 : };
118 0 : in_transaction = true;
119 :
120 : /* First, save the specific entries */
121 0 : ret = ipa_hbac_save_list(domain, true, primary_subdir,
122 : attr_name, primary_count, primary);
123 0 : if (ret != EOK) {
124 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n",
125 : primary_subdir, ret, strerror(ret));
126 0 : goto done;
127 : }
128 :
129 : /* Second, save the groups */
130 0 : if (group_count > 0) {
131 0 : ret = ipa_hbac_save_list(domain, true, group_subdir,
132 : groupattr_name, group_count, groups);
133 0 : if (ret != EOK) {
134 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n",
135 : group_subdir, ret, strerror(ret));
136 0 : goto done;
137 : }
138 : }
139 :
140 0 : ret = sysdb_transaction_commit(domain->sysdb);
141 0 : if (ret != EOK) {
142 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
143 0 : goto done;
144 : }
145 0 : in_transaction = false;
146 :
147 : done:
148 0 : if (in_transaction) {
149 0 : sret = sysdb_transaction_cancel(domain->sysdb);
150 0 : if (sret != EOK) {
151 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel sysdb transaction\n");
152 : }
153 : }
154 :
155 0 : if (ret != EOK) {
156 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Error [%d][%s]\n", ret, strerror(ret));
157 : }
158 0 : return ret;
159 : }
160 :
161 : errno_t
162 0 : replace_attribute_name(const char *old_name,
163 : const char *new_name, const size_t count,
164 : struct sysdb_attrs **list)
165 : {
166 : int ret;
167 : int i;
168 :
169 0 : for (i = 0; i < count; i++) {
170 0 : ret = sysdb_attrs_replace_name(list[i], old_name, new_name);
171 0 : if (ret != EOK) {
172 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_replace_name failed.\n");
173 0 : return ret;
174 : }
175 : }
176 :
177 0 : return EOK;
178 : }
179 :
180 : static errno_t
181 0 : create_empty_grouplist(struct hbac_request_element *el)
182 : {
183 0 : el->groups = talloc_array(el, const char *, 1);
184 0 : if (!el->groups) return ENOMEM;
185 :
186 0 : el->groups[0] = NULL;
187 0 : return EOK;
188 : }
189 :
190 : /********************************************
191 : * Functions for handling conversion to the *
192 : * HBAC evaluator format *
193 : ********************************************/
194 :
195 : static errno_t
196 : hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
197 : struct hbac_ctx *hbac_ctx,
198 : size_t index,
199 : struct hbac_rule **rule);
200 :
201 : static errno_t
202 : hbac_ctx_to_eval_request(TALLOC_CTX *mem_ctx,
203 : struct hbac_ctx *hbac_ctx,
204 : struct hbac_eval_req **request);
205 :
206 : errno_t
207 0 : hbac_ctx_to_rules(TALLOC_CTX *mem_ctx,
208 : struct hbac_ctx *hbac_ctx,
209 : struct hbac_rule ***rules,
210 : struct hbac_eval_req **request)
211 : {
212 : errno_t ret;
213 : struct hbac_rule **new_rules;
214 0 : struct hbac_eval_req *new_request = NULL;
215 : size_t i;
216 0 : TALLOC_CTX *tmp_ctx = NULL;
217 :
218 0 : if (!rules || !request) return EINVAL;
219 :
220 0 : tmp_ctx = talloc_new(mem_ctx);
221 0 : if (tmp_ctx == NULL) return ENOMEM;
222 :
223 : /* First create an array of rules */
224 0 : new_rules = talloc_array(tmp_ctx, struct hbac_rule *,
225 : hbac_ctx->rule_count + 1);
226 0 : if (new_rules == NULL) {
227 0 : ret = ENOMEM;
228 0 : goto done;
229 : }
230 :
231 : /* Create each rule one at a time */
232 0 : for (i = 0; i < hbac_ctx->rule_count ; i++) {
233 0 : ret = hbac_attrs_to_rule(new_rules, hbac_ctx, i, &(new_rules[i]));
234 0 : if (ret == EPERM) {
235 0 : goto done;
236 0 : } else if (ret != EOK) {
237 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct rules\n");
238 0 : goto done;
239 : }
240 : }
241 0 : new_rules[i] = NULL;
242 :
243 : /* Create the eval request */
244 0 : ret = hbac_ctx_to_eval_request(tmp_ctx, hbac_ctx, &new_request);
245 0 : if (ret != EOK) {
246 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct eval request\n");
247 0 : goto done;
248 : }
249 :
250 0 : *rules = talloc_steal(mem_ctx, new_rules);
251 0 : *request = talloc_steal(mem_ctx, new_request);
252 0 : ret = EOK;
253 :
254 : done:
255 0 : talloc_free(tmp_ctx);
256 0 : return ret;
257 : }
258 :
259 : static errno_t
260 0 : hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
261 : struct hbac_ctx *hbac_ctx,
262 : size_t idx,
263 : struct hbac_rule **rule)
264 : {
265 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
266 : errno_t ret;
267 : struct hbac_rule *new_rule;
268 : struct ldb_message_element *el;
269 : const char *rule_type;
270 :
271 0 : new_rule = talloc_zero(mem_ctx, struct hbac_rule);
272 0 : if (new_rule == NULL) return ENOMEM;
273 :
274 0 : ret = sysdb_attrs_get_el(hbac_ctx->rules[idx],
275 : IPA_CN, &el);
276 0 : if (ret != EOK || el->num_values == 0) {
277 0 : DEBUG(SSSDBG_CONF_SETTINGS, "rule has no name, assuming '(none)'.\n");
278 0 : new_rule->name = talloc_strdup(new_rule, "(none)");
279 : } else {
280 0 : new_rule->name = talloc_strndup(new_rule,
281 0 : (const char*) el->values[0].data,
282 0 : el->values[0].length);
283 : }
284 :
285 0 : DEBUG(SSSDBG_TRACE_LIBS, "Processing rule [%s]\n", new_rule->name);
286 :
287 0 : ret = sysdb_attrs_get_bool(hbac_ctx->rules[idx], IPA_ENABLED_FLAG,
288 : &new_rule->enabled);
289 0 : if (ret != EOK) goto done;
290 :
291 0 : if (!new_rule->enabled) {
292 0 : ret = EOK;
293 0 : goto done;
294 : }
295 :
296 0 : ret = sysdb_attrs_get_string(hbac_ctx->rules[idx],
297 : IPA_ACCESS_RULE_TYPE,
298 : &rule_type);
299 0 : if (ret != EOK) goto done;
300 :
301 0 : if (strcasecmp(rule_type, IPA_HBAC_ALLOW) != 0) {
302 0 : DEBUG(SSSDBG_TRACE_LIBS,
303 : "Rule [%s] is not an ALLOW rule\n", new_rule->name);
304 0 : ret = EPERM;
305 0 : goto done;
306 : }
307 :
308 : /* Get the users */
309 0 : ret = hbac_user_attrs_to_rule(new_rule, be_ctx->domain,
310 : new_rule->name,
311 0 : hbac_ctx->rules[idx],
312 : &new_rule->users);
313 0 : if (ret != EOK) {
314 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not parse users for rule [%s]\n",
315 : new_rule->name);
316 0 : goto done;
317 : }
318 :
319 : /* Get the services */
320 0 : ret = hbac_service_attrs_to_rule(new_rule, be_ctx->domain,
321 : new_rule->name,
322 0 : hbac_ctx->rules[idx],
323 : &new_rule->services);
324 0 : if (ret != EOK) {
325 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not parse services for rule [%s]\n",
326 : new_rule->name);
327 0 : goto done;
328 : }
329 :
330 : /* Get the target hosts */
331 0 : ret = hbac_thost_attrs_to_rule(new_rule, be_ctx->domain,
332 : new_rule->name,
333 0 : hbac_ctx->rules[idx],
334 : &new_rule->targethosts);
335 0 : if (ret != EOK) {
336 0 : DEBUG(SSSDBG_CRIT_FAILURE,
337 : "Could not parse target hosts for rule [%s]\n",
338 : new_rule->name);
339 0 : goto done;
340 : }
341 :
342 : /* Get the source hosts */
343 :
344 0 : ret = hbac_shost_attrs_to_rule(new_rule, be_ctx->domain,
345 : new_rule->name,
346 0 : hbac_ctx->rules[idx],
347 0 : dp_opt_get_bool(hbac_ctx->ipa_options,
348 : IPA_HBAC_SUPPORT_SRCHOST),
349 : &new_rule->srchosts);
350 0 : if (ret != EOK) {
351 0 : DEBUG(SSSDBG_CRIT_FAILURE,
352 : "Could not parse source hosts for rule [%s]\n",
353 : new_rule->name);
354 0 : goto done;
355 : }
356 :
357 0 : *rule = new_rule;
358 0 : ret = EOK;
359 :
360 : done:
361 0 : if (ret != EOK) talloc_free(new_rule);
362 0 : return ret;
363 : }
364 :
365 : errno_t
366 0 : hbac_get_category(struct sysdb_attrs *attrs,
367 : const char *category_attr,
368 : uint32_t *_categories)
369 : {
370 : errno_t ret;
371 : size_t i;
372 0 : uint32_t cats = HBAC_CATEGORY_NULL;
373 : const char **categories;
374 :
375 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
376 0 : if (tmp_ctx == NULL) return ENOMEM;
377 :
378 0 : ret = sysdb_attrs_get_string_array(attrs, category_attr,
379 : tmp_ctx, &categories);
380 0 : if (ret != EOK && ret != ENOENT) goto done;
381 :
382 0 : if (ret != ENOENT) {
383 0 : for (i = 0; categories[i]; i++) {
384 0 : if (strcasecmp("all", categories[i]) == 0) {
385 0 : DEBUG(SSSDBG_FUNC_DATA, "Category is set to 'all'.\n");
386 0 : cats |= HBAC_CATEGORY_ALL;
387 0 : continue;
388 : }
389 0 : DEBUG(SSSDBG_TRACE_ALL, "Unsupported user category [%s].\n",
390 : categories[i]);
391 : }
392 : }
393 :
394 0 : *_categories = cats;
395 0 : ret = EOK;
396 :
397 : done:
398 0 : talloc_free(tmp_ctx);
399 0 : return ret;
400 : }
401 :
402 : static errno_t
403 : hbac_eval_user_element(TALLOC_CTX *mem_ctx,
404 : struct sss_domain_info *domain,
405 : const char *username,
406 : struct hbac_request_element **user_element);
407 :
408 : static errno_t
409 : hbac_eval_service_element(TALLOC_CTX *mem_ctx,
410 : struct sss_domain_info *domain,
411 : const char *servicename,
412 : struct hbac_request_element **svc_element);
413 :
414 : static errno_t
415 : hbac_eval_host_element(TALLOC_CTX *mem_ctx,
416 : struct sss_domain_info *domain,
417 : const char *hostname,
418 : struct hbac_request_element **host_element);
419 :
420 : static errno_t
421 0 : hbac_ctx_to_eval_request(TALLOC_CTX *mem_ctx,
422 : struct hbac_ctx *hbac_ctx,
423 : struct hbac_eval_req **request)
424 : {
425 : errno_t ret;
426 0 : struct pam_data *pd = hbac_ctx->pd;
427 : TALLOC_CTX *tmp_ctx;
428 : struct hbac_eval_req *eval_req;
429 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
430 0 : struct sss_domain_info *domain = be_ctx->domain;
431 : const char *rhost;
432 : const char *thost;
433 : struct sss_domain_info *user_dom;
434 :
435 0 : tmp_ctx = talloc_new(mem_ctx);
436 0 : if (tmp_ctx == NULL) return ENOMEM;
437 :
438 0 : eval_req = talloc_zero(tmp_ctx, struct hbac_eval_req);
439 0 : if (eval_req == NULL) {
440 0 : ret = ENOMEM;
441 0 : goto done;
442 : }
443 :
444 0 : eval_req->request_time = time(NULL);
445 :
446 : /* Get user the user name and groups,
447 : * take care of subdomain users as well */
448 0 : if (strcasecmp(pd->domain, domain->name) != 0) {
449 0 : user_dom = find_domain_by_name(domain, pd->domain, true);
450 0 : if (user_dom == NULL) {
451 0 : DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
452 0 : ret = ENOMEM;
453 0 : goto done;
454 : }
455 0 : ret = hbac_eval_user_element(eval_req, user_dom, pd->user,
456 : &eval_req->user);
457 : } else {
458 0 : ret = hbac_eval_user_element(eval_req, domain, pd->user,
459 : &eval_req->user);
460 : }
461 0 : if (ret != EOK) goto done;
462 :
463 : /* Get the PAM service and service groups */
464 0 : ret = hbac_eval_service_element(eval_req, domain, pd->service,
465 : &eval_req->service);
466 0 : if (ret != EOK) goto done;
467 :
468 : /* Get the source host */
469 0 : if (pd->rhost == NULL || pd->rhost[0] == '\0') {
470 : /* If we haven't been passed an rhost,
471 : * the rhost is unknown. This will fail
472 : * to match any rule requiring the
473 : * source host.
474 : */
475 0 : rhost = NULL;
476 : } else {
477 0 : rhost = pd->rhost;
478 : }
479 :
480 0 : ret = hbac_eval_host_element(eval_req, domain, rhost,
481 : &eval_req->srchost);
482 0 : if (ret != EOK) goto done;
483 :
484 : /* The target host is always the current machine */
485 0 : thost = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME);
486 0 : if (thost == NULL) {
487 0 : DEBUG(SSSDBG_CRIT_FAILURE,
488 : "Missing ipa_hostname, this should never happen.\n");
489 0 : ret = EINVAL;
490 0 : goto done;
491 : }
492 :
493 0 : ret = hbac_eval_host_element(eval_req, domain, thost,
494 : &eval_req->targethost);
495 0 : if (ret != EOK) goto done;
496 :
497 0 : *request = talloc_steal(mem_ctx, eval_req);
498 :
499 0 : ret = EOK;
500 :
501 : done:
502 0 : talloc_free(tmp_ctx);
503 0 : return ret;
504 : }
505 :
506 : static errno_t
507 0 : hbac_eval_user_element(TALLOC_CTX *mem_ctx,
508 : struct sss_domain_info *domain,
509 : const char *username,
510 : struct hbac_request_element **user_element)
511 : {
512 : errno_t ret;
513 : unsigned int i;
514 0 : unsigned int num_groups = 0;
515 : TALLOC_CTX *tmp_ctx;
516 : const char *member_dn;
517 : struct hbac_request_element *users;
518 : struct ldb_message *msg;
519 : struct ldb_message_element *el;
520 0 : const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
521 :
522 0 : tmp_ctx = talloc_new(mem_ctx);
523 0 : if (tmp_ctx == NULL) return ENOMEM;
524 :
525 0 : users = talloc_zero(tmp_ctx, struct hbac_request_element);
526 0 : if (users == NULL) {
527 0 : ret = ENOMEM;
528 0 : goto done;
529 : }
530 :
531 0 : users->name = username;
532 :
533 : /* Read the originalMemberOf attribute
534 : * This will give us the list of both POSIX and
535 : * non-POSIX groups that this user belongs to.
536 : */
537 0 : ret = sysdb_search_user_by_name(tmp_ctx, domain, users->name,
538 : attrs, &msg);
539 0 : if (ret != EOK) {
540 0 : DEBUG(SSSDBG_CRIT_FAILURE,
541 : "Could not determine user memberships for [%s]\n",
542 : users->name);
543 0 : goto done;
544 : }
545 :
546 0 : el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF);
547 0 : if (el == NULL || el->num_values == 0) {
548 0 : DEBUG(SSSDBG_TRACE_LIBS, "No groups for [%s]\n", users->name);
549 0 : ret = create_empty_grouplist(users);
550 0 : goto done;
551 : }
552 0 : DEBUG(SSSDBG_TRACE_LIBS,
553 : "[%d] groups for [%s]\n", el->num_values, users->name);
554 :
555 0 : users->groups = talloc_array(users, const char *, el->num_values + 1);
556 0 : if (users->groups == NULL) {
557 0 : ret = ENOMEM;
558 0 : goto done;
559 : }
560 :
561 0 : for (i = 0; i < el->num_values; i++) {
562 0 : member_dn = (const char *)el->values[i].data;
563 :
564 0 : ret = get_ipa_groupname(users->groups, domain->sysdb, member_dn,
565 0 : &users->groups[num_groups]);
566 0 : if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) {
567 0 : DEBUG(SSSDBG_MINOR_FAILURE,
568 : "Skipping malformed entry [%s]\n", member_dn);
569 0 : continue;
570 0 : } else if (ret == EOK) {
571 0 : DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n",
572 : users->groups[num_groups], users->name);
573 0 : num_groups++;
574 0 : continue;
575 : }
576 : /* Skip entries that are not groups */
577 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
578 : "Skipping non-group memberOf [%s]\n", member_dn);
579 : }
580 0 : users->groups[num_groups] = NULL;
581 :
582 0 : if (num_groups < el->num_values) {
583 : /* Shrink the array memory */
584 0 : users->groups = talloc_realloc(users, users->groups, const char *,
585 : num_groups+1);
586 0 : if (users->groups == NULL) {
587 0 : ret = ENOMEM;
588 0 : goto done;
589 : }
590 : }
591 :
592 0 : ret = EOK;
593 : done:
594 0 : if (ret == EOK) {
595 0 : *user_element = talloc_steal(mem_ctx, users);
596 : }
597 0 : talloc_free(tmp_ctx);
598 0 : return ret;
599 : }
600 :
601 : static errno_t
602 0 : hbac_eval_service_element(TALLOC_CTX *mem_ctx,
603 : struct sss_domain_info *domain,
604 : const char *servicename,
605 : struct hbac_request_element **svc_element)
606 : {
607 : errno_t ret;
608 : size_t i, j, count;
609 : TALLOC_CTX *tmp_ctx;
610 : struct hbac_request_element *svc;
611 : struct ldb_message **msgs;
612 : struct ldb_message_element *el;
613 : struct ldb_dn *svc_dn;
614 0 : const char *memberof_attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
615 : char *name;
616 :
617 0 : tmp_ctx = talloc_new(mem_ctx);
618 0 : if (tmp_ctx == NULL) return ENOMEM;
619 :
620 0 : svc = talloc_zero(tmp_ctx, struct hbac_request_element);
621 0 : if (svc == NULL) {
622 0 : ret = ENOMEM;
623 0 : goto done;
624 : }
625 :
626 0 : svc->name = servicename;
627 :
628 0 : svc_dn = sysdb_custom_dn(tmp_ctx, domain, svc->name, HBAC_SERVICES_SUBDIR);
629 0 : if (svc_dn == NULL) {
630 0 : ret = ENOMEM;
631 0 : goto done;
632 : }
633 :
634 : /* Look up the service to get its originalMemberOf entries */
635 0 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, svc_dn,
636 : LDB_SCOPE_BASE, NULL,
637 : memberof_attrs,
638 : &count, &msgs);
639 0 : if (ret == ENOENT || count == 0) {
640 : /* We won't be able to identify any groups
641 : * This rule will only match the name or
642 : * a service category of ALL
643 : */
644 0 : ret = create_empty_grouplist(svc);
645 0 : goto done;
646 0 : } else if (ret != EOK) {
647 0 : goto done;
648 0 : } else if (count > 1) {
649 0 : DEBUG(SSSDBG_CRIT_FAILURE, "More than one result for a BASE search!\n");
650 0 : ret = EIO;
651 0 : goto done;
652 : }
653 :
654 0 : el = ldb_msg_find_element(msgs[0], SYSDB_ORIG_MEMBEROF);
655 0 : if (!el) {
656 : /* Service is not a member of any groups
657 : * This rule will only match the name or
658 : * a service category of ALL
659 : */
660 0 : ret = create_empty_grouplist(svc);
661 0 : goto done;
662 : }
663 :
664 :
665 0 : svc->groups = talloc_array(svc, const char *, el->num_values + 1);
666 0 : if (svc->groups == NULL) {
667 0 : ret = ENOMEM;
668 0 : goto done;
669 : }
670 :
671 0 : for (i = j = 0; i < el->num_values; i++) {
672 0 : ret = get_ipa_servicegroupname(tmp_ctx, domain->sysdb,
673 0 : (const char *)el->values[i].data,
674 : &name);
675 0 : if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) {
676 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Skipping malformed entry [%s]\n",
677 : (const char *)el->values[i].data);
678 0 : continue;
679 : }
680 :
681 : /* ERR_UNEXPECTED_ENTRY_TYPE means we had a memberOf entry that wasn't a
682 : * service group. We'll just ignore those (could be
683 : * HBAC rules)
684 : */
685 :
686 0 : if (ret == EOK) {
687 0 : svc->groups[j] = talloc_steal(svc->groups, name);
688 0 : j++;
689 : }
690 : }
691 0 : svc->groups[j] = NULL;
692 :
693 0 : ret = EOK;
694 :
695 : done:
696 0 : if (ret == EOK) {
697 0 : *svc_element = talloc_steal(mem_ctx, svc);
698 : }
699 0 : talloc_free(tmp_ctx);
700 0 : return ret;
701 : }
702 :
703 : static errno_t
704 0 : hbac_eval_host_element(TALLOC_CTX *mem_ctx,
705 : struct sss_domain_info *domain,
706 : const char *hostname,
707 : struct hbac_request_element **host_element)
708 : {
709 : errno_t ret;
710 : size_t i, j, count;
711 : TALLOC_CTX *tmp_ctx;
712 : struct hbac_request_element *host;
713 : struct ldb_message **msgs;
714 : struct ldb_message_element *el;
715 : struct ldb_dn *host_dn;
716 0 : const char *memberof_attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
717 : char *name;
718 :
719 0 : tmp_ctx = talloc_new(mem_ctx);
720 0 : if (tmp_ctx == NULL) return ENOMEM;
721 :
722 0 : host = talloc_zero(tmp_ctx, struct hbac_request_element);
723 0 : if (host == NULL) {
724 0 : ret = ENOMEM;
725 0 : goto done;
726 : }
727 :
728 0 : host->name = hostname;
729 :
730 0 : if (host->name == NULL) {
731 : /* We don't know the host (probably an rhost)
732 : * So we can't determine it's groups either.
733 : */
734 0 : ret = create_empty_grouplist(host);
735 0 : goto done;
736 : }
737 :
738 0 : host_dn = sysdb_custom_dn(tmp_ctx, domain, host->name, HBAC_HOSTS_SUBDIR);
739 0 : if (host_dn == NULL) {
740 0 : ret = ENOMEM;
741 0 : goto done;
742 : }
743 :
744 : /* Look up the host to get its originalMemberOf entries */
745 0 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, host_dn,
746 : LDB_SCOPE_BASE, NULL,
747 : memberof_attrs,
748 : &count, &msgs);
749 0 : if (ret == ENOENT || count == 0) {
750 : /* We won't be able to identify any groups
751 : * This rule will only match the name or
752 : * a host category of ALL
753 : */
754 0 : ret = create_empty_grouplist(host);
755 0 : goto done;
756 0 : } else if (ret != EOK) {
757 0 : goto done;
758 0 : } else if (count > 1) {
759 0 : DEBUG(SSSDBG_CRIT_FAILURE, "More than one result for a BASE search!\n");
760 0 : ret = EIO;
761 0 : goto done;
762 : }
763 :
764 0 : el = ldb_msg_find_element(msgs[0], SYSDB_ORIG_MEMBEROF);
765 0 : if (!el) {
766 : /* Host is not a member of any groups
767 : * This rule will only match the name or
768 : * a host category of ALL
769 : */
770 0 : ret = create_empty_grouplist(host);
771 0 : goto done;
772 : }
773 :
774 :
775 0 : host->groups = talloc_array(host, const char *, el->num_values + 1);
776 0 : if (host->groups == NULL) {
777 0 : ret = ENOMEM;
778 0 : goto done;
779 : }
780 :
781 0 : for (i = j = 0; i < el->num_values; i++) {
782 0 : ret = get_ipa_hostgroupname(tmp_ctx, domain->sysdb,
783 0 : (const char *)el->values[i].data,
784 : &name);
785 0 : if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) {
786 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Skipping malformed entry [%s]\n",
787 : (const char *)el->values[i].data);
788 0 : continue;
789 : }
790 :
791 : /* ERR_UNEXPECTED_ENTRY_TYPE means we had a memberOf entry that wasn't a
792 : * host group. We'll just ignore those (could be
793 : * HBAC rules)
794 : */
795 :
796 0 : if (ret == EOK) {
797 0 : host->groups[j] = talloc_steal(host->groups, name);
798 0 : j++;
799 : }
800 : }
801 0 : host->groups[j] = NULL;
802 :
803 0 : ret = EOK;
804 :
805 : done:
806 0 : if (ret == EOK) {
807 0 : *host_element = talloc_steal(mem_ctx, host);
808 : }
809 0 : talloc_free(tmp_ctx);
810 0 : return ret;
811 : }
|