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