Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Subdomains Module
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2011 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "providers/ldap/sdap_async.h"
26 : #include "providers/ldap/sdap_idmap.h"
27 : #include "providers/ipa/ipa_subdomains.h"
28 : #include "providers/ipa/ipa_common.h"
29 : #include "providers/ipa/ipa_id.h"
30 :
31 : #include <ctype.h>
32 :
33 : #define SUBDOMAINS_FILTER "objectclass=ipaNTTrustedDomain"
34 : #define MASTER_DOMAIN_FILTER "objectclass=ipaNTDomainAttrs"
35 : #define RANGE_FILTER "objectclass=ipaIDRange"
36 :
37 : #define IPA_CN "cn"
38 : #define IPA_FLATNAME "ipaNTFlatName"
39 : #define IPA_SID "ipaNTSecurityIdentifier"
40 : #define IPA_TRUSTED_DOMAIN_SID "ipaNTTrustedDomainSID"
41 : #define IPA_RANGE_TYPE "ipaRangeType"
42 :
43 : #define IPA_BASE_ID "ipaBaseID"
44 : #define IPA_ID_RANGE_SIZE "ipaIDRangeSize"
45 : #define IPA_BASE_RID "ipaBaseRID"
46 : #define IPA_SECONDARY_BASE_RID "ipaSecondaryBaseRID"
47 : #define OBJECTCLASS "objectClass"
48 :
49 : #define IPA_ASSIGNED_ID_VIEW "ipaAssignedIDView"
50 :
51 : /* do not refresh more often than every 5 seconds for now */
52 : #define IPA_SUBDOMAIN_REFRESH_LIMIT 5
53 :
54 : #define IPA_SUBDOMAIN_DISABLED_PERIOD 3600
55 :
56 : enum ipa_subdomains_req_type {
57 : IPA_SUBDOMAINS_MASTER,
58 : IPA_SUBDOMAINS_SLAVE,
59 : IPA_SUBDOMAINS_RANGES,
60 :
61 : IPA_SUBDOMAINS_MAX /* Counter */
62 : };
63 :
64 : struct ipa_subdomains_req_params {
65 : const char *filter;
66 : tevent_req_fn cb;
67 : const char *attrs[9];
68 : };
69 :
70 : struct ipa_subdomains_ctx {
71 : struct be_ctx *be_ctx;
72 : struct ipa_id_ctx *id_ctx;
73 : struct sdap_id_ctx *sdap_id_ctx;
74 : struct sdap_search_base **search_bases;
75 : struct sdap_search_base **master_search_bases;
76 : struct sdap_search_base **ranges_search_bases;
77 : struct sdap_search_base **host_search_bases;
78 :
79 : time_t last_refreshed;
80 : struct tevent_timer *timer_event;
81 : bool configured_explicit;
82 : time_t disabled_until;
83 : bool view_read_at_init;
84 : };
85 :
86 0 : static void ipa_subdomains_done(struct ipa_subdomains_ctx *sd_ctx,
87 : struct be_req *req, int dp_err,
88 : int error, const char *errstr)
89 : {
90 0 : sd_ctx->view_read_at_init = true;
91 0 : return be_req_terminate(req, dp_err, error, errstr);
92 : }
93 :
94 0 : struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx)
95 : {
96 : struct ipa_subdomains_ctx *subdom_ctx;
97 :
98 0 : subdom_ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
99 : struct ipa_subdomains_ctx);
100 0 : if (subdom_ctx == NULL) {
101 0 : DEBUG(SSSDBG_TRACE_ALL, "Subdomains are not configured.\n");
102 0 : return NULL;
103 : }
104 :
105 0 : return subdom_ctx->be_ctx;
106 : }
107 :
108 : static errno_t
109 0 : ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
110 : {
111 : errno_t ret;
112 :
113 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
114 : "Re-initializing domain %s\n", ctx->be_ctx->domain->name);
115 :
116 0 : ret = sss_write_krb5_conf_snippet(
117 0 : dp_opt_get_string(ctx->id_ctx->ipa_options->basic,
118 : IPA_KRB5_CONFD_PATH));
119 0 : if (ret != EOK) {
120 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
121 : /* Just continue */
122 : }
123 :
124 0 : ret = sysdb_master_domain_update(ctx->be_ctx->domain);
125 0 : if (ret != EOK) {
126 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed.\n");
127 0 : return ret;
128 : }
129 :
130 0 : ret = sysdb_update_subdomains(ctx->be_ctx->domain);
131 0 : if (ret != EOK) {
132 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
133 0 : return ret;
134 : }
135 :
136 0 : ret = sss_write_domain_mappings(ctx->be_ctx->domain);
137 0 : if (ret != EOK) {
138 0 : DEBUG(SSSDBG_MINOR_FAILURE,
139 : "sss_krb5_write_mappings failed.\n");
140 : /* Just continue */
141 : }
142 :
143 0 : return EOK;
144 : }
145 :
146 0 : static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx,
147 : char *domain_name,
148 : size_t count,
149 : struct sysdb_attrs **reply,
150 : struct range_info ***_range_list)
151 : {
152 0 : struct range_info **range_list = NULL;
153 : struct range_info *r;
154 : const char *value;
155 : size_t c;
156 : size_t d;
157 : int ret;
158 : enum idmap_error_code err;
159 : char *name1;
160 : char *name2;
161 : char *sid1;
162 : char *sid2;
163 : uint32_t rid1;
164 : uint32_t rid2;
165 : struct sss_idmap_range range1;
166 : struct sss_idmap_range range2;
167 : bool mapping1;
168 : bool mapping2;
169 :
170 0 : range_list = talloc_array(mem_ctx, struct range_info *, count + 1);
171 0 : if (range_list == NULL) {
172 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
173 0 : return ENOMEM;
174 : }
175 :
176 0 : for (c = 0; c < count; c++) {
177 0 : r = talloc_zero(range_list, struct range_info);
178 0 : if (r == NULL) {
179 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
180 0 : ret = ENOMEM;
181 0 : goto done;
182 : }
183 :
184 0 : ret = sysdb_attrs_get_string(reply[c], IPA_CN, &value);
185 0 : if (ret != EOK) {
186 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
187 0 : goto done;
188 : }
189 :
190 0 : r->name = talloc_strdup(r, value);
191 0 : if (r->name == NULL) {
192 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
193 0 : ret = ENOMEM;
194 0 : goto done;
195 : }
196 :
197 0 : ret = sysdb_attrs_get_string(reply[c], IPA_TRUSTED_DOMAIN_SID, &value);
198 0 : if (ret == EOK) {
199 0 : r->trusted_dom_sid = talloc_strdup(r, value);
200 0 : if (r->trusted_dom_sid == NULL) {
201 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
202 0 : ret = ENOMEM;
203 0 : goto done;
204 : }
205 0 : } else if (ret != ENOENT) {
206 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
207 0 : goto done;
208 : }
209 :
210 0 : ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_ID,
211 : &r->base_id);
212 0 : if (ret != EOK && ret != ENOENT) {
213 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
214 0 : goto done;
215 : }
216 :
217 0 : ret = sysdb_attrs_get_uint32_t(reply[c], IPA_ID_RANGE_SIZE,
218 : &r->id_range_size);
219 0 : if (ret != EOK && ret != ENOENT) {
220 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
221 0 : goto done;
222 : }
223 :
224 0 : ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_RID,
225 : &r->base_rid);
226 0 : if (ret != EOK && ret != ENOENT) {
227 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
228 0 : goto done;
229 : }
230 :
231 0 : ret = sysdb_attrs_get_uint32_t(reply[c], IPA_SECONDARY_BASE_RID,
232 : &r->secondary_base_rid);
233 0 : if (ret != EOK && ret != ENOENT) {
234 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
235 0 : goto done;
236 : }
237 :
238 0 : ret = sysdb_attrs_get_string(reply[c], IPA_RANGE_TYPE, &value);
239 0 : if (ret == EOK) {
240 0 : r->range_type = talloc_strdup(r, value);
241 0 : if (r->range_type == NULL) {
242 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
243 0 : ret = ENOMEM;
244 0 : goto done;
245 : }
246 0 : } else if (ret == ENOENT) {
247 : /* Older IPA servers might not have the range_type attribute, but
248 : * only support local ranges and trusts with algorithmic mapping. */
249 0 : if (r->trusted_dom_sid == NULL) {
250 0 : r->range_type = talloc_strdup(r, IPA_RANGE_LOCAL);
251 : } else {
252 0 : r->range_type = talloc_strdup(r, IPA_RANGE_AD_TRUST);
253 : }
254 : } else {
255 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
256 0 : goto done;
257 : }
258 0 : if (r->range_type == NULL) {
259 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
260 0 : ret = ENOMEM;
261 0 : goto done;
262 : }
263 :
264 0 : ret = get_idmap_data_from_range(r, domain_name, &name1, &sid1, &rid1,
265 : &range1, &mapping1);
266 0 : if (ret != EOK) {
267 0 : DEBUG(SSSDBG_OP_FAILURE, "get_idmap_data_from_range failed.\n");
268 0 : goto done;
269 : }
270 0 : for (d = 0; d < c; d++) {
271 0 : ret = get_idmap_data_from_range(range_list[d], domain_name, &name2,
272 : &sid2, &rid2, &range2, &mapping2);
273 0 : if (ret != EOK) {
274 0 : DEBUG(SSSDBG_OP_FAILURE,
275 : "get_idmap_data_from_range failed.\n");
276 0 : goto done;
277 : }
278 :
279 0 : err = sss_idmap_check_collision_ex(name1, sid1, &range1, rid1,
280 0 : r->name, mapping1,
281 : name2, sid2, &range2, rid2,
282 0 : range_list[d]->name, mapping2);
283 0 : if (err != IDMAP_SUCCESS) {
284 0 : DEBUG(SSSDBG_CRIT_FAILURE,
285 : "Collision of ranges [%s] and [%s] detected.\n",
286 : r->name, range_list[d]->name);
287 0 : ret = EINVAL;
288 0 : goto done;
289 : }
290 : }
291 :
292 0 : range_list[c] = r;
293 : }
294 :
295 0 : range_list[c] = NULL;
296 :
297 0 : *_range_list = range_list;
298 0 : ret = EOK;
299 :
300 : done:
301 0 : if (ret != EOK) {
302 0 : talloc_free(range_list);
303 : }
304 :
305 0 : return ret;
306 : }
307 :
308 0 : static errno_t ipa_subdom_enumerates(struct sss_domain_info *parent,
309 : struct sysdb_attrs *attrs,
310 : bool *_enumerates)
311 : {
312 : errno_t ret;
313 : const char *name;
314 :
315 0 : ret = sysdb_attrs_get_string(attrs, IPA_CN, &name);
316 0 : if (ret != EOK) {
317 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
318 0 : return ret;
319 : }
320 :
321 0 : *_enumerates = subdomain_enumerates(parent, name);
322 0 : return EOK;
323 : }
324 :
325 0 : static errno_t ipa_subdom_get_forest(TALLOC_CTX *mem_ctx,
326 : struct ldb_context *ldb_ctx,
327 : struct sysdb_attrs *attrs,
328 : char **_forest)
329 : {
330 : int ret;
331 0 : struct ldb_dn *dn = NULL;
332 : const char *name;
333 : const struct ldb_val *val;
334 0 : char *forest = NULL;
335 :
336 0 : dn = ipa_subdom_ldb_dn(mem_ctx, ldb_ctx, attrs);
337 0 : if (dn == NULL) {
338 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_subdom_ldb_dn failed.\n");
339 0 : ret = EIO;
340 0 : goto done;
341 : }
342 :
343 0 : if (ipa_subdom_is_member_dom(dn) == false) {
344 0 : ret = sysdb_attrs_get_string(attrs, IPA_CN, &name);
345 0 : if (ret) {
346 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
347 0 : goto done;
348 : }
349 :
350 0 : forest = talloc_strdup(mem_ctx, name);
351 0 : if (forest == NULL) {
352 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
353 0 : ret = ENOMEM;
354 0 : goto done;
355 : }
356 :
357 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "The forest name is %s\n", forest);
358 0 : ret = EOK;
359 0 : goto done;
360 : }
361 :
362 0 : val = ldb_dn_get_component_val(dn, 1);
363 0 : forest = talloc_strndup(mem_ctx, (const char *) val->data, val->length);
364 0 : if (forest == NULL) {
365 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
366 0 : ret = ENOMEM;
367 0 : goto done;
368 : }
369 :
370 0 : ret = EOK;
371 : done:
372 0 : talloc_free(dn);
373 :
374 0 : if (ret == EOK) {
375 0 : *_forest = forest;
376 : }
377 :
378 0 : return ret;
379 : }
380 :
381 0 : static errno_t ipa_get_sd_trust_direction(struct sysdb_attrs *sd,
382 : struct ipa_id_ctx *id_ctx,
383 : struct ldb_context *ldb_ctx,
384 : uint32_t *_direction)
385 : {
386 0 : if (id_ctx->server_mode != NULL) {
387 0 : return ipa_server_get_trust_direction(sd, ldb_ctx, _direction);
388 : } else {
389 : /* Clients do not have access to the trust objects's trust direction
390 : * and don't generally care
391 : */
392 0 : *_direction = 0;
393 0 : return EOK;
394 : }
395 : }
396 :
397 0 : static errno_t ipa_subdom_store(struct sss_domain_info *parent,
398 : struct ipa_id_ctx *id_ctx,
399 : struct sdap_idmap_ctx *sdap_idmap_ctx,
400 : struct sysdb_attrs *attrs)
401 : {
402 : TALLOC_CTX *tmp_ctx;
403 : const char *name;
404 : char *realm;
405 : const char *flat;
406 : const char *id;
407 0 : char *forest = NULL;
408 : int ret;
409 : bool mpg;
410 : bool enumerate;
411 : uint32_t direction;
412 :
413 0 : tmp_ctx = talloc_new(parent);
414 0 : if (tmp_ctx == NULL) {
415 0 : return ENOMEM;
416 : }
417 :
418 0 : ret = sysdb_attrs_get_string(attrs, IPA_CN, &name);
419 0 : if (ret != EOK) {
420 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
421 0 : goto done;
422 : }
423 :
424 0 : realm = get_uppercase_realm(tmp_ctx, name);
425 0 : if (!realm) {
426 0 : ret = ENOMEM;
427 0 : goto done;
428 : }
429 :
430 0 : ret = sysdb_attrs_get_string(attrs, IPA_FLATNAME, &flat);
431 0 : if (ret) {
432 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
433 0 : goto done;
434 : }
435 :
436 0 : ret = sysdb_attrs_get_string(attrs, IPA_TRUSTED_DOMAIN_SID, &id);
437 0 : if (ret) {
438 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
439 0 : goto done;
440 : }
441 :
442 0 : mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, name, id);
443 :
444 0 : ret = ipa_subdom_get_forest(tmp_ctx, sysdb_ctx_get_ldb(parent->sysdb),
445 : attrs, &forest);
446 0 : if (ret != EOK) {
447 0 : goto done;
448 : }
449 :
450 0 : ret = ipa_subdom_enumerates(parent, attrs, &enumerate);
451 0 : if (ret != EOK) {
452 0 : goto done;
453 : }
454 :
455 0 : ret = ipa_get_sd_trust_direction(attrs, id_ctx,
456 : sysdb_ctx_get_ldb(parent->sysdb),
457 : &direction);
458 0 : if (ret != EOK) {
459 0 : DEBUG(SSSDBG_OP_FAILURE,
460 : "ipa_get_sd_trust_direction failed: %d\n", ret);
461 0 : goto done;
462 : }
463 :
464 0 : DEBUG(SSSDBG_FUNC_DATA,
465 : "Trust direction of %s is %s\n", name, ipa_trust_dir2str(direction));
466 0 : ret = sysdb_subdomain_store(parent->sysdb, name, realm, flat,
467 : id, mpg, enumerate, forest,
468 : direction);
469 0 : if (ret) {
470 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n");
471 0 : goto done;
472 : }
473 :
474 0 : ret = EOK;
475 : done:
476 0 : talloc_free(tmp_ctx);
477 0 : return ret;
478 : }
479 :
480 0 : static void ipa_subdom_store_step(struct sss_domain_info *parent,
481 : struct ipa_id_ctx *id_ctx,
482 : struct sdap_idmap_ctx *sdap_idmap_ctx,
483 : struct sysdb_attrs *attrs)
484 : {
485 : int ret;
486 :
487 0 : ret = ipa_subdom_store(parent, id_ctx, sdap_idmap_ctx, attrs);
488 0 : if (ret == ERR_TRUST_NOT_SUPPORTED) {
489 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unsupported trust type, skipping\n");
490 0 : } else if (ret) {
491 : /* Nothing we can do about the error. */
492 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
493 : "will try to use cached subdomain\n");
494 : }
495 0 : }
496 :
497 0 : static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
498 : int count, struct sysdb_attrs **reply,
499 : bool *changes)
500 0 : {
501 : struct sss_domain_info *parent, *dom;
502 0 : bool handled[count];
503 : const char *value;
504 : int c, h;
505 : int ret;
506 :
507 0 : parent = ctx->be_ctx->domain;
508 0 : memset(handled, 0, sizeof(bool) * count);
509 0 : h = 0;
510 :
511 : /* check existing subdomains */
512 0 : for (dom = get_next_domain(parent, true);
513 0 : dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
514 0 : dom = get_next_domain(dom, false)) {
515 0 : for (c = 0; c < count; c++) {
516 0 : if (handled[c]) {
517 0 : continue;
518 : }
519 0 : ret = sysdb_attrs_get_string(reply[c], IPA_CN, &value);
520 0 : if (ret != EOK) {
521 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
522 0 : goto done;
523 : }
524 0 : if (strcmp(value, dom->name) == 0) {
525 0 : break;
526 : }
527 : }
528 :
529 0 : if (c >= count) {
530 : /* ok this subdomain does not exist anymore, let's clean up */
531 0 : sss_domain_set_state(dom, DOM_DISABLED);
532 0 : ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
533 0 : if (ret != EOK) {
534 0 : goto done;
535 : }
536 :
537 : /* Remove the AD ID ctx from the list of LDAP domains */
538 0 : ipa_ad_subdom_remove(ctx->be_ctx, ctx->id_ctx, dom);
539 : } else {
540 : /* ok let's try to update it */
541 0 : ipa_subdom_store_step(parent, ctx->id_ctx,
542 0 : ctx->sdap_id_ctx->opts->idmap_ctx,
543 0 : reply[c]);
544 0 : handled[c] = true;
545 0 : h++;
546 : }
547 : }
548 :
549 0 : if (count == h) {
550 : /* all domains were already accounted for and have been updated */
551 0 : ret = EOK;
552 0 : goto done;
553 : }
554 :
555 : /* if we get here it means we have changes to the subdomains list */
556 0 : *changes = true;
557 :
558 0 : for (c = 0; c < count; c++) {
559 0 : if (handled[c]) {
560 0 : continue;
561 : }
562 :
563 0 : ipa_subdom_store_step(parent, ctx->id_ctx,
564 0 : ctx->sdap_id_ctx->opts->idmap_ctx,
565 0 : reply[c]);
566 : }
567 :
568 0 : ret = EOK;
569 : done:
570 0 : if (ret != EOK) {
571 0 : ctx->last_refreshed = 0;
572 : } else {
573 0 : ctx->last_refreshed = time(NULL);
574 : }
575 :
576 0 : return ret;
577 : }
578 :
579 : struct ipa_subdomains_req_ctx {
580 : struct be_req *be_req;
581 : struct ipa_subdomains_ctx *sd_ctx;
582 : struct sdap_id_op *sdap_op;
583 :
584 : char *current_filter;
585 :
586 : struct sdap_search_base **search_bases;
587 : int search_base_iter;
588 :
589 : size_t reply_count;
590 : struct sysdb_attrs **reply;
591 : };
592 :
593 : static void ipa_subdomains_get_conn_done(struct tevent_req *req);
594 : static errno_t
595 : ipa_subdomains_handler_get_start(struct ipa_subdomains_req_ctx *ctx,
596 : struct sdap_search_base **search_bases,
597 : enum ipa_subdomains_req_type type);
598 : static errno_t
599 : ipa_subdomains_handler_get_cont(struct ipa_subdomains_req_ctx *ctx,
600 : enum ipa_subdomains_req_type type);
601 : static void ipa_subdomains_handler_done(struct tevent_req *req);
602 : static void ipa_subdomains_handler_master_done(struct tevent_req *req);
603 : static void ipa_subdomains_handler_ranges_done(struct tevent_req *req);
604 :
605 : static struct ipa_subdomains_req_params subdomain_requests[] = {
606 : { MASTER_DOMAIN_FILTER,
607 : ipa_subdomains_handler_master_done,
608 : { IPA_CN, IPA_FLATNAME, IPA_SID, NULL }
609 : },
610 : { SUBDOMAINS_FILTER,
611 : ipa_subdomains_handler_done,
612 : { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
613 : IPA_TRUST_DIRECTION, NULL }
614 : },
615 : { RANGE_FILTER,
616 : ipa_subdomains_handler_ranges_done,
617 : { OBJECTCLASS, IPA_CN,
618 : IPA_BASE_ID, IPA_BASE_RID, IPA_SECONDARY_BASE_RID,
619 : IPA_ID_RANGE_SIZE, IPA_TRUSTED_DOMAIN_SID, IPA_RANGE_TYPE, NULL
620 : }
621 : }
622 : };
623 :
624 0 : static void ipa_subdomains_retrieve(struct ipa_subdomains_ctx *ctx, struct be_req *be_req)
625 : {
626 0 : struct ipa_subdomains_req_ctx *req_ctx = NULL;
627 : struct tevent_req *req;
628 0 : int dp_error = DP_ERR_FATAL;
629 : int ret;
630 :
631 0 : req_ctx = talloc(be_req, struct ipa_subdomains_req_ctx);
632 0 : if (req_ctx == NULL) {
633 0 : ret = ENOMEM;
634 0 : goto done;
635 : }
636 :
637 0 : req_ctx->be_req = be_req;
638 0 : req_ctx->sd_ctx = ctx;
639 0 : req_ctx->search_base_iter = 0;
640 0 : req_ctx->search_bases = ctx->ranges_search_bases;
641 0 : req_ctx->current_filter = NULL;
642 0 : req_ctx->reply_count = 0;
643 0 : req_ctx->reply = NULL;
644 :
645 0 : req_ctx->sdap_op = sdap_id_op_create(req_ctx,
646 0 : ctx->sdap_id_ctx->conn->conn_cache);
647 0 : if (req_ctx->sdap_op == NULL) {
648 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
649 0 : ret = ENOMEM;
650 0 : goto done;
651 : }
652 :
653 0 : req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
654 0 : if (req == NULL) {
655 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
656 : ret, strerror(ret));
657 0 : goto done;
658 : }
659 :
660 0 : tevent_req_set_callback(req, ipa_subdomains_get_conn_done, req_ctx);
661 :
662 0 : return;
663 :
664 : done:
665 0 : talloc_free(req_ctx);
666 0 : if (ret == EOK) {
667 0 : dp_error = DP_ERR_OK;
668 : }
669 0 : ipa_subdomains_done(ctx, be_req, dp_error, ret, NULL);
670 : }
671 :
672 0 : static void ipa_subdomains_get_conn_done(struct tevent_req *req)
673 : {
674 : int ret;
675 0 : int dp_error = DP_ERR_FATAL;
676 : struct ipa_subdomains_req_ctx *ctx;
677 :
678 0 : ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
679 :
680 0 : ret = sdap_id_op_connect_recv(req, &dp_error);
681 0 : talloc_zfree(req);
682 0 : if (ret) {
683 0 : if (dp_error == DP_ERR_OFFLINE) {
684 0 : DEBUG(SSSDBG_MINOR_FAILURE,
685 : "No IPA server is available, cannot get the "
686 : "subdomain list while offline\n");
687 : } else {
688 0 : DEBUG(SSSDBG_OP_FAILURE,
689 : "Failed to connect to IPA server: [%d](%s)\n",
690 : ret, strerror(ret));
691 : }
692 :
693 0 : goto fail;
694 : }
695 :
696 0 : ret = ipa_subdomains_handler_get_start(ctx,
697 0 : ctx->sd_ctx->ranges_search_bases,
698 : IPA_SUBDOMAINS_RANGES);
699 0 : if (ret != EOK && ret != EAGAIN) {
700 0 : goto fail;
701 : }
702 :
703 0 : return;
704 :
705 : fail:
706 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
707 : }
708 :
709 : static errno_t
710 0 : ipa_subdomains_handler_get(struct ipa_subdomains_req_ctx *ctx,
711 : enum ipa_subdomains_req_type type)
712 : {
713 : struct tevent_req *req;
714 : struct sdap_search_base *base;
715 : struct ipa_subdomains_req_params *params;
716 :
717 0 : if (type >= IPA_SUBDOMAINS_MAX) {
718 0 : return EINVAL;
719 : }
720 :
721 0 : params = &subdomain_requests[type];
722 :
723 0 : base = ctx->search_bases[ctx->search_base_iter];
724 0 : if (base == NULL) {
725 0 : return EOK;
726 : }
727 :
728 0 : talloc_free(ctx->current_filter);
729 0 : ctx->current_filter = sdap_get_id_specific_filter(ctx, params->filter,
730 : base->filter);
731 0 : if (ctx->current_filter == NULL) {
732 0 : return ENOMEM;
733 : }
734 :
735 0 : req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
736 0 : ctx->sd_ctx->sdap_id_ctx->opts,
737 : sdap_id_op_handle(ctx->sdap_op),
738 : base->basedn, base->scope,
739 0 : ctx->current_filter, params->attrs, NULL, 0,
740 0 : dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
741 : SDAP_SEARCH_TIMEOUT), false);
742 :
743 0 : if (req == NULL) {
744 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
745 0 : return ENOMEM;
746 : }
747 :
748 0 : tevent_req_set_callback(req, params->cb, ctx);
749 :
750 0 : return EAGAIN;
751 : }
752 :
753 : static errno_t
754 0 : ipa_subdomains_handler_get_start(struct ipa_subdomains_req_ctx *ctx,
755 : struct sdap_search_base **search_bases,
756 : enum ipa_subdomains_req_type type)
757 : {
758 0 : ctx->search_base_iter = 0;
759 0 : ctx->search_bases = search_bases;
760 0 : return ipa_subdomains_handler_get(ctx, type);
761 : }
762 :
763 : static errno_t
764 0 : ipa_subdomains_handler_get_cont(struct ipa_subdomains_req_ctx *ctx,
765 : enum ipa_subdomains_req_type type)
766 : {
767 0 : ctx->search_base_iter++;
768 0 : return ipa_subdomains_handler_get(ctx, type);
769 : }
770 :
771 : static void ipa_get_view_name_done(struct tevent_req *req);
772 : static void ipa_server_create_trusts_done(struct tevent_req *trust_req);
773 : static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx);
774 :
775 0 : static errno_t ipa_get_view_name(struct ipa_subdomains_req_ctx *ctx)
776 : {
777 : struct tevent_req *req;
778 : struct sdap_search_base *base;
779 0 : const char *attrs[] = {IPA_CN, OBJECTCLASS, NULL};
780 : struct sdap_attr_map_info *maps;
781 :
782 0 : maps = talloc_zero(ctx, struct sdap_attr_map_info);
783 0 : if (maps == NULL) {
784 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
785 0 : return ENOMEM;
786 : }
787 0 : maps->map = ctx->sd_ctx->id_ctx->ipa_options->view_map;
788 0 : maps->num_attrs = IPA_OPTS_VIEW;
789 :
790 0 : base = ctx->search_bases[ctx->search_base_iter];
791 0 : if (base == NULL) {
792 0 : return EOK;
793 : }
794 :
795 0 : req = sdap_deref_search_with_filter_send(ctx, ctx->sd_ctx->be_ctx->ev,
796 0 : ctx->sd_ctx->sdap_id_ctx->opts,
797 : sdap_id_op_handle(ctx->sdap_op),
798 : base->basedn,
799 0 : ctx->current_filter, IPA_ASSIGNED_ID_VIEW, attrs,
800 : 1, maps,
801 0 : dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
802 : SDAP_SEARCH_TIMEOUT));
803 :
804 0 : if (req == NULL) {
805 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
806 0 : return ENOMEM;
807 : }
808 :
809 0 : tevent_req_set_callback(req, ipa_get_view_name_done, ctx);
810 :
811 0 : return EAGAIN;
812 : }
813 :
814 0 : static void ipa_get_view_name_done(struct tevent_req *req)
815 : {
816 : int ret;
817 : int sret;
818 : struct ipa_subdomains_req_ctx *ctx;
819 : size_t reply_count;
820 0 : struct sdap_deref_attrs **reply = NULL;
821 : const char *view_name;
822 0 : int dp_error = DP_ERR_FATAL;
823 :
824 0 : ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
825 :
826 0 : ret = sdap_deref_search_with_filter_recv(req, ctx, &reply_count, &reply);
827 0 : talloc_zfree(req);
828 0 : if (ret != EOK) {
829 : /* Depending on the version 389ds return a different error code if the
830 : * search for the view name failed because our dereference attribute
831 : * ipaAssignedIDView is not known. Newer version return
832 : * LDAP_UNAVAILABLE_CRITICAL_EXTENSION(12) which is translated to
833 : * EOPNOTSUPP and older versions return LDAP_PROTOCOL_ERROR(2) which
834 : * is returned as EIO. In both cases we have to assume that the server
835 : * is not view aware and keep the view name unset. */
836 0 : if (ret == EOPNOTSUPP || ret == EIO) {
837 0 : DEBUG(SSSDBG_TRACE_FUNC, "get_view_name request failed, looks " \
838 : "like server does not support views.\n");
839 0 : ret = ipa_check_master(ctx);
840 0 : if (ret == EAGAIN) {
841 0 : return;
842 0 : } else if (ret != EOK) {
843 0 : goto done;
844 : }
845 :
846 : } else {
847 0 : DEBUG(SSSDBG_OP_FAILURE, "get_view_name request failed.\n");
848 : }
849 0 : goto done;
850 : }
851 :
852 0 : if (reply_count == 0) {
853 0 : ctx->search_base_iter++;
854 0 : ret = ipa_get_view_name(ctx);
855 0 : if (ret == EAGAIN) {
856 0 : return;
857 0 : } else if (ret == EOK) {
858 0 : DEBUG(SSSDBG_TRACE_FUNC, "No view found, using default.\n");
859 0 : view_name = SYSDB_DEFAULT_VIEW_NAME;
860 : } else {
861 0 : goto done;
862 : }
863 0 : } else if (reply_count > 1) {
864 0 : DEBUG(SSSDBG_CRIT_FAILURE,
865 : "get_view_name request returned more than one object.\n");
866 0 : ret = EINVAL;
867 0 : goto done;
868 : } else {
869 0 : ret = sysdb_attrs_get_string(reply[0]->attrs, SYSDB_VIEW_NAME,
870 : &view_name);
871 0 : if (ret != EOK) {
872 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
873 0 : goto done;
874 : }
875 : }
876 :
877 0 : DEBUG(SSSDBG_TRACE_FUNC, "Found view name [%s].\n", view_name);
878 0 : if (is_default_view(view_name)) {
879 0 : DEBUG(SSSDBG_TRACE_ALL,
880 : "Found IPA default view name, replacing with sysdb default.\n");
881 0 : view_name = SYSDB_DEFAULT_VIEW_NAME;
882 : }
883 :
884 0 : DEBUG(SSSDBG_TRACE_ALL, "read_at_init [%s] current view [%s].\n",
885 : ctx->sd_ctx->view_read_at_init ? "true" : "false",
886 : ctx->sd_ctx->id_ctx->view_name);
887 :
888 0 : if (ctx->sd_ctx->id_ctx->view_name != NULL
889 0 : && strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0
890 0 : && ctx->sd_ctx->view_read_at_init) {
891 0 : DEBUG(SSSDBG_CRIT_FAILURE,
892 : "View name changed, this is not supported at runtime. " \
893 : "Please restart SSSD to get the new view applied.\n");
894 : } else {
895 0 : if (ctx->sd_ctx->id_ctx->view_name == NULL
896 0 : || strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0) {
897 : /* View name changed */
898 :
899 0 : if (ctx->sd_ctx->id_ctx->view_name != NULL) {
900 0 : ret = sysdb_transaction_start(
901 0 : ctx->sd_ctx->be_ctx->domain->sysdb);
902 0 : if (ret != EOK) {
903 0 : DEBUG(SSSDBG_OP_FAILURE,
904 : "sysdb_transaction_start failed.\n");
905 0 : goto done;
906 : }
907 :
908 0 : if (!is_default_view(ctx->sd_ctx->id_ctx->view_name)
909 0 : && !is_local_view(ctx->sd_ctx->id_ctx->view_name)) {
910 : /* Old view was not the default view, delete view tree */
911 0 : ret = sysdb_delete_view_tree(
912 0 : ctx->sd_ctx->be_ctx->domain->sysdb,
913 0 : ctx->sd_ctx->id_ctx->view_name);
914 0 : if (ret != EOK) {
915 0 : DEBUG(SSSDBG_OP_FAILURE,
916 : "sysdb_delete_view_tree failed.\n");
917 0 : sret = sysdb_transaction_cancel(
918 0 : ctx->sd_ctx->be_ctx->domain->sysdb);
919 0 : if (sret != EOK) {
920 0 : DEBUG(SSSDBG_OP_FAILURE,
921 : "sysdb_transaction_cancel failed.\n");
922 0 : goto done;
923 : }
924 0 : goto done;
925 : }
926 : }
927 :
928 0 : ret = sysdb_invalidate_overrides(
929 0 : ctx->sd_ctx->be_ctx->domain->sysdb);
930 0 : if (ret != EOK) {
931 0 : DEBUG(SSSDBG_OP_FAILURE,
932 : "sysdb_invalidate_overrides failed.\n");
933 0 : sret = sysdb_transaction_cancel(
934 0 : ctx->sd_ctx->be_ctx->domain->sysdb);
935 0 : if (sret != EOK) {
936 0 : DEBUG(SSSDBG_OP_FAILURE,
937 : "sysdb_transaction_cancel failed.\n");
938 0 : goto done;
939 : }
940 0 : goto done;
941 : }
942 :
943 0 : ret = sysdb_transaction_commit(
944 0 : ctx->sd_ctx->be_ctx->domain->sysdb);
945 0 : if (ret != EOK) {
946 0 : DEBUG(SSSDBG_OP_FAILURE,
947 : "sysdb_transaction_commit failed.\n");
948 0 : goto done;
949 : }
950 :
951 : /* TODO: start referesh task */
952 : }
953 :
954 0 : ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
955 : view_name);
956 0 : if (ret != EOK) {
957 0 : DEBUG(SSSDBG_CRIT_FAILURE,
958 : "Cannot add/update view name to sysdb.\n");
959 : } else {
960 0 : talloc_free(ctx->sd_ctx->id_ctx->view_name);
961 0 : ctx->sd_ctx->id_ctx->view_name = talloc_strdup(
962 0 : ctx->sd_ctx->id_ctx,
963 : view_name);
964 0 : if (ctx->sd_ctx->id_ctx->view_name == NULL) {
965 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
966 : }
967 : }
968 : }
969 :
970 0 : if (!ctx->sd_ctx->view_read_at_init) {
971 : /* refresh view data of all domains at startup */
972 0 : ret = sysdb_master_domain_update(ctx->sd_ctx->be_ctx->domain);
973 0 : if (ret != EOK) {
974 0 : DEBUG(SSSDBG_OP_FAILURE,
975 : "sysdb_master_domain_update failed.\n");
976 0 : goto done;
977 : }
978 :
979 0 : ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
980 0 : if (ret != EOK) {
981 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
982 0 : goto done;
983 : }
984 : }
985 :
986 0 : ctx->sd_ctx->view_read_at_init = true;
987 :
988 : }
989 :
990 0 : ret = EOK;
991 : done:
992 0 : if (ret == EOK) {
993 0 : dp_error = DP_ERR_OK;
994 : }
995 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
996 : }
997 :
998 0 : static void ipa_subdomains_handler_done(struct tevent_req *req)
999 : {
1000 : int ret;
1001 : size_t reply_count;
1002 0 : struct sysdb_attrs **reply = NULL;
1003 : struct ipa_subdomains_req_ctx *ctx;
1004 : struct sss_domain_info *domain;
1005 0 : bool refresh_has_changes = false;
1006 0 : int dp_error = DP_ERR_FATAL;
1007 : struct tevent_req *trust_req;
1008 :
1009 0 : ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
1010 0 : domain = ctx->sd_ctx->be_ctx->domain;
1011 :
1012 0 : ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
1013 0 : talloc_zfree(req);
1014 0 : if (ret != EOK) {
1015 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
1016 0 : goto done;
1017 : }
1018 :
1019 0 : if (reply_count) {
1020 0 : ctx->reply = talloc_realloc(ctx, ctx->reply, struct sysdb_attrs *,
1021 : ctx->reply_count + reply_count);
1022 0 : if (ctx->reply == NULL) {
1023 0 : ret = ENOMEM;
1024 0 : goto done;
1025 : }
1026 0 : memcpy(ctx->reply+ctx->reply_count, reply,
1027 : reply_count * sizeof(struct sysdb_attrs *));
1028 0 : ctx->reply_count += reply_count;
1029 : }
1030 :
1031 0 : ret = ipa_subdomains_handler_get_cont(ctx, IPA_SUBDOMAINS_SLAVE);
1032 0 : if (ret == EAGAIN) {
1033 0 : return;
1034 0 : } else if (ret != EOK) {
1035 0 : goto done;
1036 : }
1037 :
1038 0 : ret = ipa_subdomains_refresh(ctx->sd_ctx, ctx->reply_count, ctx->reply,
1039 : &refresh_has_changes);
1040 0 : if (ret != EOK) {
1041 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
1042 0 : goto done;
1043 : }
1044 :
1045 0 : if (refresh_has_changes) {
1046 0 : ret = ipa_subdom_reinit(ctx->sd_ctx);
1047 0 : if (ret != EOK) {
1048 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
1049 0 : goto done;
1050 : }
1051 :
1052 0 : if (ctx->sd_ctx->id_ctx->server_mode != NULL) {
1053 0 : trust_req = ipa_server_create_trusts_send(ctx, ctx->sd_ctx->be_ctx->ev,
1054 0 : ctx->sd_ctx->be_ctx,
1055 0 : ctx->sd_ctx->id_ctx,
1056 : domain);
1057 0 : if (trust_req == NULL) {
1058 0 : ret = ENOMEM;
1059 0 : goto done;
1060 : }
1061 0 : tevent_req_set_callback(trust_req, ipa_server_create_trusts_done, ctx);
1062 0 : return;
1063 : }
1064 : }
1065 :
1066 0 : ctx->search_base_iter = 0;
1067 0 : ctx->search_bases = ctx->sd_ctx->host_search_bases;
1068 0 : talloc_zfree(ctx->current_filter);
1069 0 : ctx->current_filter = talloc_asprintf(ctx, "(&(objectClass=%s)(%s=%s))",
1070 0 : ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_OC_HOST].name,
1071 0 : ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_AT_HOST_FQDN].name,
1072 0 : dp_opt_get_string(ctx->sd_ctx->id_ctx->ipa_options->basic,
1073 : IPA_HOSTNAME));
1074 0 : if (ctx->current_filter == NULL) {
1075 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
1076 0 : ret = ENOMEM;
1077 0 : goto done;
1078 : }
1079 :
1080 0 : if (ctx->sd_ctx->id_ctx->server_mode == NULL) {
1081 : /* Only get view on clients, on servers it is always 'default' */
1082 0 : ret = ipa_get_view_name(ctx);
1083 0 : if (ret == EAGAIN) {
1084 0 : return;
1085 0 : } else if (ret != EOK) {
1086 0 : goto done;
1087 : }
1088 : }
1089 :
1090 0 : ret = EOK;
1091 : done:
1092 0 : if (ret == EOK) {
1093 0 : dp_error = DP_ERR_OK;
1094 : }
1095 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
1096 : }
1097 :
1098 0 : static void ipa_server_create_trusts_done(struct tevent_req *trust_req)
1099 : {
1100 : errno_t ret;
1101 0 : int dp_error = DP_ERR_FATAL;
1102 : struct ipa_subdomains_req_ctx *ctx;
1103 :
1104 0 : ctx = tevent_req_callback_data(trust_req, struct ipa_subdomains_req_ctx);
1105 :
1106 0 : ret = ipa_server_create_trusts_recv(trust_req);
1107 0 : talloc_zfree(trust_req);
1108 0 : if (ret == EOK) {
1109 0 : dp_error = DP_ERR_OK;
1110 : }
1111 :
1112 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
1113 0 : }
1114 :
1115 0 : static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx)
1116 : {
1117 : int ret;
1118 : struct sss_domain_info *domain;
1119 :
1120 0 : domain = ctx->sd_ctx->be_ctx->domain;
1121 :
1122 0 : ret = sysdb_master_domain_update(domain);
1123 0 : if (ret != EOK) {
1124 0 : return ret;
1125 : }
1126 :
1127 0 : if (domain->flat_name == NULL ||
1128 0 : domain->domain_id == NULL ||
1129 0 : domain->realm == NULL) {
1130 :
1131 0 : ret = ipa_subdomains_handler_get_start(ctx,
1132 0 : ctx->sd_ctx->master_search_bases,
1133 : IPA_SUBDOMAINS_MASTER);
1134 0 : if (ret == EAGAIN) {
1135 0 : return EAGAIN;
1136 0 : } else if (ret != EOK) {
1137 0 : return ret;
1138 : }
1139 : }
1140 :
1141 0 : return EOK;
1142 : }
1143 :
1144 :
1145 0 : static void ipa_subdomains_handler_ranges_done(struct tevent_req *req)
1146 : {
1147 : errno_t ret;
1148 0 : int dp_error = DP_ERR_FATAL;
1149 : size_t reply_count;
1150 0 : struct sysdb_attrs **reply = NULL;
1151 : struct ipa_subdomains_req_ctx *ctx;
1152 0 : struct range_info **range_list = NULL;
1153 : struct sysdb_ctx *sysdb;
1154 : struct sss_domain_info *domain;
1155 :
1156 0 : ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
1157 0 : domain = ctx->sd_ctx->be_ctx->domain;
1158 0 : sysdb = domain->sysdb;
1159 :
1160 0 : ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
1161 0 : talloc_zfree(req);
1162 0 : if (ret != EOK) {
1163 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
1164 0 : goto done;
1165 : }
1166 :
1167 0 : ret = ipa_ranges_parse_results(ctx, domain->name,
1168 : reply_count, reply, &range_list);
1169 0 : if (ret != EOK) {
1170 0 : DEBUG(SSSDBG_OP_FAILURE,
1171 : "ipa_ranges_parse_results request failed.\n");
1172 0 : goto done;
1173 : }
1174 :
1175 0 : ret = sysdb_update_ranges(sysdb, range_list);
1176 0 : talloc_free(range_list);
1177 0 : if (ret != EOK) {
1178 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_ranges failed.\n");
1179 0 : goto done;
1180 : }
1181 :
1182 0 : ret = ipa_check_master(ctx);
1183 0 : if (ret == EAGAIN) {
1184 0 : DEBUG(SSSDBG_TRACE_ALL, "Checking master record..\n");
1185 0 : return;
1186 0 : } else if (ret != EOK) {
1187 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_check_master failed.\n");
1188 0 : goto done;
1189 : }
1190 : /* Master domain is up-to-date. Continue checking subdomains */
1191 :
1192 0 : DEBUG(SSSDBG_TRACE_ALL, "Master record up2date, checking subdomains\n");
1193 0 : ret = ipa_subdomains_handler_get_start(ctx, ctx->sd_ctx->search_bases,
1194 : IPA_SUBDOMAINS_SLAVE);
1195 0 : if (ret == EAGAIN) {
1196 0 : return;
1197 0 : } else if (ret != EOK) {
1198 0 : goto done;
1199 : }
1200 :
1201 0 : DEBUG(SSSDBG_OP_FAILURE, "No search base for ranges available.\n");
1202 0 : ret = EINVAL;
1203 :
1204 : done:
1205 0 : if (ret == EOK) {
1206 0 : dp_error = DP_ERR_OK;
1207 : }
1208 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
1209 : }
1210 :
1211 0 : static void ipa_subdomains_handler_master_done(struct tevent_req *req)
1212 : {
1213 : errno_t ret;
1214 0 : int dp_error = DP_ERR_FATAL;
1215 0 : size_t reply_count = 0;
1216 0 : struct sysdb_attrs **reply = NULL;
1217 : struct ipa_subdomains_req_ctx *ctx;
1218 :
1219 0 : ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
1220 :
1221 0 : ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
1222 0 : talloc_zfree(req);
1223 0 : if (ret != EOK) {
1224 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
1225 0 : goto done;
1226 : }
1227 :
1228 0 : if (reply_count) {
1229 0 : const char *flat = NULL;
1230 0 : const char *id = NULL;
1231 : const char *realm;
1232 :
1233 0 : ret = sysdb_attrs_get_string(reply[0], IPA_FLATNAME, &flat);
1234 0 : if (ret != EOK) {
1235 0 : goto done;
1236 : }
1237 :
1238 0 : ret = sysdb_attrs_get_string(reply[0], IPA_SID, &id);
1239 0 : if (ret != EOK) {
1240 0 : goto done;
1241 : }
1242 :
1243 0 : realm = dp_opt_get_string(ctx->sd_ctx->id_ctx->ipa_options->basic,
1244 : IPA_KRB5_REALM);
1245 0 : if (realm == NULL) {
1246 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
1247 0 : ret = EINVAL;
1248 0 : goto done;
1249 : }
1250 :
1251 0 : ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
1252 : realm, flat, id, NULL);
1253 0 : if (ret != EOK) {
1254 0 : goto done;
1255 : }
1256 :
1257 : /* There is only one master record. Don't bother checking other IPA
1258 : * search bases; move to checking subdomains instead
1259 : */
1260 0 : ret = ipa_subdomains_handler_get_start(ctx,
1261 0 : ctx->sd_ctx->search_bases,
1262 : IPA_SUBDOMAINS_SLAVE);
1263 0 : if (ret == EAGAIN) {
1264 0 : return;
1265 : }
1266 :
1267 : /* Either no search bases or an error. End the request in both cases */
1268 : } else {
1269 0 : ret = ipa_subdomains_handler_get_cont(ctx, IPA_SUBDOMAINS_MASTER);
1270 0 : if (ret == EAGAIN) {
1271 0 : return;
1272 0 : } else if (ret != EOK) {
1273 0 : goto done;
1274 : }
1275 :
1276 : /* Right now we know there has been an error
1277 : * and we don't have the master domain record
1278 : */
1279 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Master domain record not found!\n");
1280 :
1281 0 : if (!ctx->sd_ctx->configured_explicit) {
1282 0 : ctx->sd_ctx->disabled_until = time(NULL) +
1283 : IPA_SUBDOMAIN_DISABLED_PERIOD;
1284 : }
1285 :
1286 0 : ret = EIO;
1287 : }
1288 :
1289 : done:
1290 0 : if (ret == EOK) {
1291 0 : dp_error = DP_ERR_OK;
1292 : }
1293 0 : ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
1294 : }
1295 :
1296 : static void ipa_subdom_online_cb(void *pvt);
1297 :
1298 0 : static void ipa_subdom_timer_refresh(struct tevent_context *ev,
1299 : struct tevent_timer *te,
1300 : struct timeval current_time,
1301 : void *pvt)
1302 : {
1303 0 : ipa_subdom_online_cb(pvt);
1304 0 : }
1305 :
1306 0 : static void ipa_subdom_be_req_callback(struct be_req *be_req,
1307 : int dp_err, int dp_ret,
1308 : const char *errstr)
1309 : {
1310 0 : talloc_free(be_req);
1311 0 : }
1312 :
1313 0 : static void ipa_subdom_reset_timeouts_cb(void *pvt)
1314 : {
1315 : struct ipa_subdomains_ctx *ctx;
1316 :
1317 0 : ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
1318 0 : if (ctx == NULL) {
1319 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
1320 0 : return;
1321 : }
1322 :
1323 0 : DEBUG(SSSDBG_TRACE_ALL, "Resetting last_refreshed and disabled_until.\n");
1324 0 : ctx->last_refreshed = 0;
1325 0 : ctx->disabled_until = 0;
1326 : }
1327 :
1328 0 : static void ipa_subdom_online_cb(void *pvt)
1329 : {
1330 : struct ipa_subdomains_ctx *ctx;
1331 : struct be_req *be_req;
1332 : struct timeval tv;
1333 : uint32_t refresh_interval;
1334 :
1335 0 : ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
1336 0 : if (!ctx) {
1337 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
1338 0 : return;
1339 : }
1340 :
1341 0 : ctx->disabled_until = 0;
1342 :
1343 0 : refresh_interval = ctx->be_ctx->domain->subdomain_refresh_interval;
1344 :
1345 0 : be_req = be_req_create(ctx, NULL, ctx->be_ctx,
1346 : ipa_subdom_be_req_callback, NULL);
1347 0 : if (be_req == NULL) {
1348 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_req_create() failed.\n");
1349 0 : return;
1350 : }
1351 :
1352 0 : ipa_subdomains_retrieve(ctx, be_req);
1353 :
1354 0 : tv = tevent_timeval_current_ofs(refresh_interval, 0);
1355 0 : ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
1356 : ipa_subdom_timer_refresh, ctx);
1357 0 : if (!ctx->timer_event) {
1358 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom timer event\n");
1359 : }
1360 : }
1361 :
1362 0 : static void ipa_subdom_offline_cb(void *pvt)
1363 : {
1364 : struct ipa_subdomains_ctx *ctx;
1365 :
1366 0 : ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
1367 :
1368 0 : if (ctx) {
1369 0 : talloc_zfree(ctx->timer_event);
1370 : }
1371 0 : }
1372 :
1373 0 : static errno_t get_config_status(struct be_ctx *be_ctx,
1374 : bool *configured_explicit)
1375 : {
1376 : int ret;
1377 0 : TALLOC_CTX *tmp_ctx = NULL;
1378 : char *tmp_str;
1379 :
1380 0 : tmp_ctx = talloc_new(NULL);
1381 0 : if (tmp_ctx == NULL) {
1382 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1383 0 : return ENOMEM;
1384 : }
1385 :
1386 0 : ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
1387 : CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, NULL,
1388 : &tmp_str);
1389 0 : if (ret != EOK) {
1390 0 : DEBUG(SSSDBG_OP_FAILURE, "confdb_get_string failed.\n");
1391 0 : goto done;
1392 : }
1393 :
1394 0 : if (tmp_str == NULL) {
1395 0 : *configured_explicit = false;
1396 : } else {
1397 0 : *configured_explicit = true;
1398 : }
1399 :
1400 0 : DEBUG(SSSDBG_TRACE_ALL, "IPA subdomain provider is configured %s.\n",
1401 : *configured_explicit ? "explicit" : "implicit");
1402 :
1403 0 : ret = EOK;
1404 :
1405 : done:
1406 0 : talloc_free(tmp_ctx);
1407 :
1408 0 : return ret;
1409 : }
1410 :
1411 0 : void ipa_subdomains_handler(struct be_req *be_req)
1412 : {
1413 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
1414 : struct ipa_subdomains_ctx *ctx;
1415 : time_t now;
1416 :
1417 0 : ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
1418 : struct ipa_subdomains_ctx);
1419 0 : if (!ctx) {
1420 0 : be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
1421 0 : return;
1422 : }
1423 :
1424 0 : now = time(NULL);
1425 :
1426 0 : if (ctx->disabled_until > now) {
1427 0 : DEBUG(SSSDBG_TRACE_ALL, "Subdomain provider disabled.\n");
1428 0 : ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
1429 0 : return;
1430 : }
1431 :
1432 0 : if (ctx->last_refreshed > now - IPA_SUBDOMAIN_REFRESH_LIMIT) {
1433 0 : ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
1434 0 : return;
1435 : }
1436 :
1437 0 : ipa_subdomains_retrieve(ctx, be_req);
1438 : }
1439 :
1440 : struct bet_ops ipa_subdomains_ops = {
1441 : .handler = ipa_subdomains_handler,
1442 : .finalize = NULL
1443 : };
1444 :
1445 0 : int ipa_subdom_init(struct be_ctx *be_ctx,
1446 : struct ipa_id_ctx *id_ctx,
1447 : struct bet_ops **ops,
1448 : void **pvt_data)
1449 : {
1450 : struct ipa_subdomains_ctx *ctx;
1451 : int ret;
1452 0 : bool configured_explicit = false;
1453 :
1454 0 : ret = get_config_status(be_ctx, &configured_explicit);
1455 0 : if (ret != EOK) {
1456 0 : DEBUG(SSSDBG_OP_FAILURE, "get_config_status failed.\n");
1457 0 : return ret;
1458 : }
1459 :
1460 0 : ctx = talloc_zero(id_ctx, struct ipa_subdomains_ctx);
1461 0 : if (ctx == NULL) {
1462 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
1463 0 : return ENOMEM;
1464 : }
1465 :
1466 0 : ctx->be_ctx = be_ctx;
1467 0 : ctx->id_ctx = id_ctx;
1468 0 : ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
1469 0 : ctx->search_bases = id_ctx->ipa_options->subdomains_search_bases;
1470 0 : ctx->master_search_bases = id_ctx->ipa_options->master_domain_search_bases;
1471 0 : ctx->ranges_search_bases = id_ctx->ipa_options->ranges_search_bases;
1472 0 : ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
1473 0 : ctx->configured_explicit = configured_explicit;
1474 0 : ctx->disabled_until = 0;
1475 0 : *ops = &ipa_subdomains_ops;
1476 0 : *pvt_data = ctx;
1477 :
1478 0 : ret = be_add_unconditional_online_cb(ctx, be_ctx,
1479 : ipa_subdom_reset_timeouts_cb, ctx,
1480 : NULL);
1481 0 : if (ret != EOK) {
1482 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1483 : "Failed to add subdom reset timeouts callback\n");
1484 : }
1485 :
1486 0 : ret = be_add_online_cb(ctx, be_ctx, ipa_subdom_online_cb, ctx, NULL);
1487 0 : if (ret != EOK) {
1488 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom online callback\n");
1489 : }
1490 :
1491 0 : ret = be_add_offline_cb(ctx, be_ctx, ipa_subdom_offline_cb, ctx, NULL);
1492 0 : if (ret != EOK) {
1493 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom offline callback\n");
1494 : }
1495 :
1496 0 : ret = ipa_subdom_reinit(ctx);
1497 0 : if (ret != EOK) {
1498 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not load the list of subdomains. "
1499 : "Users from trusted domains might not be resolved correctly\n");
1500 : }
1501 :
1502 0 : ret = ipa_ad_subdom_init(be_ctx, id_ctx);
1503 0 : if (ret != EOK) {
1504 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ipa_ad_subdom_init failed.\n");
1505 0 : return ret;
1506 : }
1507 :
1508 0 : return EOK;
1509 : }
|