Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Subdomains Module - server mode
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2015 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 : /* These constants are defined in MS-ADTS 6.1.6.7.1
32 : * https://msdn.microsoft.com/en-us/library/cc223768.aspx
33 : */
34 : #define LSA_TRUST_DIRECTION_INBOUND 0x00000001
35 : #define LSA_TRUST_DIRECTION_OUTBOUND 0x00000002
36 :
37 17 : static char *forest_keytab(TALLOC_CTX *mem_ctx, const char *forest)
38 : {
39 17 : return talloc_asprintf(mem_ctx,
40 : "%s/%s.keytab", IPA_TRUST_KEYTAB_DIR, forest);
41 : }
42 :
43 17 : static char *subdomain_trust_princ(TALLOC_CTX *mem_ctx,
44 : const char *forest_realm,
45 : struct sss_domain_info *sd)
46 : {
47 17 : if (sd->parent->flat_name == NULL) {
48 0 : DEBUG(SSSDBG_CRIT_FAILURE,
49 : "Unknown flat name for parent %s\n", sd->parent->name);
50 0 : return NULL;
51 : }
52 :
53 17 : return talloc_asprintf(mem_ctx, "%s$@%s",
54 17 : sd->parent->flat_name, forest_realm);
55 : }
56 :
57 2 : static uint32_t default_direction(TALLOC_CTX *mem_ctx,
58 : struct ldb_context *ldb_ctx,
59 : struct sysdb_attrs *attrs)
60 : {
61 2 : struct ldb_dn *dn = NULL;
62 : uint32_t direction;
63 :
64 2 : dn = ipa_subdom_ldb_dn(mem_ctx, ldb_ctx, attrs);
65 2 : if (dn == NULL) {
66 : /* Shouldn't happen, but let's try system keytab in this case */
67 0 : DEBUG(SSSDBG_CRIT_FAILURE,
68 : "Cannot determine subdomain DN, falling back to two-way trust\n");
69 0 : return (LSA_TRUST_DIRECTION_INBOUND|LSA_TRUST_DIRECTION_OUTBOUND);
70 : }
71 :
72 2 : if (ipa_subdom_is_member_dom(dn) == true) {
73 : /* It's expected member domains do not have the direction */
74 1 : direction = 0;
75 : } else {
76 : /* Old server? Default to 2way trust */
77 1 : direction = (LSA_TRUST_DIRECTION_INBOUND|LSA_TRUST_DIRECTION_OUTBOUND);
78 : }
79 :
80 2 : talloc_free(dn);
81 2 : return direction;
82 : }
83 :
84 5 : errno_t ipa_server_get_trust_direction(struct sysdb_attrs *sd,
85 : struct ldb_context *ldb_ctx,
86 : uint32_t *_direction)
87 : {
88 5 : uint32_t ipa_trust_direction = 0;
89 : uint32_t direction;
90 : int ret;
91 :
92 5 : ret = sysdb_attrs_get_uint32_t(sd, IPA_TRUST_DIRECTION,
93 : &ipa_trust_direction);
94 5 : DEBUG(SSSDBG_TRACE_INTERNAL,
95 : "Raw %s value: %d\n", IPA_TRUST_DIRECTION, ipa_trust_direction);
96 5 : if (ret == ENOENT) {
97 2 : direction = default_direction(sd, ldb_ctx, sd);
98 3 : } else if (ret == EOK) {
99 : /* Just store the AD value in SYSDB, we will check it while we're
100 : * trying to use the trust */
101 3 : direction = ipa_trust_direction;
102 : } else {
103 0 : return ret;
104 : }
105 :
106 5 : *_direction = direction;
107 5 : return EOK;
108 : }
109 :
110 4 : const char *ipa_trust_dir2str(uint32_t direction)
111 : {
112 4 : if ((direction & LSA_TRUST_DIRECTION_OUTBOUND)
113 1 : && (direction & LSA_TRUST_DIRECTION_INBOUND)) {
114 0 : return "two-way trust";
115 4 : } else if (direction & LSA_TRUST_DIRECTION_OUTBOUND) {
116 1 : return "one-way outbound: local domain is trusted by remote domain";
117 3 : } else if (direction & LSA_TRUST_DIRECTION_INBOUND) {
118 1 : return "one-way inbound: local domain trusts the remote domain";
119 2 : } else if (direction == 0) {
120 1 : return "trust direction not set";
121 : }
122 :
123 1 : return "unknown";
124 : }
125 :
126 : #ifndef IPA_GETKEYTAB_TIMEOUT
127 : #define IPA_GETKEYTAB_TIMEOUT 5
128 : #endif /* IPA_GETKEYTAB_TIMEOUT */
129 :
130 : static struct ad_options *
131 8 : ipa_create_1way_trust_ctx(struct ipa_id_ctx *id_ctx,
132 : const char *forest,
133 : const char *forest_realm,
134 : struct sss_domain_info *subdom)
135 : {
136 : char *keytab;
137 : char *principal;
138 : struct ad_options *ad_options;
139 : const char *ad_domain;
140 :
141 8 : ad_domain = subdom->name;
142 8 : keytab = forest_keytab(id_ctx, forest);
143 8 : principal = subdomain_trust_princ(id_ctx, forest_realm, subdom);
144 8 : if (keytab == NULL || principal == NULL) {
145 0 : return NULL;
146 : }
147 :
148 8 : ad_options = ad_create_1way_trust_options(id_ctx,
149 : ad_domain,
150 8 : id_ctx->server_mode->hostname,
151 : keytab,
152 : principal);
153 8 : if (ad_options == NULL) {
154 0 : talloc_free(keytab);
155 0 : talloc_free(principal);
156 0 : return NULL;
157 : }
158 :
159 8 : return ad_options;
160 : }
161 :
162 12 : static struct ad_options *ipa_ad_options_new(struct ipa_id_ctx *id_ctx,
163 : struct sss_domain_info *subdom)
164 : {
165 12 : struct ad_options *ad_options = NULL;
166 : uint32_t direction;
167 : const char *forest;
168 : const char *forest_realm;
169 :
170 : /* Trusts are only established with forest roots */
171 12 : direction = subdom->forest_root->trust_direction;
172 12 : forest_realm = subdom->forest_root->realm;
173 12 : forest = subdom->forest_root->forest;
174 :
175 12 : if (direction & LSA_TRUST_DIRECTION_OUTBOUND) {
176 8 : ad_options = ad_create_2way_trust_options(id_ctx,
177 4 : id_ctx->server_mode->realm,
178 4 : subdom->name,
179 4 : id_ctx->server_mode->hostname);
180 8 : } else if (direction & LSA_TRUST_DIRECTION_INBOUND) {
181 8 : ad_options = ipa_create_1way_trust_ctx(id_ctx, forest,
182 : forest_realm, subdom);
183 : } else {
184 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported trust direction!\n");
185 0 : ad_options = NULL;
186 : }
187 :
188 12 : if (ad_options == NULL) {
189 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
190 0 : return NULL;
191 : }
192 12 : return ad_options;
193 : }
194 :
195 :
196 : static errno_t
197 12 : ipa_ad_ctx_new(struct be_ctx *be_ctx,
198 : struct ipa_id_ctx *id_ctx,
199 : struct sss_domain_info *subdom,
200 : struct ad_id_ctx **_ad_id_ctx)
201 : {
202 : struct ad_options *ad_options;
203 : struct ad_id_ctx *ad_id_ctx;
204 : const char *gc_service_name;
205 : struct ad_srv_plugin_ctx *srv_ctx;
206 : const char *ad_domain;
207 : const char *ad_site_override;
208 : struct sdap_domain *sdom;
209 : errno_t ret;
210 : const char *extra_attrs;
211 :
212 12 : ad_domain = subdom->name;
213 12 : DEBUG(SSSDBG_TRACE_LIBS, "Setting up AD subdomain %s\n", subdom->name);
214 :
215 12 : ad_options = ipa_ad_options_new(id_ctx, subdom);
216 12 : if (ad_options == NULL) {
217 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
218 0 : talloc_free(ad_options);
219 0 : return ENOMEM;
220 : }
221 :
222 12 : extra_attrs = dp_opt_get_string(id_ctx->sdap_id_ctx->opts->basic,
223 : SDAP_USER_EXTRA_ATTRS);
224 12 : if (extra_attrs != NULL) {
225 0 : DEBUG(SSSDBG_TRACE_ALL,
226 : "Setting extra attrs for subdomain [%s] to [%s].\n", ad_domain,
227 : extra_attrs);
228 :
229 0 : ret = dp_opt_set_string(ad_options->id->basic, SDAP_USER_EXTRA_ATTRS,
230 : extra_attrs);
231 0 : if (ret != EOK) {
232 0 : DEBUG(SSSDBG_OP_FAILURE, "dp_opt_get_string failed.\n");
233 0 : talloc_free(ad_options);
234 0 : return ret;
235 : }
236 :
237 0 : ret = sdap_extend_map_with_list(ad_options->id, ad_options->id,
238 : SDAP_USER_EXTRA_ATTRS,
239 0 : ad_options->id->user_map,
240 : SDAP_OPTS_USER,
241 0 : &ad_options->id->user_map,
242 0 : &ad_options->id->user_map_cnt);
243 0 : if (ret != EOK) {
244 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_extend_map_with_list failed.\n");
245 0 : talloc_free(ad_options);
246 0 : return ret;
247 : }
248 : } else {
249 12 : DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n");
250 : }
251 :
252 12 : gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
253 12 : if (gc_service_name == NULL) {
254 0 : talloc_free(ad_options);
255 0 : return ENOMEM;
256 : }
257 :
258 : /* Set KRB5 realm to same as the one of IPA when IPA
259 : * is able to attach PAC. For testing, use hardcoded. */
260 24 : ret = ad_failover_init(ad_options, be_ctx, NULL, NULL,
261 12 : id_ctx->server_mode->realm,
262 12 : subdom->name, gc_service_name,
263 12 : subdom->name, &ad_options->service);
264 12 : if (ret != EOK) {
265 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
266 0 : talloc_free(ad_options);
267 0 : return ret;
268 : }
269 :
270 12 : ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx);
271 12 : if (ad_id_ctx == NULL) {
272 0 : talloc_free(ad_options);
273 0 : return ENOMEM;
274 : }
275 12 : ad_id_ctx->sdap_id_ctx->opts = ad_options->id;
276 12 : ad_options->id_ctx = ad_id_ctx;
277 :
278 12 : ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
279 :
280 : /* use AD plugin */
281 24 : srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
282 : default_host_dbs,
283 12 : ad_id_ctx->ad_options->id,
284 12 : id_ctx->server_mode->hostname,
285 : ad_domain,
286 : ad_site_override);
287 12 : if (srv_ctx == NULL) {
288 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
289 0 : return ENOMEM;
290 : }
291 12 : be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send,
292 : ad_srv_plugin_recv, srv_ctx, "AD");
293 :
294 24 : ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx,
295 12 : ad_id_ctx->sdap_id_ctx->opts->sdom,
296 : subdom->parent);
297 12 : if (ret != EOK) {
298 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize sdap domain\n");
299 0 : talloc_free(ad_options);
300 0 : return ret;
301 : }
302 :
303 12 : sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom);
304 12 : if (sdom == NULL) {
305 0 : return EFAULT;
306 : }
307 :
308 24 : sdap_inherit_options(subdom->parent->sd_inherit,
309 12 : id_ctx->sdap_id_ctx->opts,
310 12 : ad_id_ctx->sdap_id_ctx->opts);
311 :
312 12 : ret = sdap_id_setup_tasks(be_ctx,
313 : ad_id_ctx->sdap_id_ctx,
314 : sdom,
315 : ldap_enumeration_send,
316 : ldap_enumeration_recv,
317 12 : ad_id_ctx->sdap_id_ctx);
318 12 : if (ret != EOK) {
319 0 : talloc_free(ad_options);
320 0 : return ret;
321 : }
322 :
323 12 : sdom->pvt = ad_id_ctx;
324 :
325 : /* Set up the ID mapping object */
326 24 : ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
327 12 : id_ctx->sdap_id_ctx->opts->idmap_ctx;
328 :
329 12 : *_ad_id_ctx = ad_id_ctx;
330 12 : return EOK;
331 : }
332 :
333 : struct ipa_getkeytab_state {
334 : int child_status;
335 : struct sss_child_ctx_old *child_ctx;
336 : struct tevent_timer *timeout_handler;
337 : };
338 :
339 : static void ipa_getkeytab_exec(const char *ccache,
340 : const char *server,
341 : const char *principal,
342 : const char *keytab_path);
343 : static void ipa_getkeytab_done(int child_status,
344 : struct tevent_signal *sige,
345 : void *pvt);
346 : static void ipa_getkeytab_timeout(struct tevent_context *ev,
347 : struct tevent_timer *te,
348 : struct timeval tv, void *pvt);
349 :
350 9 : static struct tevent_req *ipa_getkeytab_send(TALLOC_CTX *mem_ctx,
351 : struct tevent_context *ev,
352 : const char *ccache,
353 : const char *server,
354 : const char *principal,
355 : const char *keytab)
356 :
357 :
358 : {
359 : errno_t ret;
360 9 : struct tevent_req *req = NULL;
361 : struct ipa_getkeytab_state *state;
362 : pid_t child_pid;
363 : struct timeval tv;
364 :
365 9 : req = tevent_req_create(mem_ctx, &state, struct ipa_getkeytab_state);
366 9 : if (req == NULL) {
367 0 : return NULL;
368 : }
369 9 : state->child_status = EFAULT;
370 :
371 9 : if (server == NULL || principal == NULL || keytab == NULL) {
372 0 : ret = EINVAL;
373 0 : goto done;
374 : }
375 :
376 9 : DEBUG(SSSDBG_TRACE_FUNC,
377 : "Retrieving keytab for %s from %s into %s using ccache %s\n",
378 : principal, server, keytab, ccache);
379 :
380 9 : child_pid = fork();
381 18 : if (child_pid == 0) { /* child */
382 9 : ipa_getkeytab_exec(ccache, server, principal, keytab);
383 9 : } else if (child_pid > 0) { /* parent */
384 : /* Set up SIGCHLD handler */
385 9 : ret = child_handler_setup(ev, child_pid, ipa_getkeytab_done, req,
386 9 : &state->child_ctx);
387 9 : if (ret != EOK) {
388 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
389 : ret, sss_strerror(ret));
390 0 : ret = ERR_IPA_GETKEYTAB_FAILED;
391 0 : goto done;
392 : }
393 :
394 : /* Set up timeout handler */
395 9 : tv = tevent_timeval_current_ofs(IPA_GETKEYTAB_TIMEOUT, 0);
396 9 : state->timeout_handler = tevent_add_timer(ev, req, tv,
397 : ipa_getkeytab_timeout, req);
398 9 : if(state->timeout_handler == NULL) {
399 0 : ret = ERR_IPA_GETKEYTAB_FAILED;
400 0 : goto done;
401 : }
402 :
403 : /* Now either wait for the timeout to fire or the child
404 : * to finish
405 : */
406 : } else { /* error */
407 0 : ret = errno;
408 0 : DEBUG(SSSDBG_CRIT_FAILURE,
409 : "fork failed [%d][%s].\n", ret, sss_strerror(ret));
410 0 : goto done;
411 : }
412 :
413 9 : ret = EOK;
414 : done:
415 9 : if (ret != EOK) {
416 0 : tevent_req_error(req, ret);
417 0 : tevent_req_post(req, ev);
418 : }
419 9 : return req;
420 : }
421 :
422 9 : static void ipa_getkeytab_exec(const char *ccache,
423 : const char *server,
424 : const char *principal,
425 : const char *keytab_path)
426 : {
427 : errno_t ret;
428 : int debug_fd;
429 9 : const char *gkt_env[2] = { NULL, NULL };
430 :
431 9 : if (debug_level >= SSSDBG_TRACE_LIBS) {
432 0 : debug_fd = get_fd_from_debug_file();
433 0 : ret = dup2(debug_fd, STDERR_FILENO);
434 0 : if (ret == -1) {
435 0 : ret = errno;
436 0 : DEBUG(SSSDBG_MINOR_FAILURE,
437 : "dup2 failed [%d][%s].\n", ret, sss_strerror(ret));
438 : /* stderr is not fatal */
439 : }
440 : }
441 :
442 9 : gkt_env[0] = talloc_asprintf(NULL, "KRB5CCNAME=%s", ccache);
443 9 : if (gkt_env[0] == NULL) {
444 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to format KRB5CCNAME\n");
445 0 : exit(1);
446 : }
447 :
448 : /* ipa-getkeytab cannot add keys to an empty file, let's unlink it and only
449 : * use the filename */
450 9 : ret = unlink(keytab_path);
451 9 : if (ret == -1) {
452 0 : ret = errno;
453 0 : DEBUG(SSSDBG_CRIT_FAILURE,
454 : "Failed to unlink the temporary ccname [%d][%s]\n",
455 : ret, sss_strerror(ret));
456 0 : exit(1);
457 : }
458 :
459 9 : errno = 0;
460 9 : ret = execle(IPA_GETKEYTAB_PATH, IPA_GETKEYTAB_PATH,
461 : "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL,
462 : gkt_env);
463 :
464 9 : DEBUG(SSSDBG_CRIT_FAILURE,
465 : "execle returned %d, this shouldn't happen!\n", ret);
466 :
467 : /* The child should never end up here */
468 0 : ret = errno;
469 0 : DEBUG(SSSDBG_CRIT_FAILURE,
470 : "execle failed [%d][%s].\n", ret, sss_strerror(ret));
471 0 : exit(1);
472 : }
473 :
474 9 : static void ipa_getkeytab_done(int child_status,
475 : struct tevent_signal *sige,
476 : void *pvt)
477 : {
478 9 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
479 9 : struct ipa_getkeytab_state *state =
480 9 : tevent_req_data(req, struct ipa_getkeytab_state);
481 :
482 9 : state->child_status = child_status;
483 :
484 9 : if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
485 3 : DEBUG(SSSDBG_OP_FAILURE,
486 : "ipa-getkeytab failed with status [%d]\n", child_status);
487 3 : tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED);
488 3 : return;
489 : }
490 :
491 6 : if (WIFSIGNALED(child_status)) {
492 0 : DEBUG(SSSDBG_OP_FAILURE,
493 : "ipa-getkeytab was terminated by signal [%d]\n",
494 : WTERMSIG(child_status));
495 0 : tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED);
496 0 : return;
497 : }
498 :
499 6 : tevent_req_done(req);
500 : }
501 :
502 0 : static void ipa_getkeytab_timeout(struct tevent_context *ev,
503 : struct tevent_timer *te,
504 : struct timeval tv, void *pvt)
505 : {
506 0 : struct tevent_req *req =
507 : talloc_get_type(pvt, struct tevent_req);
508 0 : struct ipa_getkeytab_state *state =
509 0 : tevent_req_data(req, struct ipa_getkeytab_state);
510 :
511 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for retrieving keytab from IPA server\n");
512 0 : child_handler_destroy(state->child_ctx);
513 0 : state->child_ctx = NULL;
514 0 : state->child_status = ETIMEDOUT;
515 0 : tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED);
516 0 : }
517 :
518 9 : static errno_t ipa_getkeytab_recv(struct tevent_req *req, int *child_status)
519 : {
520 9 : struct ipa_getkeytab_state *state =
521 9 : tevent_req_data(req, struct ipa_getkeytab_state);
522 :
523 9 : DEBUG(SSSDBG_TRACE_INTERNAL,
524 : "ipa-getkeytab status %d\n", state->child_status);
525 9 : if (child_status) {
526 0 : *child_status = state->child_status;
527 : }
528 :
529 12 : TEVENT_REQ_RETURN_ON_ERROR(req);
530 :
531 6 : return EOK;
532 : }
533 :
534 12 : static errno_t ipa_check_keytab(const char *keytab,
535 : uid_t kt_owner_uid,
536 : gid_t kt_owner_gid)
537 : {
538 : errno_t ret;
539 :
540 12 : ret = check_file(keytab, getuid(), getgid(), S_IFREG|0600, 0, NULL, false);
541 12 : if (ret == ENOENT) {
542 4 : DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab);
543 4 : goto done;
544 8 : } else if (ret != EOK) {
545 0 : if (kt_owner_uid) {
546 0 : ret = check_file(keytab, kt_owner_uid, kt_owner_gid,
547 : S_IFREG|0600, 0, NULL, false);
548 : }
549 :
550 0 : if (ret != EOK) {
551 0 : if (ret != ENOENT) {
552 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab);
553 : } else {
554 0 : DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab);
555 : }
556 : }
557 0 : goto done;
558 : }
559 :
560 8 : DEBUG(SSSDBG_TRACE_ALL, "keytab %s already exists\n", keytab);
561 8 : ret = EOK;
562 : done:
563 12 : return ret;
564 : }
565 :
566 : struct ipa_server_trusted_dom_setup_state {
567 : struct tevent_context *ev;
568 : struct be_ctx *be_ctx;
569 : struct ipa_id_ctx *id_ctx;
570 : struct sss_domain_info *subdom;
571 :
572 : uint32_t direction;
573 : const char *forest;
574 : const char *keytab;
575 : char *new_keytab;
576 : const char *principal;
577 : const char *forest_realm;
578 : const char *ccache;
579 : };
580 :
581 : static errno_t ipa_server_trusted_dom_setup_1way(struct tevent_req *req);
582 : static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq);
583 :
584 : struct tevent_req *
585 13 : ipa_server_trusted_dom_setup_send(TALLOC_CTX *mem_ctx,
586 : struct tevent_context *ev,
587 : struct be_ctx *be_ctx,
588 : struct ipa_id_ctx *id_ctx,
589 : struct sss_domain_info *subdom)
590 : {
591 13 : struct tevent_req *req = NULL;
592 13 : struct ipa_server_trusted_dom_setup_state *state = NULL;
593 : errno_t ret;
594 :
595 13 : req = tevent_req_create(mem_ctx, &state,
596 : struct ipa_server_trusted_dom_setup_state);
597 13 : if (req == NULL) {
598 0 : return NULL;
599 : }
600 13 : state->ev = ev;
601 13 : state->be_ctx = be_ctx;
602 13 : state->id_ctx = id_ctx;
603 13 : state->subdom = subdom;
604 :
605 : /* Trusts are only established with forest roots */
606 13 : if (subdom->forest_root == NULL) {
607 0 : DEBUG(SSSDBG_OP_FAILURE,
608 : "Subdomain %s has no forest root?\n", subdom->name);
609 0 : ret = ERR_TRUST_FOREST_UNKNOWN;
610 0 : goto immediate;
611 : }
612 :
613 13 : state->direction = subdom->forest_root->trust_direction;
614 13 : state->forest = subdom->forest_root->forest;
615 13 : state->forest_realm = subdom->forest_root->realm;
616 26 : state->ccache = talloc_asprintf(state, "%s/ccache_%s",
617 13 : DB_PATH, subdom->parent->realm);
618 13 : if (state->ccache == NULL) {
619 0 : ret = ENOMEM;
620 0 : goto immediate;
621 : }
622 :
623 13 : DEBUG(SSSDBG_TRACE_LIBS,
624 : "Trust direction of subdom %s from forest %s is: %s\n",
625 : subdom->name, state->forest,
626 : ipa_trust_dir2str(state->direction));
627 :
628 13 : if (state->direction & LSA_TRUST_DIRECTION_OUTBOUND) {
629 : /* Use system keytab, nothing to do here */
630 4 : ret = EOK;
631 4 : goto immediate;
632 9 : } else if (state->direction & LSA_TRUST_DIRECTION_INBOUND) {
633 : /* Need special keytab */
634 9 : ret = ipa_server_trusted_dom_setup_1way(req);
635 9 : if (ret == EAGAIN) {
636 : /* In progress.. */
637 9 : return req;
638 0 : } else if (ret == EOK) {
639 : /* Keytab available, shortcut */
640 0 : ret = EOK;
641 0 : goto immediate;
642 : }
643 : } else {
644 : /* Even unset is an error at this point */
645 0 : DEBUG(SSSDBG_OP_FAILURE,
646 : "Subdomain %s has trust direction %d\n",
647 : subdom->name, subdom->trust_direction);
648 0 : ret = ERR_TRUST_NOT_SUPPORTED;
649 : }
650 :
651 : immediate:
652 4 : if (ret != EOK) {
653 0 : DEBUG(SSSDBG_OP_FAILURE,
654 : "Could not add trusted subdomain %s from forest %s\n",
655 : subdom->name, state->forest);
656 0 : tevent_req_error(req, ret);
657 : } else {
658 4 : tevent_req_done(req);
659 : }
660 4 : tevent_req_post(req, ev);
661 4 : return req;
662 : }
663 :
664 9 : static errno_t ipa_server_trusted_dom_setup_1way(struct tevent_req *req)
665 : {
666 : errno_t ret;
667 9 : struct tevent_req *subreq = NULL;
668 9 : struct ipa_server_trusted_dom_setup_state *state =
669 9 : tevent_req_data(req, struct ipa_server_trusted_dom_setup_state);
670 : const char *hostname;
671 :
672 9 : state->keytab = forest_keytab(state, state->forest);
673 9 : if (state->keytab == NULL) {
674 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n");
675 0 : return EIO;
676 : }
677 :
678 9 : state->new_keytab = talloc_asprintf(state, "%sXXXXXX", state->keytab);
679 9 : if (state->new_keytab == NULL) {
680 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n");
681 0 : return ENOMEM;
682 : }
683 :
684 9 : ret = sss_unique_filename(state, state->new_keytab);
685 9 : if (ret != EOK) {
686 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create temporary keytab name\n");
687 0 : return ret;
688 : }
689 :
690 9 : DEBUG(SSSDBG_TRACE_FUNC,
691 : "Will re-fetch keytab for %s\n", state->subdom->name);
692 :
693 9 : hostname = dp_opt_get_string(state->id_ctx->ipa_options->basic,
694 : IPA_HOSTNAME);
695 :
696 9 : state->principal = subdomain_trust_princ(state,
697 : state->forest_realm,
698 : state->subdom);
699 9 : if (state->principal == NULL) {
700 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n");
701 0 : return EIO;
702 : }
703 :
704 9 : subreq = ipa_getkeytab_send(state->be_ctx, state->be_ctx->ev,
705 : state->ccache,
706 : hostname,
707 : state->principal,
708 9 : state->new_keytab);
709 9 : if (subreq == NULL) {
710 0 : return ENOMEM;
711 : }
712 9 : tevent_req_set_callback(subreq, ipa_server_trust_1way_kt_done, req);
713 9 : return EAGAIN;
714 : }
715 :
716 9 : static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq)
717 : {
718 : errno_t ret;
719 9 : struct tevent_req *req = tevent_req_callback_data(subreq,
720 : struct tevent_req);
721 9 : struct ipa_server_trusted_dom_setup_state *state =
722 9 : tevent_req_data(req, struct ipa_server_trusted_dom_setup_state);
723 :
724 9 : ret = ipa_getkeytab_recv(subreq, NULL);
725 9 : talloc_zfree(subreq);
726 9 : if (ret != EOK) {
727 : /* Do not fail here, but try to check and use the previous keytab,
728 : * if any */
729 3 : DEBUG(SSSDBG_MINOR_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret);
730 : } else {
731 6 : DEBUG(SSSDBG_TRACE_FUNC,
732 : "Keytab successfully retrieved to %s\n", state->new_keytab);
733 : }
734 :
735 18 : ret = ipa_check_keytab(state->new_keytab,
736 9 : state->id_ctx->server_mode->kt_owner_uid,
737 9 : state->id_ctx->server_mode->kt_owner_gid);
738 9 : if (ret == EOK) {
739 6 : ret = rename(state->new_keytab, state->keytab);
740 6 : if (ret == -1) {
741 0 : ret = errno;
742 0 : DEBUG(SSSDBG_CRIT_FAILURE,
743 : "rename failed [%d][%s].\n", ret, strerror(ret));
744 0 : tevent_req_error(req, ret);
745 0 : return;
746 : }
747 6 : DEBUG(SSSDBG_TRACE_INTERNAL, "Keytab renamed to %s\n", state->keytab);
748 3 : } else if (ret != EOK) {
749 3 : DEBUG(SSSDBG_MINOR_FAILURE,
750 : "Trying to recover and use the previous keytab, if available\n");
751 6 : ret = ipa_check_keytab(state->keytab,
752 3 : state->id_ctx->server_mode->kt_owner_uid,
753 3 : state->id_ctx->server_mode->kt_owner_gid);
754 3 : if (ret == EOK) {
755 2 : DEBUG(SSSDBG_TRACE_FUNC,
756 : "The previous keytab %s contains the expected principal\n",
757 : state->keytab);
758 : } else {
759 1 : DEBUG(SSSDBG_OP_FAILURE,
760 : "Cannot use the old keytab: %d\n", ret);
761 : /* Nothing we can do now */
762 1 : tevent_req_error(req, ret);
763 1 : return;
764 : }
765 : }
766 :
767 8 : DEBUG(SSSDBG_TRACE_FUNC,
768 : "Keytab %s contains the expected principals\n", state->new_keytab);
769 :
770 8 : DEBUG(SSSDBG_TRACE_FUNC,
771 : "Established trust context for %s\n", state->subdom->name);
772 8 : tevent_req_done(req);
773 : }
774 :
775 13 : errno_t ipa_server_trusted_dom_setup_recv(struct tevent_req *req)
776 : {
777 14 : TEVENT_REQ_RETURN_ON_ERROR(req);
778 12 : return EOK;
779 : }
780 :
781 : struct ipa_server_create_trusts_state {
782 : struct tevent_context *ev;
783 : struct be_ctx *be_ctx;
784 : struct ipa_id_ctx *id_ctx;
785 : struct sss_domain_info *domiter;
786 : };
787 :
788 : static errno_t ipa_server_create_trusts_step(struct tevent_req *req);
789 : static errno_t ipa_server_create_trusts_ctx(struct tevent_req *req);
790 : static void ipa_server_create_trusts_done(struct tevent_req *subreq);
791 :
792 : struct tevent_req *
793 8 : ipa_server_create_trusts_send(TALLOC_CTX *mem_ctx,
794 : struct tevent_context *ev,
795 : struct be_ctx *be_ctx,
796 : struct ipa_id_ctx *id_ctx,
797 : struct sss_domain_info *parent)
798 : {
799 8 : struct tevent_req *req = NULL;
800 8 : struct ipa_server_create_trusts_state *state = NULL;
801 : errno_t ret;
802 :
803 8 : req = tevent_req_create(mem_ctx, &state,
804 : struct ipa_server_create_trusts_state);
805 8 : if (req == NULL) {
806 0 : return NULL;
807 : }
808 :
809 8 : state->ev = ev;
810 8 : state->be_ctx = be_ctx;
811 8 : state->id_ctx = id_ctx;
812 8 : state->domiter = parent;
813 :
814 8 : ret = ipa_server_create_trusts_step(req);
815 8 : if (ret != EAGAIN) {
816 1 : goto immediate;
817 : }
818 :
819 7 : return req;
820 :
821 : immediate:
822 1 : if (ret != EOK) {
823 0 : tevent_req_error(req, ret);
824 : } else {
825 1 : tevent_req_done(req);
826 : }
827 1 : tevent_req_post(req, ev);
828 1 : return req;
829 : }
830 :
831 20 : static errno_t ipa_server_create_trusts_step(struct tevent_req *req)
832 : {
833 20 : struct tevent_req *subreq = NULL;
834 : struct ipa_ad_server_ctx *trust_iter;
835 20 : struct ipa_server_create_trusts_state *state = NULL;
836 :
837 20 : state = tevent_req_data(req, struct ipa_server_create_trusts_state);
838 :
839 40 : for (state->domiter = get_next_domain(state->domiter, true);
840 33 : state->domiter && IS_SUBDOMAIN(state->domiter);
841 0 : state->domiter = get_next_domain(state->domiter, false)) {
842 :
843 : /* Check if we already have an ID context for this subdomain */
844 19 : DLIST_FOR_EACH(trust_iter, state->id_ctx->server_mode->trusts) {
845 6 : if (trust_iter->dom == state->domiter) {
846 0 : break;
847 : }
848 : }
849 :
850 : /* Newly detected trust */
851 13 : if (trust_iter == NULL) {
852 13 : subreq = ipa_server_trusted_dom_setup_send(state,
853 : state->ev,
854 : state->be_ctx,
855 : state->id_ctx,
856 : state->domiter);
857 13 : if (subreq == NULL) {
858 0 : return ENOMEM;
859 : }
860 13 : tevent_req_set_callback(subreq, ipa_server_create_trusts_done, req);
861 13 : return EAGAIN;
862 : }
863 : }
864 :
865 7 : return EOK;
866 : }
867 :
868 13 : static void ipa_server_create_trusts_done(struct tevent_req *subreq)
869 : {
870 : errno_t ret;
871 13 : struct tevent_req *req = tevent_req_callback_data(subreq,
872 : struct tevent_req);
873 :
874 13 : ret = ipa_server_trusted_dom_setup_recv(subreq);
875 13 : talloc_zfree(subreq);
876 13 : if (ret != EOK) {
877 1 : tevent_req_error(req, ret);
878 1 : return;
879 : }
880 :
881 12 : ret = ipa_server_create_trusts_ctx(req);
882 12 : if (ret != EOK) {
883 0 : tevent_req_error(req, ret);
884 0 : return;
885 : }
886 :
887 12 : ret = ipa_server_create_trusts_step(req);
888 12 : if (ret == EOK) {
889 6 : tevent_req_done(req);
890 6 : return;
891 6 : } else if (ret != EAGAIN) {
892 0 : tevent_req_error(req, ret);
893 0 : return;
894 : }
895 :
896 : /* Will cycle back */
897 : }
898 :
899 12 : static errno_t ipa_server_create_trusts_ctx(struct tevent_req *req)
900 : {
901 : struct ipa_ad_server_ctx *trust_ctx;
902 : struct ad_id_ctx *ad_id_ctx;
903 : errno_t ret;
904 12 : struct ipa_server_create_trusts_state *state = NULL;
905 :
906 12 : state = tevent_req_data(req, struct ipa_server_create_trusts_state);
907 :
908 12 : ret = ipa_ad_ctx_new(state->be_ctx, state->id_ctx, state->domiter, &ad_id_ctx);
909 12 : if (ret != EOK) {
910 0 : DEBUG(SSSDBG_OP_FAILURE,
911 : "Cannot create ad_id_ctx for subdomain %s\n", state->domiter->name);
912 0 : return ret;
913 : }
914 :
915 12 : trust_ctx = talloc(state->id_ctx->server_mode, struct ipa_ad_server_ctx);
916 12 : if (trust_ctx == NULL) {
917 0 : return ENOMEM;
918 : }
919 12 : trust_ctx->dom = state->domiter;
920 12 : trust_ctx->ad_id_ctx = ad_id_ctx;
921 :
922 12 : DLIST_ADD(state->id_ctx->server_mode->trusts, trust_ctx);
923 12 : return EOK;
924 : }
925 :
926 8 : errno_t ipa_server_create_trusts_recv(struct tevent_req *req)
927 : {
928 9 : TEVENT_REQ_RETURN_ON_ERROR(req);
929 7 : return EOK;
930 : }
931 :
932 1 : void ipa_ad_subdom_remove(struct be_ctx *be_ctx,
933 : struct ipa_id_ctx *id_ctx,
934 : struct sss_domain_info *subdom)
935 : {
936 : struct ipa_ad_server_ctx *iter;
937 : struct sdap_domain *sdom;
938 :
939 2 : if (dp_opt_get_bool(id_ctx->ipa_options->basic,
940 1 : IPA_SERVER_MODE) == false) {
941 0 : return;
942 : }
943 :
944 1 : DLIST_FOR_EACH(iter, id_ctx->server_mode->trusts) {
945 1 : if (iter->dom == subdom) break;
946 : }
947 :
948 1 : if (iter == NULL) {
949 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No IPA-AD context for subdomain %s\n",
950 : subdom->name);
951 0 : return;
952 : }
953 :
954 1 : sdom = sdap_domain_get(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
955 1 : if (sdom == NULL) return;
956 1 : be_ptask_destroy(&sdom->enum_task);
957 1 : be_ptask_destroy(&sdom->cleanup_task);
958 :
959 1 : sdap_domain_remove(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
960 1 : DLIST_REMOVE(id_ctx->server_mode->trusts, iter);
961 :
962 : /* terminate all requests for this subdomain so we can free it */
963 1 : be_terminate_domain_requests(be_ctx, subdom->name);
964 1 : talloc_zfree(sdom);
965 : }
966 :
967 : struct ipa_ad_subdom_reinit_state {
968 : struct tevent_context *ev;
969 : struct be_ctx *be_ctx;
970 : struct ipa_id_ctx *id_ctx;
971 : struct sss_domain_info *parent;
972 : };
973 :
974 2 : static void create_trusts_at_startup_done(struct tevent_req *req)
975 : {
976 : errno_t ret;
977 :
978 2 : ret = ipa_server_create_trusts_recv(req);
979 2 : talloc_free(req);
980 2 : if (ret != EOK) {
981 0 : DEBUG(SSSDBG_MINOR_FAILURE,
982 : "ipa_server_create_trusts_send request failed [%d]: %s\n",
983 : ret, sss_strerror(ret));
984 : }
985 2 : }
986 :
987 2 : static void create_trusts_at_startup(struct tevent_context *ev,
988 : struct tevent_immediate *imm,
989 : void *pvt)
990 : {
991 : struct tevent_req *req;
992 : struct ipa_ad_subdom_reinit_state *state;
993 :
994 2 : state = talloc_get_type(pvt, struct ipa_ad_subdom_reinit_state);
995 :
996 2 : req = ipa_server_create_trusts_send(state, state->ev, state->be_ctx,
997 : state->id_ctx, state->parent);
998 2 : if (req == NULL) {
999 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_server_create_trusts_send failed.\n");
1000 0 : talloc_free(state);
1001 0 : return;
1002 : }
1003 :
1004 2 : tevent_req_set_callback(req, create_trusts_at_startup_done, state);
1005 2 : return;
1006 : }
1007 :
1008 2 : static errno_t ipa_ad_subdom_reinit(TALLOC_CTX *mem_ctx,
1009 : struct tevent_context *ev,
1010 : struct be_ctx *be_ctx,
1011 : struct ipa_id_ctx *id_ctx,
1012 : struct sss_domain_info *parent)
1013 : {
1014 : struct tevent_immediate *imm;
1015 : struct ipa_ad_subdom_reinit_state *state;
1016 :
1017 2 : state = talloc(mem_ctx, struct ipa_ad_subdom_reinit_state);
1018 2 : if (state == NULL) {
1019 0 : return ENOMEM;
1020 : }
1021 2 : state->ev = ev;
1022 2 : state->be_ctx = be_ctx;
1023 2 : state->id_ctx = id_ctx;
1024 2 : state->parent = parent;
1025 :
1026 4 : if (dp_opt_get_bool(id_ctx->ipa_options->basic,
1027 2 : IPA_SERVER_MODE) == false) {
1028 0 : return EOK;
1029 : }
1030 :
1031 2 : imm = tevent_create_immediate(mem_ctx);
1032 2 : if (imm == NULL) {
1033 0 : DEBUG(SSSDBG_OP_FAILURE, "tevent_create_immediate failed.\n");
1034 0 : talloc_free(state);
1035 0 : return ENOMEM;
1036 : }
1037 :
1038 2 : tevent_schedule_immediate(imm, ev, create_trusts_at_startup, state);
1039 2 : return EOK;
1040 : }
1041 :
1042 2 : int ipa_ad_subdom_init(struct be_ctx *be_ctx,
1043 : struct ipa_id_ctx *id_ctx)
1044 : {
1045 : char *realm;
1046 : char *hostname;
1047 : errno_t ret;
1048 :
1049 4 : if (dp_opt_get_bool(id_ctx->ipa_options->basic,
1050 2 : IPA_SERVER_MODE) == false) {
1051 0 : return EOK;
1052 : }
1053 :
1054 : /* The IPA code relies on the default FQDN format to unparse user
1055 : * names. Warn loudly if the full_name_format was customized on the
1056 : * IPA server
1057 : */
1058 2 : if ((strcmp(be_ctx->domain->names->fq_fmt,
1059 : CONFDB_DEFAULT_FULL_NAME_FORMAT) != 0)
1060 0 : && (strcmp(be_ctx->domain->names->fq_fmt,
1061 : CONFDB_DEFAULT_FULL_NAME_FORMAT_INTERNAL) != 0)) {
1062 0 : DEBUG(SSSDBG_FATAL_FAILURE, "%s is set to a non-default value [%s] " \
1063 : "lookups of subdomain users will likely fail!\n",
1064 : CONFDB_FULL_NAME_FORMAT, be_ctx->domain->names->fq_fmt);
1065 0 : sss_log(SSS_LOG_ERR, "%s is set to a non-default value [%s] " \
1066 : "lookups of subdomain users will likely fail!\n",
1067 0 : CONFDB_FULL_NAME_FORMAT, be_ctx->domain->names->fq_fmt);
1068 : /* Attempt to continue */
1069 : }
1070 :
1071 2 : realm = dp_opt_get_string(id_ctx->ipa_options->basic, IPA_KRB5_REALM);
1072 2 : if (realm == NULL) {
1073 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
1074 0 : return EINVAL;
1075 : }
1076 :
1077 2 : hostname = dp_opt_get_string(id_ctx->ipa_options->basic, IPA_HOSTNAME);
1078 2 : if (hostname == NULL) {
1079 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No host name for IPA?\n");
1080 0 : return EINVAL;
1081 : }
1082 :
1083 2 : id_ctx->server_mode = talloc_zero(id_ctx, struct ipa_server_mode_ctx);
1084 2 : if (id_ctx->server_mode == NULL) {
1085 0 : return ENOMEM;
1086 : }
1087 2 : id_ctx->server_mode->realm = realm;
1088 2 : id_ctx->server_mode->hostname = hostname;
1089 2 : id_ctx->server_mode->trusts = NULL;
1090 2 : id_ctx->server_mode->ext_groups = NULL;
1091 2 : id_ctx->server_mode->kt_owner_uid = 0;
1092 2 : id_ctx->server_mode->kt_owner_gid = 0;
1093 :
1094 2 : if (getuid() == 0) {
1095 : /* We need to handle keytabs created by IPA oddjob script gracefully
1096 : * even if we're running as root and IPA creates them as the SSSD user
1097 : */
1098 0 : ret = sss_user_by_name_or_uid(SSSD_USER,
1099 0 : &id_ctx->server_mode->kt_owner_uid,
1100 0 : &id_ctx->server_mode->kt_owner_gid);
1101 0 : if (ret != EOK) {
1102 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get ID of %s\n", SSSD_USER);
1103 : }
1104 : }
1105 :
1106 2 : ret = ipa_ad_subdom_reinit(be_ctx, be_ctx->ev,
1107 : be_ctx, id_ctx, be_ctx->domain);
1108 2 : if (ret != EOK) {
1109 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_ad_subdom_refresh failed.\n");
1110 0 : return ret;
1111 : }
1112 :
1113 2 : return EOK;
1114 : }
|