Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2015 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 : #include <dhash.h>
24 :
25 : #include "providers/ldap/sdap_ops.h"
26 : #include "providers/ldap/sdap_sudo_shared.h"
27 : #include "providers/ipa/ipa_common.h"
28 : #include "providers/ipa/ipa_hosts.h"
29 : #include "providers/ipa/ipa_sudo.h"
30 : #include "providers/ipa/ipa_dn.h"
31 : #include "db/sysdb.h"
32 : #include "db/sysdb_sudo.h"
33 :
34 : struct ipa_hostinfo {
35 : size_t num_hosts;
36 : size_t num_hostgroups;
37 : struct sysdb_attrs **hosts;
38 : struct sysdb_attrs **hostgroups;
39 : };
40 :
41 : static char *
42 0 : ipa_sudo_filter_append_origdn(char *filter,
43 : struct sysdb_attrs *attrs,
44 : const char *attr_name)
45 : {
46 : const char *origdn;
47 : char *sanitizeddn;
48 : errno_t ret;
49 :
50 0 : ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &origdn);
51 0 : if (ret != EOK) {
52 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original DN "
53 : "[%d]: %s\n", ret, sss_strerror(ret));
54 0 : return NULL;
55 : }
56 :
57 0 : ret = sss_filter_sanitize(NULL, origdn, &sanitizeddn);
58 0 : if (ret != EOK) {
59 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize DN "
60 : "[%d]: %s\n", ret, sss_strerror(ret));
61 0 : return NULL;
62 : }
63 :
64 0 : filter = talloc_asprintf_append(filter, "(%s=%s)", attr_name, sanitizeddn);
65 0 : talloc_free(sanitizeddn);
66 0 : if (filter == NULL) {
67 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append() failed\n");
68 : }
69 :
70 0 : return filter;
71 : }
72 :
73 : /**
74 : * (|(hostCategory=ALL)(memberHost=$DN(fqdn))(memberHost=$DN(hostgroup))...)
75 : */
76 : static char *
77 0 : ipa_sudo_host_filter(TALLOC_CTX *mem_ctx,
78 : struct ipa_hostinfo *host,
79 : struct sdap_attr_map *map)
80 : {
81 : TALLOC_CTX *tmp_ctx;
82 : char *filter;
83 : size_t i;
84 :
85 : /* If realloc fails we will free all data through tmp_ctx. */
86 0 : tmp_ctx = talloc_new(NULL);
87 0 : if (tmp_ctx == NULL) {
88 0 : return NULL;
89 : }
90 :
91 0 : filter = talloc_asprintf(tmp_ctx, "(!(%s=*))",
92 0 : map[IPA_AT_SUDORULE_HOST].name);
93 0 : if (filter == NULL) {
94 0 : goto fail;
95 : }
96 :
97 : /* Append hostCategory=ALL */
98 0 : filter = talloc_asprintf_append(filter, "(%s=ALL)",
99 0 : map[IPA_AT_SUDORULE_HOSTCATEGORY].name);
100 0 : if (filter == NULL) {
101 0 : goto fail;
102 : }
103 :
104 : /* Append client machine */
105 0 : for (i = 0; i < host->num_hosts; i++) {
106 0 : filter = ipa_sudo_filter_append_origdn(filter, host->hosts[i],
107 0 : map[IPA_AT_SUDORULE_HOST].name);
108 0 : if (filter == NULL) {
109 0 : goto fail;
110 : }
111 : }
112 :
113 : /* Append hostgroups */
114 0 : for (i = 0; i < host->num_hostgroups; i++) {
115 0 : filter = ipa_sudo_filter_append_origdn(filter, host->hostgroups[i],
116 0 : map[IPA_AT_SUDORULE_HOST].name);
117 0 : if (filter == NULL) {
118 0 : goto fail;
119 : }
120 : }
121 :
122 : /* OR filters */
123 0 : filter = talloc_asprintf(tmp_ctx, "(|%s)", filter);
124 0 : if (filter == NULL) {
125 0 : goto fail;
126 : }
127 :
128 0 : talloc_steal(mem_ctx, filter);
129 0 : talloc_free(tmp_ctx);
130 0 : return filter;
131 :
132 : fail:
133 0 : talloc_free(tmp_ctx);
134 0 : return NULL;
135 : }
136 :
137 : static errno_t
138 0 : ipa_sudo_highest_usn(TALLOC_CTX *mem_ctx,
139 : struct sysdb_attrs **attrs,
140 : size_t num_attrs,
141 : char **current_usn)
142 : {
143 : errno_t ret;
144 : char *usn;
145 :
146 0 : ret = sysdb_get_highest_usn(mem_ctx, attrs, num_attrs, &usn);
147 0 : if (ret != EOK) {
148 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n",
149 : ret, sss_strerror(ret));
150 0 : return ret;
151 : }
152 :
153 0 : if (sysdb_compare_usn(usn, *current_usn) > 0) {
154 0 : talloc_free(*current_usn);
155 0 : *current_usn = usn;
156 0 : return EOK;
157 : }
158 :
159 0 : talloc_free(usn);
160 0 : return EOK;
161 : }
162 :
163 : static errno_t
164 0 : ipa_sudo_assoc_rules_filter(TALLOC_CTX *mem_ctx,
165 : struct sysdb_attrs **cmdgroups,
166 : size_t num_cmdgroups,
167 : char **_filter)
168 : {
169 : TALLOC_CTX *tmp_ctx;
170 : const char *origdn;
171 : char *sanitized;
172 : char *filter;
173 : errno_t ret;
174 : size_t i;
175 :
176 0 : if (num_cmdgroups == 0) {
177 0 : return ENOENT;
178 : }
179 :
180 0 : tmp_ctx = talloc_new(NULL);
181 0 : if (tmp_ctx == NULL) {
182 0 : return ENOMEM;
183 : }
184 :
185 0 : filter = talloc_strdup(tmp_ctx, "");
186 0 : if (filter == NULL) {
187 0 : ret = ENOMEM;
188 0 : goto done;
189 : }
190 :
191 0 : for (i = 0; i < num_cmdgroups; i++) {
192 0 : ret = sysdb_attrs_get_string(cmdgroups[i], SYSDB_ORIG_DN, &origdn);
193 0 : if (ret != EOK) {
194 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original dn [%d]: %s\n",
195 : ret, sss_strerror(ret));
196 0 : ret = ERR_INTERNAL;
197 0 : goto done;
198 : }
199 :
200 0 : ret = sss_filter_sanitize(tmp_ctx, origdn, &sanitized);
201 0 : if (ret != EOK) {
202 0 : goto done;
203 : }
204 :
205 0 : filter = talloc_asprintf_append(filter, "(%s=%s)",
206 : SYSDB_IPA_SUDORULE_ORIGCMD, sanitized);
207 0 : if (filter == NULL) {
208 0 : ret = ENOMEM;
209 0 : goto done;
210 : }
211 : }
212 :
213 0 : filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(|%s)))",
214 : SYSDB_SUDO_CACHE_OC, filter);
215 0 : if (filter == NULL) {
216 0 : ret = ENOMEM;
217 0 : goto done;
218 : }
219 :
220 0 : *_filter = talloc_steal(mem_ctx, filter);
221 0 : ret = EOK;
222 :
223 : done:
224 0 : talloc_free(tmp_ctx);
225 0 : return ret;
226 : }
227 :
228 : static errno_t
229 0 : ipa_sudo_assoc_rules(TALLOC_CTX *mem_ctx,
230 : struct sss_domain_info *domain,
231 : struct sysdb_attrs **cmdgroups,
232 : size_t num_cmdgroups,
233 : struct sysdb_attrs ***_rules,
234 : size_t *_num_rules)
235 : {
236 : TALLOC_CTX *tmp_ctx;
237 0 : const char *attrs[] = {SYSDB_NAME, NULL};
238 : struct sysdb_attrs **rules;
239 : struct ldb_message **msgs;
240 : size_t num_rules;
241 : char *filter;
242 : errno_t ret;
243 :
244 0 : tmp_ctx = talloc_new(NULL);
245 0 : if (tmp_ctx == NULL) {
246 0 : return ENOMEM;
247 : }
248 :
249 0 : ret = ipa_sudo_assoc_rules_filter(tmp_ctx, cmdgroups,
250 : num_cmdgroups, &filter);
251 0 : if (ret != EOK) {
252 0 : goto done;
253 : }
254 :
255 0 : ret = sysdb_search_custom(tmp_ctx, domain, filter,
256 : SUDORULE_SUBDIR, attrs,
257 : &num_rules, &msgs);
258 0 : if (ret == ENOENT) {
259 0 : *_rules = NULL;
260 0 : *_num_rules = 0;
261 0 : ret = EOK;
262 0 : goto done;
263 0 : } else if (ret != EOK) {
264 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up sudo rules [%d]: %s\n",
265 : ret, sss_strerror(ret));
266 0 : goto done;
267 : }
268 :
269 0 : ret = sysdb_msg2attrs(tmp_ctx, num_rules, msgs, &rules);
270 0 : if (ret != EOK) {
271 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not convert ldb message to "
272 : "sysdb_attrs [%d]: %s\n", ret, sss_strerror(ret));
273 0 : goto done;
274 : }
275 :
276 0 : *_rules = talloc_steal(mem_ctx, rules);
277 0 : *_num_rules = num_rules;
278 :
279 : done:
280 0 : talloc_free(tmp_ctx);
281 0 : return ret;
282 : }
283 :
284 : static errno_t
285 0 : ipa_sudo_filter_rules_bycmdgroups(TALLOC_CTX *mem_ctx,
286 : struct sss_domain_info *domain,
287 : struct sysdb_attrs **cmdgroups,
288 : size_t num_cmdgroups,
289 : struct sdap_attr_map *map_rule,
290 : char **_filter)
291 : {
292 : TALLOC_CTX *tmp_ctx;
293 : struct sysdb_attrs **rules;
294 : size_t num_rules;
295 : const char *name;
296 : char *sanitized;
297 : char *filter;
298 : errno_t ret;
299 : size_t i;
300 :
301 0 : if (num_cmdgroups == 0) {
302 0 : *_filter = NULL;
303 0 : return EOK;
304 : }
305 :
306 0 : tmp_ctx = talloc_new(NULL);
307 0 : if (tmp_ctx == NULL) {
308 0 : return ENOMEM;
309 : }
310 :
311 0 : ret = ipa_sudo_assoc_rules(tmp_ctx, domain, cmdgroups, num_cmdgroups,
312 : &rules, &num_rules);
313 0 : if (ret != EOK) {
314 0 : goto done;
315 : }
316 :
317 0 : if (num_rules == 0) {
318 0 : *_filter = NULL;
319 0 : ret = EOK;
320 0 : goto done;
321 : }
322 :
323 0 : filter = talloc_strdup(tmp_ctx, "");
324 0 : if (filter == NULL) {
325 0 : ret = ENOMEM;
326 0 : goto done;
327 : }
328 :
329 0 : for (i = 0; i < num_rules; i++) {
330 0 : ret = sysdb_attrs_get_string(rules[i], SYSDB_NAME, &name);
331 0 : if (ret != EOK) {
332 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get name [%d]: %s\n",
333 : ret, sss_strerror(ret));
334 0 : goto done;
335 : }
336 :
337 0 : ret = sss_filter_sanitize(tmp_ctx, name, &sanitized);
338 0 : if (ret != EOK) {
339 0 : goto done;
340 : }
341 :
342 0 : filter = talloc_asprintf_append(filter, "(%s=%s)",
343 0 : map_rule[IPA_AT_SUDORULE_NAME].name, sanitized);
344 0 : if (filter == NULL) {
345 0 : ret = ENOMEM;
346 0 : goto done;
347 : }
348 : }
349 :
350 0 : filter = talloc_asprintf(tmp_ctx, "(|%s)", filter);
351 0 : if (filter == NULL) {
352 0 : ret = ENOMEM;
353 0 : goto done;
354 : }
355 :
356 0 : *_filter = talloc_steal(mem_ctx, filter);
357 0 : ret = EOK;
358 :
359 : done:
360 0 : talloc_free(tmp_ctx);
361 0 : return ret;
362 : }
363 :
364 : struct ipa_sudo_fetch_state {
365 : struct tevent_context *ev;
366 : struct sysdb_ctx *sysdb;
367 : struct sss_domain_info *domain;
368 : struct ipa_sudo_ctx *sudo_ctx;
369 : struct sdap_options *sdap_opts;
370 : struct ipa_hostinfo *host;
371 : struct sdap_handle *sh;
372 : const char *search_filter;
373 : const char *cmdgroups_filter;
374 :
375 : struct sdap_attr_map *map_cmdgroup;
376 : struct sdap_attr_map *map_rule;
377 : struct sdap_attr_map *map_cmd;
378 : struct sdap_search_base **sudo_sb;
379 :
380 : struct ipa_sudo_conv *conv;
381 : struct sysdb_attrs **rules;
382 : size_t num_rules;
383 : char *usn;
384 : };
385 :
386 : static errno_t ipa_sudo_fetch_addtl_cmdgroups(struct tevent_req *req);
387 : static void ipa_sudo_fetch_addtl_cmdgroups_done(struct tevent_req *subreq);
388 : static errno_t ipa_sudo_fetch_rules(struct tevent_req *req);
389 : static void ipa_sudo_fetch_rules_done(struct tevent_req *subreq);
390 : static errno_t ipa_sudo_fetch_cmdgroups(struct tevent_req *req);
391 : static void ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq);
392 : static errno_t ipa_sudo_fetch_cmds(struct tevent_req *req);
393 : static void ipa_sudo_fetch_cmds_done(struct tevent_req *subreq);
394 : static void ipa_sudo_fetch_done(struct tevent_req *req);
395 :
396 : static struct tevent_req *
397 0 : ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx,
398 : struct tevent_context *ev,
399 : struct sss_domain_info *domain,
400 : struct sysdb_ctx *sysdb,
401 : struct ipa_sudo_ctx *sudo_ctx,
402 : struct ipa_hostinfo *host,
403 : struct sdap_attr_map *map_user,
404 : struct sdap_attr_map *map_group,
405 : struct sdap_attr_map *map_host,
406 : struct sdap_attr_map *map_hostgroup,
407 : struct sdap_handle *sh,
408 : const char *cmdgroups_filter,
409 : const char *search_filter)
410 : {
411 0 : struct ipa_sudo_fetch_state *state = NULL;
412 0 : struct tevent_req *req = NULL;
413 : errno_t ret;
414 :
415 0 : req = tevent_req_create(mem_ctx, &state,
416 : struct ipa_sudo_fetch_state);
417 0 : if (req == NULL) {
418 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
419 0 : return NULL;
420 : }
421 :
422 0 : state->ev = ev;
423 0 : state->sysdb = sysdb;
424 0 : state->domain = domain;
425 0 : state->sudo_ctx = sudo_ctx;
426 0 : state->sdap_opts = sudo_ctx->sdap_opts;
427 0 : state->host = host;
428 0 : state->sh = sh;
429 0 : state->search_filter = search_filter == NULL ? "" : search_filter;
430 0 : state->cmdgroups_filter = cmdgroups_filter;
431 :
432 0 : state->map_cmdgroup = sudo_ctx->sudocmdgroup_map;
433 0 : state->map_rule = sudo_ctx->sudorule_map;
434 0 : state->map_cmd = sudo_ctx->sudocmd_map;
435 0 : state->sudo_sb = sudo_ctx->sudo_sb;
436 :
437 0 : state->conv = ipa_sudo_conv_init(state, sysdb, state->map_rule,
438 0 : state->map_cmdgroup, state->map_cmd,
439 : map_user, map_group, map_host,
440 : map_hostgroup);
441 0 : if (state->conv == NULL) {
442 0 : ret = ENOMEM;
443 0 : goto immediately;
444 : }
445 :
446 0 : if (state->cmdgroups_filter != NULL) {
447 : /* We need to fetch additional cmdgroups that may not be revealed
448 : * during normal search. Such as when using entryUSN filter in smart
449 : * refresh, some command groups may have change but none rule was
450 : * modified but we need to fetch associated rules anyway. */
451 0 : ret = ipa_sudo_fetch_addtl_cmdgroups(req);
452 : } else {
453 0 : ret = ipa_sudo_fetch_rules(req);
454 : }
455 0 : if (ret != EAGAIN) {
456 0 : goto immediately;
457 : }
458 :
459 0 : return req;
460 :
461 : immediately:
462 0 : if (ret == EOK) {
463 0 : tevent_req_done(req);
464 : } else {
465 0 : tevent_req_error(req, ret);
466 : }
467 0 : tevent_req_post(req, state->ev);
468 :
469 0 : return req;
470 : }
471 :
472 : static errno_t
473 0 : ipa_sudo_fetch_addtl_cmdgroups(struct tevent_req *req)
474 : {
475 : struct ipa_sudo_fetch_state *state;
476 : struct tevent_req *subreq;
477 : struct sdap_attr_map *map;
478 : char *filter;
479 :
480 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to fetch additional command groups\n");
481 :
482 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
483 0 : map = state->map_cmdgroup;
484 :
485 0 : filter = talloc_asprintf(state, "(&(objectClass=%s)%s)",
486 : map[IPA_OC_SUDOCMDGROUP].name,
487 : state->cmdgroups_filter);
488 0 : if (filter == NULL) {
489 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
490 0 : return ENOMEM;
491 : }
492 :
493 0 : subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
494 : state->sh, state->sudo_sb, map, true, 0,
495 : filter, NULL);
496 0 : if (subreq == NULL) {
497 0 : return ENOMEM;
498 : }
499 :
500 0 : tevent_req_set_callback(subreq, ipa_sudo_fetch_addtl_cmdgroups_done, req);
501 0 : return EAGAIN;
502 : }
503 :
504 : static void
505 0 : ipa_sudo_fetch_addtl_cmdgroups_done(struct tevent_req *subreq)
506 : {
507 0 : struct ipa_sudo_fetch_state *state = NULL;
508 0 : struct tevent_req *req = NULL;
509 : struct sysdb_attrs **attrs;
510 : size_t num_attrs;
511 : char *filter;
512 : errno_t ret;
513 :
514 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
515 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
516 :
517 0 : ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
518 0 : talloc_zfree(subreq);
519 0 : if (ret != EOK) {
520 0 : goto done;
521 : }
522 :
523 0 : DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu additional command groups\n",
524 : num_attrs);
525 :
526 0 : ret = ipa_sudo_filter_rules_bycmdgroups(state, state->domain, attrs,
527 : num_attrs, state->map_rule,
528 : &filter);
529 0 : if (ret != EOK) {
530 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct rules filter "
531 : "[%d]: %s\n", ret, sss_strerror(ret));
532 0 : goto done;
533 : }
534 :
535 0 : state->search_filter = sdap_or_filters(state, state->search_filter, filter);
536 0 : if (state->search_filter == NULL) {
537 0 : ret = ENOMEM;
538 0 : goto done;
539 : }
540 :
541 0 : ret = ipa_sudo_fetch_rules(req);
542 :
543 : done:
544 0 : if (ret == EOK) {
545 0 : ipa_sudo_fetch_done(req);
546 0 : } else if (ret != EAGAIN) {
547 0 : tevent_req_error(req, ret);
548 : }
549 :
550 0 : return;
551 : }
552 :
553 : static errno_t
554 0 : ipa_sudo_fetch_rules(struct tevent_req *req)
555 : {
556 : struct ipa_sudo_fetch_state *state;
557 : struct tevent_req *subreq;
558 : struct sdap_attr_map *map;
559 : char *host_filter;
560 : char *filter;
561 :
562 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo rules\n");
563 :
564 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
565 0 : map = state->map_rule;
566 :
567 0 : host_filter = ipa_sudo_host_filter(state, state->host, map);
568 0 : if (host_filter == NULL) {
569 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build host filter\n");
570 0 : return ENOMEM;
571 : }
572 :
573 0 : filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=TRUE)%s%s)",
574 : map[IPA_OC_SUDORULE].name,
575 0 : map[IPA_AT_SUDORULE_ENABLED].name,
576 : host_filter, state->search_filter);
577 0 : talloc_zfree(host_filter);
578 0 : if (filter == NULL) {
579 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
580 0 : return ENOMEM;
581 : }
582 :
583 0 : subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
584 : state->sh, state->sudo_sb, map, true, 0,
585 : filter, NULL);
586 0 : if (subreq == NULL) {
587 0 : return ENOMEM;
588 : }
589 :
590 0 : tevent_req_set_callback(subreq, ipa_sudo_fetch_rules_done, req);
591 0 : return EAGAIN;
592 : }
593 :
594 : static void
595 0 : ipa_sudo_fetch_rules_done(struct tevent_req *subreq)
596 : {
597 0 : struct ipa_sudo_fetch_state *state = NULL;
598 0 : struct tevent_req *req = NULL;
599 : struct sysdb_attrs **attrs;
600 : size_t num_attrs;
601 : errno_t ret;
602 :
603 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
604 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
605 :
606 0 : ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
607 0 : talloc_zfree(subreq);
608 0 : if (ret != EOK) {
609 0 : goto done;
610 : }
611 :
612 0 : DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", num_attrs);
613 :
614 0 : ret = ipa_sudo_conv_rules(state->conv, attrs, num_attrs);
615 0 : if (ret != EOK) {
616 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting rules "
617 : "[%d]: %s\n", ret, sss_strerror(ret));
618 0 : goto done;
619 : }
620 :
621 0 : ret = ipa_sudo_highest_usn(state, attrs, num_attrs, &state->usn);
622 0 : if (ret != EOK) {
623 0 : goto done;
624 : }
625 :
626 0 : ret = ipa_sudo_fetch_cmdgroups(req);
627 :
628 : done:
629 0 : if (ret == EOK) {
630 0 : ipa_sudo_fetch_done(req);
631 0 : } else if (ret != EAGAIN) {
632 0 : tevent_req_error(req, ret);
633 : }
634 :
635 0 : return;
636 : }
637 :
638 : static errno_t
639 0 : ipa_sudo_fetch_cmdgroups(struct tevent_req *req)
640 : {
641 : struct ipa_sudo_fetch_state *state;
642 : struct tevent_req *subreq;
643 : char *filter;
644 :
645 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo command groups\n");
646 :
647 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
648 :
649 0 : if (ipa_sudo_conv_has_cmdgroups(state->conv)) {
650 0 : DEBUG(SSSDBG_TRACE_FUNC, "No command groups needs to be downloaded\n");
651 0 : return ipa_sudo_fetch_cmds(req);
652 : }
653 :
654 0 : filter = ipa_sudo_conv_cmdgroup_filter(state, state->conv);
655 0 : if (filter == NULL) {
656 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
657 0 : return ENOMEM;
658 : }
659 :
660 0 : subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
661 : state->sh, state->sudo_sb,
662 : state->map_cmdgroup, true, 0,
663 : filter, NULL);
664 0 : if (subreq == NULL) {
665 0 : return ENOMEM;
666 : }
667 :
668 0 : tevent_req_set_callback(subreq, ipa_sudo_fetch_cmdgroups_done, req);
669 0 : return EAGAIN;
670 : }
671 :
672 : static void
673 0 : ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq)
674 : {
675 0 : struct ipa_sudo_fetch_state *state = NULL;
676 0 : struct tevent_req *req = NULL;
677 : struct sysdb_attrs **attrs;
678 : size_t num_attrs;
679 : errno_t ret;
680 :
681 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
682 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
683 :
684 0 : ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
685 0 : talloc_zfree(subreq);
686 0 : if (ret != EOK) {
687 0 : goto done;
688 : }
689 :
690 0 : DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo command groups\n",
691 : num_attrs);
692 :
693 0 : ret = ipa_sudo_conv_cmdgroups(state->conv, attrs, num_attrs);
694 0 : if (ret != EOK) {
695 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting command groups "
696 : "[%d]: %s\n", ret, sss_strerror(ret));
697 0 : goto done;
698 : }
699 :
700 0 : ret = ipa_sudo_highest_usn(state, attrs, num_attrs, &state->usn);
701 0 : if (ret != EOK) {
702 0 : goto done;
703 : }
704 :
705 0 : ret = ipa_sudo_fetch_cmds(req);
706 :
707 : done:
708 0 : if (ret == EOK) {
709 0 : ipa_sudo_fetch_done(req);
710 0 : } else if (ret != EAGAIN) {
711 0 : tevent_req_error(req, ret);
712 : }
713 :
714 0 : return;
715 : }
716 :
717 : static errno_t
718 0 : ipa_sudo_fetch_cmds(struct tevent_req *req)
719 : {
720 : struct ipa_sudo_fetch_state *state;
721 : struct tevent_req *subreq;
722 : char *filter;
723 :
724 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo commands\n");
725 :
726 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
727 :
728 0 : if (ipa_sudo_conv_has_cmds(state->conv)) {
729 0 : DEBUG(SSSDBG_TRACE_FUNC, "No commands needs to be downloaded\n");
730 0 : return EOK;
731 : }
732 :
733 0 : filter = ipa_sudo_conv_cmd_filter(state, state->conv);
734 0 : if (filter == NULL) {
735 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
736 0 : return ENOMEM;
737 : }
738 :
739 0 : subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
740 : state->sh, state->sudo_sb,
741 : state->map_cmd, true, 0,
742 : filter, NULL);
743 0 : if (subreq == NULL) {
744 0 : return ENOMEM;
745 : }
746 :
747 0 : tevent_req_set_callback(subreq, ipa_sudo_fetch_cmds_done, req);
748 0 : return EAGAIN;
749 : }
750 :
751 : static void
752 0 : ipa_sudo_fetch_cmds_done(struct tevent_req *subreq)
753 : {
754 0 : struct ipa_sudo_fetch_state *state = NULL;
755 0 : struct tevent_req *req = NULL;
756 : struct sysdb_attrs **attrs;
757 : size_t num_attrs;
758 : errno_t ret;
759 :
760 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
761 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
762 :
763 0 : ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
764 0 : talloc_zfree(subreq);
765 0 : if (ret != EOK) {
766 0 : goto done;
767 : }
768 :
769 0 : DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo commands\n", num_attrs);
770 :
771 0 : ret = ipa_sudo_conv_cmds(state->conv, attrs, num_attrs);
772 0 : if (ret != EOK) {
773 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting commands "
774 : "[%d]: %s\n", ret, sss_strerror(ret));
775 0 : goto done;
776 : }
777 :
778 : done:
779 0 : if (ret == EOK) {
780 0 : ipa_sudo_fetch_done(req);
781 0 : } else if (ret != EAGAIN) {
782 0 : tevent_req_error(req, ret);
783 : }
784 :
785 0 : return;
786 : }
787 :
788 : static void
789 0 : ipa_sudo_fetch_done(struct tevent_req *req)
790 : {
791 0 : struct ipa_sudo_fetch_state *state = NULL;
792 : errno_t ret;
793 :
794 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
795 :
796 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to convert rules\n");
797 :
798 0 : ret = ipa_sudo_conv_result(state, state->conv,
799 : &state->rules, &state->num_rules);
800 0 : if (ret != EOK) {
801 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert rules [%d]: %s\n",
802 : ret, sss_strerror(ret));
803 0 : goto done;
804 : }
805 :
806 0 : ret = EOK;
807 :
808 : done:
809 0 : if (ret != EOK) {
810 0 : tevent_req_error(req, ret);
811 0 : return;
812 : }
813 :
814 0 : tevent_req_done(req);
815 : }
816 :
817 : static errno_t
818 0 : ipa_sudo_fetch_recv(TALLOC_CTX *mem_ctx,
819 : struct tevent_req *req,
820 : struct sysdb_attrs ***_rules,
821 : size_t *_num_rules,
822 : char **_usn)
823 : {
824 0 : struct ipa_sudo_fetch_state *state = NULL;
825 0 : state = tevent_req_data(req, struct ipa_sudo_fetch_state);
826 :
827 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
828 :
829 0 : *_rules = talloc_steal(mem_ctx, state->rules);
830 0 : *_num_rules = state->num_rules;
831 0 : *_usn = talloc_steal(mem_ctx, state->usn);
832 :
833 0 : return EOK;
834 : }
835 :
836 :
837 : struct ipa_sudo_refresh_state {
838 : struct tevent_context *ev;
839 : struct sysdb_ctx *sysdb;
840 : struct sss_domain_info *domain;
841 : struct ipa_sudo_ctx *sudo_ctx;
842 : struct ipa_options *ipa_opts;
843 : struct sdap_options *sdap_opts;
844 : const char *cmdgroups_filter;
845 : const char *search_filter;
846 : const char *delete_filter;
847 :
848 : struct sdap_id_op *sdap_op;
849 : struct sdap_handle *sh;
850 : int dp_error;
851 :
852 : struct sysdb_attrs **rules;
853 : size_t num_rules;
854 : };
855 :
856 : static errno_t ipa_sudo_refresh_retry(struct tevent_req *req);
857 : static void ipa_sudo_refresh_connect_done(struct tevent_req *subreq);
858 : static void ipa_sudo_refresh_host_done(struct tevent_req *subreq);
859 : static void ipa_sudo_refresh_done(struct tevent_req *subreq);
860 :
861 : struct tevent_req *
862 0 : ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx,
863 : struct tevent_context *ev,
864 : struct ipa_sudo_ctx *sudo_ctx,
865 : const char *cmdgroups_filter,
866 : const char *search_filter,
867 : const char *delete_filter)
868 : {
869 : struct ipa_sudo_refresh_state *state;
870 : struct tevent_req *req;
871 : errno_t ret;
872 :
873 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_sudo_refresh_state);
874 0 : if (req == NULL) {
875 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
876 0 : return NULL;
877 : }
878 :
879 0 : state->ev = ev;
880 0 : state->sysdb = sudo_ctx->id_ctx->be->domain->sysdb;
881 0 : state->domain = sudo_ctx->id_ctx->be->domain;
882 0 : state->sudo_ctx = sudo_ctx;
883 0 : state->ipa_opts = sudo_ctx->ipa_opts;
884 0 : state->sdap_opts = sudo_ctx->sdap_opts;
885 0 : state->dp_error = DP_ERR_FATAL;
886 :
887 0 : state->sdap_op = sdap_id_op_create(state,
888 0 : sudo_ctx->id_ctx->conn->conn_cache);
889 0 : if (!state->sdap_op) {
890 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
891 0 : ret = ENOMEM;
892 0 : goto immediately;
893 : }
894 :
895 0 : state->cmdgroups_filter = talloc_strdup(state, cmdgroups_filter);
896 0 : if (cmdgroups_filter != NULL && state->cmdgroups_filter == NULL) {
897 0 : ret = ENOMEM;
898 0 : goto immediately;
899 : }
900 :
901 0 : state->search_filter = talloc_strdup(state, search_filter);
902 0 : if (search_filter != NULL && state->search_filter == NULL) {
903 0 : ret = ENOMEM;
904 0 : goto immediately;
905 : }
906 :
907 0 : state->delete_filter = talloc_strdup(state, delete_filter);
908 0 : if (delete_filter != NULL && state->delete_filter == NULL) {
909 0 : ret = ENOMEM;
910 0 : goto immediately;
911 : }
912 :
913 0 : ret = ipa_sudo_refresh_retry(req);
914 0 : if (ret == EAGAIN) {
915 : /* asynchronous processing */
916 0 : return req;
917 : }
918 :
919 : immediately:
920 0 : if (ret == EOK) {
921 0 : tevent_req_done(req);
922 : } else {
923 0 : tevent_req_error(req, ret);
924 : }
925 0 : tevent_req_post(req, state->ev);
926 :
927 0 : return req;
928 : }
929 :
930 : static errno_t
931 0 : ipa_sudo_refresh_retry(struct tevent_req *req)
932 : {
933 : struct ipa_sudo_refresh_state *state;
934 : struct tevent_req *subreq;
935 : int ret;
936 :
937 0 : state = tevent_req_data(req, struct ipa_sudo_refresh_state);
938 :
939 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
940 0 : if (subreq == NULL) {
941 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
942 : "%d(%s)\n", ret, strerror(ret));
943 0 : return ret;
944 : }
945 :
946 0 : tevent_req_set_callback(subreq, ipa_sudo_refresh_connect_done, req);
947 :
948 0 : return EAGAIN;
949 : }
950 :
951 : static void
952 0 : ipa_sudo_refresh_connect_done(struct tevent_req *subreq)
953 : {
954 : struct ipa_sudo_refresh_state *state;
955 : const char *hostname;
956 : struct tevent_req *req;
957 : int dp_error;
958 : int ret;
959 :
960 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
961 0 : state = tevent_req_data(req, struct ipa_sudo_refresh_state);
962 :
963 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
964 0 : talloc_zfree(subreq);
965 :
966 0 : if (ret != EOK) {
967 0 : DEBUG(SSSDBG_CRIT_FAILURE, "SUDO LDAP connection failed "
968 : "[%d]: %s\n", ret, strerror(ret));
969 0 : state->dp_error = dp_error;
970 0 : tevent_req_error(req, ret);
971 0 : return;
972 : }
973 :
974 0 : state->sh = sdap_id_op_handle(state->sdap_op);
975 :
976 0 : DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n");
977 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to fetch host information\n");
978 :
979 : /* Obtain host information. */
980 0 : hostname = dp_opt_get_string(state->ipa_opts->basic, IPA_HOSTNAME);
981 :
982 0 : subreq = ipa_host_info_send(state, state->ev,
983 : state->sh, state->sdap_opts, hostname,
984 0 : state->ipa_opts->host_map,
985 0 : state->ipa_opts->hostgroup_map,
986 0 : state->ipa_opts->host_search_bases);
987 0 : if (subreq == NULL) {
988 0 : state->dp_error = DP_ERR_FATAL;
989 0 : tevent_req_error(req, ENOMEM);
990 0 : return;
991 : }
992 :
993 0 : tevent_req_set_callback(subreq, ipa_sudo_refresh_host_done, req);
994 : }
995 :
996 : static void
997 0 : ipa_sudo_refresh_host_done(struct tevent_req *subreq)
998 : {
999 : struct ipa_sudo_refresh_state *state;
1000 : struct ipa_hostinfo *host;
1001 : struct tevent_req *req;
1002 : int ret;
1003 :
1004 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1005 0 : state = tevent_req_data(req, struct ipa_sudo_refresh_state);
1006 :
1007 0 : host = talloc_zero(state, struct ipa_hostinfo);
1008 0 : if (host == NULL) {
1009 0 : state->dp_error = DP_ERR_FATAL;
1010 0 : tevent_req_error(req, ENOMEM);
1011 0 : return;
1012 : }
1013 :
1014 0 : ret = ipa_host_info_recv(subreq, host, &host->num_hosts, &host->hosts,
1015 : &host->num_hostgroups, &host->hostgroups);
1016 0 : talloc_zfree(subreq);
1017 0 : if (ret != EOK) {
1018 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve host information "
1019 : "[%d]: %s\n", ret, sss_strerror(ret));
1020 0 : state->dp_error = DP_ERR_FATAL;
1021 0 : tevent_req_error(req, ret);
1022 0 : return;
1023 : }
1024 :
1025 0 : subreq = ipa_sudo_fetch_send(state, state->ev, state->domain, state->sysdb,
1026 : state->sudo_ctx, host,
1027 0 : state->sdap_opts->user_map,
1028 0 : state->sdap_opts->group_map,
1029 0 : state->ipa_opts->host_map,
1030 0 : state->ipa_opts->hostgroup_map, state->sh,
1031 : state->cmdgroups_filter, state->search_filter);
1032 0 : if (subreq == NULL) {
1033 0 : state->dp_error = DP_ERR_FATAL;
1034 0 : tevent_req_error(req, ENOMEM);
1035 0 : return;
1036 : }
1037 :
1038 0 : tevent_req_set_callback(subreq, ipa_sudo_refresh_done, req);
1039 : }
1040 :
1041 : static void
1042 0 : ipa_sudo_refresh_done(struct tevent_req *subreq)
1043 : {
1044 : struct ipa_sudo_refresh_state *state;
1045 : struct tevent_req *req;
1046 0 : char *usn = NULL;
1047 0 : bool in_transaction = false;
1048 : errno_t sret;
1049 : int ret;
1050 :
1051 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1052 0 : state = tevent_req_data(req, struct ipa_sudo_refresh_state);
1053 :
1054 0 : ret = ipa_sudo_fetch_recv(state, subreq, &state->rules,
1055 : &state->num_rules, &usn);
1056 0 : talloc_zfree(subreq);
1057 :
1058 0 : ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error);
1059 0 : if (state->dp_error == DP_ERR_OK && ret != EOK) {
1060 : /* retry */
1061 0 : ret = ipa_sudo_refresh_retry(req);
1062 0 : if (ret != EOK) {
1063 0 : tevent_req_error(req, ret);
1064 : }
1065 0 : return;
1066 0 : } else if (ret != EOK) {
1067 0 : tevent_req_error(req, ret);
1068 0 : return;
1069 : }
1070 :
1071 0 : ret = sysdb_transaction_start(state->sysdb);
1072 0 : if (ret != EOK) {
1073 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1074 0 : goto done;
1075 : }
1076 0 : in_transaction = true;
1077 :
1078 0 : ret = sysdb_sudo_purge(state->domain, state->delete_filter,
1079 : state->rules, state->num_rules);
1080 0 : if (ret != EOK) {
1081 0 : goto done;
1082 : }
1083 :
1084 0 : ret = sysdb_sudo_store(state->domain, state->rules, state->num_rules);
1085 0 : if (ret != EOK) {
1086 0 : goto done;
1087 : }
1088 :
1089 0 : ret = sysdb_transaction_commit(state->sysdb);
1090 0 : if (ret != EOK) {
1091 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
1092 0 : goto done;
1093 : }
1094 0 : in_transaction = false;
1095 :
1096 0 : if (usn != NULL) {
1097 0 : sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn);
1098 : }
1099 :
1100 0 : DEBUG(SSSDBG_TRACE_FUNC, "Sudo rules are successfully stored in cache\n");
1101 :
1102 : done:
1103 0 : if (in_transaction) {
1104 0 : sret = sysdb_transaction_cancel(state->sysdb);
1105 0 : if (sret != EOK) {
1106 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
1107 : }
1108 : }
1109 :
1110 0 : if (ret != EOK) {
1111 0 : tevent_req_error(req, ret);
1112 0 : return;
1113 : }
1114 :
1115 0 : tevent_req_done(req);
1116 : }
1117 :
1118 : errno_t
1119 0 : ipa_sudo_refresh_recv(struct tevent_req *req,
1120 : int *dp_error,
1121 : size_t *_num_rules)
1122 : {
1123 0 : struct ipa_sudo_refresh_state *state = NULL;
1124 0 : state = tevent_req_data(req, struct ipa_sudo_refresh_state);
1125 :
1126 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1127 :
1128 0 : *dp_error = state->dp_error;
1129 :
1130 0 : if (_num_rules != NULL) {
1131 0 : *_num_rules = state->num_rules;
1132 : }
1133 :
1134 0 : return EOK;
1135 : }
|