Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Backend Module -- selinux loading
5 :
6 : Authors:
7 : Jan Zeleny <jzeleny@redhat.com>
8 :
9 : Copyright (C) 2012 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 : #include <security/pam_modules.h>
25 :
26 : #include "db/sysdb_selinux.h"
27 : #include "util/child_common.h"
28 : #include "util/sss_selinux.h"
29 : #include "providers/ldap/sdap_async.h"
30 : #include "providers/ipa/ipa_common.h"
31 : #include "providers/ipa/ipa_config.h"
32 : #include "providers/ipa/ipa_selinux.h"
33 : #include "providers/ipa/ipa_hosts.h"
34 : #include "providers/ipa/ipa_hbac_rules.h"
35 : #include "providers/ipa/ipa_hbac_private.h"
36 : #include "providers/ipa/ipa_access.h"
37 : #include "providers/ipa/ipa_selinux_maps.h"
38 : #include "providers/ipa/ipa_subdomains.h"
39 :
40 : #ifndef SELINUX_CHILD_DIR
41 : #ifndef SSSD_LIBEXEC_PATH
42 : #error "SSSD_LIBEXEC_PATH not defined"
43 : #endif /* SSSD_LIBEXEC_PATH */
44 :
45 : #define SELINUX_CHILD_DIR SSSD_LIBEXEC_PATH
46 : #endif /* SELINUX_CHILD_DIR */
47 :
48 : #define SELINUX_CHILD SELINUX_CHILD_DIR"/selinux_child"
49 : #define SELINUX_CHILD_LOG_FILE "selinux_child"
50 :
51 : #include <selinux/selinux.h>
52 :
53 : /* fd used by the selinux_child process for logging */
54 : int selinux_child_debug_fd = -1;
55 :
56 : static struct tevent_req *
57 : ipa_get_selinux_send(TALLOC_CTX *mem_ctx,
58 : struct be_ctx *be_ctx,
59 : struct sysdb_attrs *user,
60 : struct sysdb_attrs *host,
61 : struct ipa_selinux_ctx *selinux_ctx);
62 : static errno_t ipa_get_selinux_recv(struct tevent_req *req,
63 : TALLOC_CTX *mem_ctx,
64 : size_t *count,
65 : struct sysdb_attrs ***maps,
66 : size_t *hbac_count,
67 : struct sysdb_attrs ***hbac_rules,
68 : char **default_user,
69 : char **map_order);
70 :
71 : static void ipa_get_selinux_connect_done(struct tevent_req *subreq);
72 : static void ipa_get_selinux_hosts_done(struct tevent_req *subreq);
73 : static void ipa_get_config_step(struct tevent_req *req);
74 : static void ipa_get_selinux_config_done(struct tevent_req *subreq);
75 : static void ipa_get_selinux_maps_done(struct tevent_req *subreq);
76 : static void ipa_get_selinux_hbac_done(struct tevent_req *subreq);
77 : static errno_t ipa_selinux_process_maps(TALLOC_CTX *mem_ctx,
78 : struct sysdb_attrs *user,
79 : struct sysdb_attrs *host,
80 : struct sysdb_attrs **selinux_maps,
81 : size_t selinux_map_count,
82 : struct sysdb_attrs **hbac_rules,
83 : size_t hbac_rule_count,
84 : struct sysdb_attrs ***usermaps);
85 :
86 : static errno_t
87 0 : ipa_save_user_maps(struct sysdb_ctx *sysdb,
88 : struct sss_domain_info *domain,
89 : size_t map_count,
90 : struct sysdb_attrs **maps)
91 : {
92 : errno_t ret;
93 : errno_t sret;
94 0 : bool in_transaction = false;
95 : int i;
96 :
97 0 : ret = sysdb_transaction_start(sysdb);
98 0 : if (ret) {
99 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
100 0 : goto done;
101 : }
102 0 : in_transaction = true;
103 :
104 0 : for (i = 0; i < map_count; i++) {
105 0 : ret = sysdb_store_selinux_usermap(domain, maps[i]);
106 0 : if (ret != EOK) {
107 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store user map %d. "
108 : "Ignoring.\n", i);
109 : } else {
110 0 : DEBUG(SSSDBG_TRACE_FUNC, "User map %d processed.\n", i);
111 : }
112 : }
113 :
114 0 : ret = sysdb_transaction_commit(sysdb);
115 0 : if (ret) {
116 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
117 0 : goto done;
118 : }
119 0 : in_transaction = false;
120 0 : ret = EOK;
121 :
122 : done:
123 0 : if (in_transaction) {
124 0 : sret = sysdb_transaction_cancel(sysdb);
125 0 : if (sret != EOK) {
126 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
127 : }
128 : }
129 0 : return ret;
130 : }
131 :
132 : struct map_order_ctx {
133 : char *order;
134 : char **order_array;
135 : size_t order_count;
136 : };
137 :
138 : struct selinux_child_input {
139 : const char *seuser;
140 : const char *mls_range;
141 : const char *username;
142 : };
143 :
144 : static errno_t
145 : ipa_selinux_process_seealso_maps(struct sysdb_attrs *user,
146 : struct sysdb_attrs *host,
147 : struct sysdb_attrs **seealso_rules,
148 : size_t seealso_rules_count,
149 : struct sysdb_attrs **hbac_rules,
150 : size_t hbac_rule_count,
151 : uint32_t top_priority,
152 : struct sysdb_attrs **usermaps,
153 : size_t best_match_maps_cnt);
154 : static errno_t
155 0 : ipa_selinux_process_maps(TALLOC_CTX *mem_ctx,
156 : struct sysdb_attrs *user,
157 : struct sysdb_attrs *host,
158 : struct sysdb_attrs **selinux_maps,
159 : size_t selinux_map_count,
160 : struct sysdb_attrs **hbac_rules,
161 : size_t hbac_rule_count,
162 : struct sysdb_attrs ***_usermaps)
163 : {
164 : TALLOC_CTX *tmp_ctx;
165 : int i;
166 : errno_t ret;
167 0 : uint32_t priority = 0;
168 0 : uint32_t top_priority = 0;
169 : struct sysdb_attrs **seealso_rules;
170 0 : size_t num_seealso_rules = 0;
171 : const char *seealso_str;
172 : struct sysdb_attrs **usermaps;
173 0 : size_t best_match_maps_cnt = 0;
174 :
175 0 : tmp_ctx = talloc_new(NULL);
176 0 : if (!tmp_ctx) {
177 0 : return ENOMEM;
178 : }
179 :
180 0 : seealso_rules = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
181 : selinux_map_count + 1);
182 0 : if (seealso_rules == NULL) {
183 0 : ret = ENOMEM;
184 0 : goto done;
185 : }
186 :
187 0 : usermaps = talloc_zero_array(tmp_ctx, struct sysdb_attrs *, selinux_map_count + 1);
188 0 : if (usermaps == NULL) {
189 0 : ret = ENOMEM;
190 0 : goto done;
191 : }
192 :
193 0 : for (i = 0; i < selinux_map_count; i++) {
194 0 : if (sss_selinux_match(selinux_maps[i], user, host, &priority)) {
195 0 : if (priority < top_priority) {
196 : /* This rule has lower priority than what we already have,
197 : * skip it. */
198 0 : continue;
199 0 : } else if (priority > top_priority) {
200 : /* This rule has higher priority, drop what we already have */
201 0 : while (best_match_maps_cnt > 0) {
202 0 : best_match_maps_cnt--;
203 0 : usermaps[best_match_maps_cnt] = NULL;
204 : }
205 0 : top_priority = priority;
206 : }
207 :
208 0 : usermaps[best_match_maps_cnt] = selinux_maps[i];
209 0 : best_match_maps_cnt++;
210 :
211 0 : continue;
212 : }
213 :
214 : /* SELinux map did not matched -> check sealso attribute for
215 : * possible HBAC match */
216 0 : ret = sysdb_attrs_get_string(selinux_maps[i],
217 : SYSDB_SELINUX_SEEALSO, &seealso_str);
218 0 : if (ret == ENOENT) {
219 0 : continue;
220 0 : } else if (ret != EOK) {
221 0 : goto done;
222 : }
223 :
224 0 : seealso_rules[num_seealso_rules] = selinux_maps[i];
225 0 : num_seealso_rules++;
226 : }
227 :
228 0 : ret = ipa_selinux_process_seealso_maps(user, host,
229 : seealso_rules, num_seealso_rules,
230 : hbac_rules, hbac_rule_count,
231 : top_priority, usermaps, best_match_maps_cnt);
232 0 : if (ret != EOK) {
233 0 : goto done;
234 : }
235 :
236 0 : *_usermaps = talloc_steal(mem_ctx, usermaps);
237 :
238 0 : ret = EOK;
239 : done:
240 0 : talloc_free(tmp_ctx);
241 0 : return ret;
242 : }
243 :
244 : static errno_t
245 0 : ipa_selinux_process_seealso_maps(struct sysdb_attrs *user,
246 : struct sysdb_attrs *host,
247 : struct sysdb_attrs **seealso_rules,
248 : size_t seealso_rules_count,
249 : struct sysdb_attrs **hbac_rules,
250 : size_t hbac_rule_count,
251 : uint32_t top_priority,
252 : struct sysdb_attrs **usermaps,
253 : size_t best_match_maps_cnt)
254 : {
255 : int i, j;
256 : errno_t ret;
257 : struct ldb_message_element *el;
258 : struct sysdb_attrs *usermap;
259 : const char *seealso_dn;
260 : const char *hbac_dn;
261 : uint32_t priority;
262 :
263 0 : for (i = 0; i < hbac_rule_count; i++) {
264 0 : ret = sysdb_attrs_get_string(hbac_rules[i], SYSDB_ORIG_DN, &hbac_dn);
265 0 : if (ret != EOK) {
266 0 : return ret;
267 : }
268 :
269 : /* We need to do this translation for further processing. We have to
270 : * do it manually because no map was used to retrieve HBAC rules.
271 : */
272 0 : ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_HOST, &el);
273 0 : if (ret != EOK) return ret;
274 0 : el->name = SYSDB_ORIG_MEMBER_HOST;
275 :
276 0 : ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_USER, &el);
277 0 : if (ret != EOK) return ret;
278 0 : el->name = SYSDB_ORIG_MEMBER_USER;
279 :
280 0 : DEBUG(SSSDBG_TRACE_ALL,
281 : "Matching HBAC rule %s with SELinux mappings\n", hbac_dn);
282 :
283 0 : if (!sss_selinux_match(hbac_rules[i], user, host, &priority)) {
284 0 : DEBUG(SSSDBG_TRACE_ALL, "Rule did not match\n");
285 0 : continue;
286 : }
287 :
288 : /* HBAC rule matched, find if it is in the "possible" list */
289 0 : for (j = 0; j < seealso_rules_count; j++) {
290 0 : usermap = seealso_rules[j];
291 0 : if (usermap == NULL) {
292 0 : continue;
293 : }
294 :
295 0 : ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn);
296 0 : if (ret != EOK) {
297 0 : return ret;
298 : }
299 :
300 0 : if (strcasecmp(hbac_dn, seealso_dn) == 0) {
301 0 : DEBUG(SSSDBG_TRACE_FUNC, "HBAC rule [%s] matched, copying its"
302 : "attributes to SELinux user map [%s]\n",
303 : hbac_dn, seealso_dn);
304 :
305 : /* Selinux maps priority evaluation removed --DELETE this comment before pushing*/
306 0 : if (priority < top_priority) {
307 : /* This rule has lower priority than what we already have,
308 : * skip it. */
309 0 : continue;
310 0 : } else if (priority > top_priority) {
311 : /* This rule has higher priority, drop what we already have */
312 0 : while (best_match_maps_cnt > 0) {
313 0 : best_match_maps_cnt--;
314 0 : usermaps[best_match_maps_cnt] = NULL;
315 : }
316 0 : top_priority = priority;
317 : }
318 :
319 0 : usermaps[best_match_maps_cnt] = usermap;
320 0 : best_match_maps_cnt++;
321 :
322 0 : ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_ORIG_MEMBER_USER);
323 0 : if (ret != EOK) {
324 0 : return ret;
325 : }
326 :
327 0 : ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_USER_CATEGORY);
328 0 : if (ret != EOK) {
329 0 : return ret;
330 : }
331 :
332 : /* Speed up the next iteration */
333 0 : seealso_rules[j] = NULL;
334 : }
335 : }
336 : }
337 :
338 0 : return EOK;
339 : }
340 :
341 0 : static errno_t init_map_order_ctx(TALLOC_CTX *mem_ctx, const char *map_order,
342 : struct map_order_ctx **_mo_ctx)
343 : {
344 : TALLOC_CTX *tmp_ctx;
345 : errno_t ret;
346 : int i;
347 : int len;
348 : struct map_order_ctx *mo_ctx;
349 :
350 0 : tmp_ctx = talloc_new(NULL);
351 0 : if (tmp_ctx == NULL) {
352 0 : ret = ENOMEM;
353 0 : goto done;
354 : }
355 :
356 0 : mo_ctx = talloc(tmp_ctx, struct map_order_ctx);
357 0 : if (mo_ctx == NULL) {
358 0 : ret = ENOMEM;
359 0 : goto done;
360 : }
361 :
362 : /* The "order" string contains one or more SELinux user records
363 : * separated by $. Now we need to create an array of string from
364 : * this one string. First find out how many elements in the array
365 : * will be. This way only one alloc will be necessary for the array
366 : */
367 0 : mo_ctx->order_count = 1;
368 0 : len = strlen(map_order);
369 0 : for (i = 0; i < len; i++) {
370 0 : if (map_order[i] == '$') mo_ctx->order_count++;
371 : }
372 :
373 0 : mo_ctx->order_array = talloc_array(mo_ctx, char *, mo_ctx->order_count);
374 0 : if (mo_ctx->order_array == NULL) {
375 0 : ret = ENOMEM;
376 0 : goto done;
377 : }
378 :
379 0 : mo_ctx->order = talloc_strdup(mo_ctx, map_order);
380 0 : if (mo_ctx->order == NULL) {
381 0 : ret = ENOMEM;
382 0 : goto done;
383 : }
384 :
385 : /* Now fill the array with pointers to the original string. Also
386 : * use binary zeros to make multiple string out of the one.
387 : */
388 0 : mo_ctx->order_array[0] = mo_ctx->order;
389 0 : mo_ctx->order_count = 1;
390 0 : for (i = 0; i < len; i++) {
391 0 : if (mo_ctx->order[i] == '$') {
392 0 : mo_ctx->order[i] = '\0';
393 0 : mo_ctx->order_array[mo_ctx->order_count] = &mo_ctx->order[i+1];
394 0 : mo_ctx->order_count++;
395 : }
396 : }
397 :
398 0 : *_mo_ctx = talloc_steal(mem_ctx, mo_ctx);
399 0 : ret = EOK;
400 : done:
401 0 : talloc_free(tmp_ctx);
402 0 : return ret;
403 : }
404 :
405 : static errno_t selinux_child_setup(TALLOC_CTX *mem_ctx,
406 : const char *orig_name,
407 : struct sss_domain_info *dom,
408 : const char *seuser_mls_string,
409 : struct selinux_child_input **_sci);
410 :
411 : /* Choose best selinux user based on given order and write
412 : * the user to selinux login file. */
413 0 : static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx,
414 : struct sysdb_attrs **usermaps,
415 : struct pam_data *pd,
416 : struct sss_domain_info *user_domain,
417 : struct map_order_ctx *mo_ctx,
418 : const char *default_user,
419 : struct selinux_child_input **_sci)
420 : {
421 : TALLOC_CTX *tmp_ctx;
422 0 : char *seuser_mls_str = NULL;
423 : const char *tmp_str;
424 : errno_t ret;
425 : int i, j;
426 : struct selinux_child_input *sci;
427 :
428 0 : tmp_ctx = talloc_new(NULL);
429 0 : if (tmp_ctx == NULL) {
430 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
431 0 : return ENOMEM;
432 : }
433 :
434 : /* If no maps match, we'll use the default SELinux user from the
435 : * config */
436 0 : seuser_mls_str = talloc_strdup(tmp_ctx, default_user ? default_user : "");
437 0 : if (seuser_mls_str == NULL) {
438 0 : ret = ENOMEM;
439 0 : goto done;
440 : }
441 :
442 : /* Iterate through the order array and try to find SELinux users
443 : * in fetched maps. The order array contains all SELinux users
444 : * allowed in the domain in the same order they should appear
445 : * in the SELinux config file. If any user from the order array
446 : * is not in fetched user maps, it means it should not be allowed
447 : * for the user who is just logging in.
448 : *
449 : * Right now we have empty content of the SELinux config file,
450 : * we shall add only those SELinux users that are present both in
451 : * the order array and user maps applicable to the user who is
452 : * logging in.
453 : */
454 0 : for (i = 0; i < mo_ctx->order_count; i++) {
455 0 : for (j = 0; usermaps[j] != NULL; j++) {
456 0 : tmp_str = sss_selinux_map_get_seuser(usermaps[j]);
457 :
458 0 : if (tmp_str && !strcasecmp(tmp_str, mo_ctx->order_array[i])) {
459 : /* If seuser_mls_str contained something, overwrite it.
460 : * This record has higher priority.
461 : */
462 0 : talloc_zfree(seuser_mls_str);
463 0 : seuser_mls_str = talloc_strdup(tmp_ctx, tmp_str);
464 0 : if (seuser_mls_str == NULL) {
465 0 : ret = ENOMEM;
466 0 : goto done;
467 : }
468 0 : break;
469 : }
470 : }
471 : }
472 :
473 0 : ret = selinux_child_setup(tmp_ctx, pd->user, user_domain, seuser_mls_str, &sci);
474 0 : if (ret != EOK) {
475 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot set up child input buffer\n");
476 0 : goto done;
477 : }
478 :
479 0 : *_sci = talloc_steal(mem_ctx, sci);
480 0 : ret = EOK;
481 : done:
482 0 : talloc_free(tmp_ctx);
483 0 : return ret;
484 : }
485 :
486 : static errno_t
487 0 : selinux_child_setup(TALLOC_CTX *mem_ctx,
488 : const char *orig_name,
489 : struct sss_domain_info *dom,
490 : const char *seuser_mls_string,
491 : struct selinux_child_input **_sci)
492 : {
493 : errno_t ret;
494 : char *seuser;
495 : const char *mls_range;
496 : char *ptr;
497 : char *username;
498 : char *username_final;
499 0 : char *domain_name = NULL;
500 : TALLOC_CTX *tmp_ctx;
501 : struct selinux_child_input *sci;
502 :
503 0 : tmp_ctx = talloc_new(NULL);
504 0 : if (tmp_ctx == NULL) {
505 0 : return ENOMEM;
506 : }
507 :
508 : /* Split seuser and mls_range */
509 0 : seuser = talloc_strdup(tmp_ctx, seuser_mls_string);
510 0 : if (seuser == NULL) {
511 0 : ret = ENOMEM;
512 0 : goto done;
513 : }
514 :
515 0 : ptr = seuser;
516 0 : while (*ptr != ':' && *ptr != '\0') {
517 0 : ptr++;
518 : }
519 0 : if (*ptr == '\0') {
520 : /* No mls_range specified */
521 0 : mls_range = "";
522 : } else {
523 0 : *ptr = '\0'; /* split */
524 0 : mls_range = ptr + 1;
525 : }
526 :
527 : /* pam_selinux needs the username in the same format getpwnam() would
528 : * return it
529 : */
530 0 : username = sss_get_cased_name(tmp_ctx, orig_name, dom->case_preserve);
531 0 : if (username == NULL) {
532 0 : ret = ENOMEM;
533 0 : goto done;
534 : }
535 :
536 0 : if (dom->fqnames) {
537 0 : ret = sss_parse_name(tmp_ctx, dom->names, username, &domain_name,
538 : NULL);
539 0 : if (ret == EOK && domain_name != NULL) {
540 : /* username is already a fully qualified name */
541 0 : username_final = username;
542 0 : } else if ((ret == EOK && domain_name == NULL)
543 0 : || ret == ERR_REGEX_NOMATCH) {
544 0 : username_final = talloc_asprintf(tmp_ctx, dom->names->fq_fmt,
545 : username, dom->name);
546 0 : if (username_final == NULL) {
547 0 : ret = ENOMEM;
548 0 : goto done;
549 : }
550 : } else {
551 0 : DEBUG(SSSDBG_OP_FAILURE,
552 : "sss_parse_name failed: [%d] %s\n", ret, sss_strerror(ret));
553 0 : goto done;
554 : }
555 : } else {
556 0 : username_final = username;
557 : }
558 :
559 0 : sci = talloc(tmp_ctx, struct selinux_child_input);
560 0 : if (sci == NULL) {
561 0 : ret = ENOMEM;
562 0 : goto done;
563 : }
564 :
565 0 : sci->seuser = talloc_strdup(sci, seuser);
566 0 : sci->mls_range = talloc_strdup(sci, mls_range);
567 0 : sci->username = talloc_strdup(sci, username_final);
568 0 : if (sci->seuser == NULL || sci->mls_range == NULL
569 0 : || sci->username == NULL) {
570 0 : ret = ENOMEM;
571 0 : goto done;
572 : }
573 :
574 0 : *_sci = talloc_steal(mem_ctx, sci);
575 0 : ret = EOK;
576 : done:
577 0 : talloc_free(tmp_ctx);
578 0 : return ret;
579 : }
580 :
581 : struct selinux_child_state {
582 : struct selinux_child_input *sci;
583 : struct tevent_context *ev;
584 : struct io_buffer *buf;
585 : struct child_io_fds *io;
586 : };
587 :
588 : static errno_t selinux_child_init(void);
589 : static errno_t selinux_child_create_buffer(struct selinux_child_state *state);
590 : static errno_t selinux_fork_child(struct selinux_child_state *state);
591 : static void selinux_child_step(struct tevent_req *subreq);
592 : static void selinux_child_done(struct tevent_req *subreq);
593 : static errno_t selinux_child_parse_response(uint8_t *buf, ssize_t len,
594 : uint32_t *_child_result);
595 :
596 0 : static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx,
597 : struct tevent_context *ev,
598 : struct selinux_child_input *sci)
599 : {
600 : struct tevent_req *req;
601 : struct tevent_req *subreq;
602 : struct selinux_child_state *state;
603 : errno_t ret;
604 :
605 0 : req = tevent_req_create(mem_ctx, &state, struct selinux_child_state);
606 0 : if (req == NULL) {
607 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
608 0 : return NULL;
609 : }
610 :
611 0 : state->sci = sci;
612 0 : state->ev = ev;
613 0 : state->io = talloc(state, struct child_io_fds);
614 0 : state->buf = talloc(state, struct io_buffer);
615 0 : if (state->io == NULL || state->buf == NULL) {
616 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
617 0 : ret = ENOMEM;
618 0 : goto immediately;
619 : }
620 :
621 0 : state->io->write_to_child_fd = -1;
622 0 : state->io->read_from_child_fd = -1;
623 0 : talloc_set_destructor((void *) state->io, child_io_destructor);
624 :
625 0 : ret = selinux_child_init();
626 0 : if (ret != EOK) {
627 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to init the child\n");
628 0 : goto immediately;
629 : }
630 :
631 0 : ret = selinux_child_create_buffer(state);
632 0 : if (ret != EOK) {
633 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to create the send buffer\n");
634 0 : ret = ENOMEM;
635 0 : goto immediately;
636 : }
637 :
638 0 : ret = selinux_fork_child(state);
639 0 : if (ret != EOK) {
640 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to fork the child\n");
641 0 : goto immediately;
642 : }
643 :
644 0 : subreq = write_pipe_send(state, ev, state->buf->data, state->buf->size,
645 0 : state->io->write_to_child_fd);
646 0 : if (subreq == NULL) {
647 0 : ret = ENOMEM;
648 0 : goto immediately;
649 : }
650 0 : tevent_req_set_callback(subreq, selinux_child_step, req);
651 :
652 0 : ret = EOK;
653 : immediately:
654 0 : if (ret != EOK) {
655 0 : tevent_req_error(req, ret);
656 0 : tevent_req_post(req, ev);
657 : }
658 0 : return req;
659 : }
660 :
661 0 : static errno_t selinux_child_init(void)
662 : {
663 0 : return child_debug_init(SELINUX_CHILD_LOG_FILE, &selinux_child_debug_fd);
664 : }
665 :
666 0 : static errno_t selinux_child_create_buffer(struct selinux_child_state *state)
667 : {
668 : size_t rp;
669 : size_t seuser_len;
670 : size_t mls_range_len;
671 : size_t username_len;
672 :
673 0 : seuser_len = strlen(state->sci->seuser);
674 0 : mls_range_len = strlen(state->sci->mls_range);
675 0 : username_len = strlen(state->sci->username);
676 :
677 0 : state->buf->size = 3 * sizeof(uint32_t);
678 0 : state->buf->size += seuser_len + mls_range_len + username_len;
679 :
680 0 : DEBUG(SSSDBG_TRACE_ALL, "buffer size: %zu\n", state->buf->size);
681 :
682 0 : state->buf->data = talloc_size(state->buf, state->buf->size);
683 0 : if (state->buf->data == NULL) {
684 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
685 0 : return ENOMEM;
686 : }
687 :
688 0 : rp = 0;
689 :
690 : /* seuser */
691 0 : SAFEALIGN_SET_UINT32(&state->buf->data[rp], seuser_len, &rp);
692 0 : safealign_memcpy(&state->buf->data[rp], state->sci->seuser,
693 : seuser_len, &rp);
694 :
695 : /* mls_range */
696 0 : SAFEALIGN_SET_UINT32(&state->buf->data[rp], mls_range_len, &rp);
697 0 : safealign_memcpy(&state->buf->data[rp], state->sci->mls_range,
698 : mls_range_len, &rp);
699 :
700 : /* username */
701 0 : SAFEALIGN_SET_UINT32(&state->buf->data[rp], username_len, &rp);
702 0 : safealign_memcpy(&state->buf->data[rp], state->sci->username,
703 : username_len, &rp);
704 :
705 0 : return EOK;
706 : }
707 :
708 0 : static errno_t selinux_fork_child(struct selinux_child_state *state)
709 : {
710 : int pipefd_to_child[2];
711 : int pipefd_from_child[2];
712 : pid_t pid;
713 : errno_t ret;
714 :
715 0 : ret = pipe(pipefd_from_child);
716 0 : if (ret == -1) {
717 0 : ret = errno;
718 0 : DEBUG(SSSDBG_CRIT_FAILURE,
719 : "pipe failed [%d][%s].\n", errno, sss_strerror(errno));
720 0 : return ret;
721 : }
722 :
723 0 : ret = pipe(pipefd_to_child);
724 0 : if (ret == -1) {
725 0 : ret = errno;
726 0 : DEBUG(SSSDBG_CRIT_FAILURE,
727 : "pipe failed [%d][%s].\n", errno, sss_strerror(errno));
728 0 : return ret;
729 : }
730 :
731 0 : pid = fork();
732 :
733 0 : if (pid == 0) { /* child */
734 0 : exec_child(state, pipefd_to_child, pipefd_from_child,
735 : SELINUX_CHILD, selinux_child_debug_fd);
736 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n",
737 : ret, sss_strerror(ret));
738 0 : return ret;
739 0 : } else if (pid > 0) { /* parent */
740 0 : state->io->read_from_child_fd = pipefd_from_child[0];
741 0 : close(pipefd_from_child[1]);
742 0 : state->io->write_to_child_fd = pipefd_to_child[1];
743 0 : close(pipefd_to_child[0]);
744 0 : sss_fd_nonblocking(state->io->read_from_child_fd);
745 0 : sss_fd_nonblocking(state->io->write_to_child_fd);
746 :
747 0 : ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
748 0 : if (ret != EOK) {
749 0 : DEBUG(SSSDBG_CRIT_FAILURE,
750 : "Could not set up child signal handler\n");
751 0 : return ret;
752 : }
753 : } else { /* error */
754 0 : ret = errno;
755 0 : DEBUG(SSSDBG_CRIT_FAILURE,
756 : "fork failed [%d][%s].\n", errno, sss_strerror(errno));
757 0 : return ret;
758 : }
759 :
760 0 : return EOK;
761 : }
762 :
763 0 : static void selinux_child_step(struct tevent_req *subreq)
764 : {
765 : struct tevent_req *req;
766 : errno_t ret;
767 : struct selinux_child_state *state;
768 :
769 :
770 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
771 0 : state = tevent_req_data(req, struct selinux_child_state);
772 :
773 0 : ret = write_pipe_recv(subreq);
774 0 : talloc_zfree(subreq);
775 0 : if (ret != EOK) {
776 0 : tevent_req_error(req, ret);
777 0 : return;
778 : }
779 :
780 0 : close(state->io->write_to_child_fd);
781 0 : state->io->write_to_child_fd = -1;
782 :
783 0 : subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
784 0 : if (subreq == NULL) {
785 0 : tevent_req_error(req, ENOMEM);
786 0 : return;
787 : }
788 0 : tevent_req_set_callback(subreq, selinux_child_done, req);
789 : }
790 :
791 0 : static void selinux_child_done(struct tevent_req *subreq)
792 : {
793 : struct tevent_req *req;
794 : struct selinux_child_state *state;
795 : uint32_t child_result;
796 : errno_t ret;
797 : ssize_t len;
798 : uint8_t *buf;
799 :
800 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
801 0 : state = tevent_req_data(req, struct selinux_child_state);
802 :
803 0 : ret = read_pipe_recv(subreq, state, &buf, &len);
804 0 : talloc_zfree(subreq);
805 0 : if (ret != EOK) {
806 0 : tevent_req_error(req, ret);
807 0 : return;
808 : }
809 :
810 0 : close(state->io->read_from_child_fd);
811 0 : state->io->read_from_child_fd = -1;
812 :
813 0 : ret = selinux_child_parse_response(buf, len, &child_result);
814 0 : if (ret != EOK) {
815 0 : DEBUG(SSSDBG_CRIT_FAILURE,
816 : "selinux_child_parse_response failed: [%d][%s]\n",
817 : ret, strerror(ret));
818 0 : tevent_req_error(req, ret);
819 0 : return;
820 0 : } else if (child_result != 0){
821 0 : DEBUG(SSSDBG_CRIT_FAILURE,
822 : "Error in selinux_child: [%d][%s]\n",
823 : child_result, strerror(child_result));
824 0 : tevent_req_error(req, ERR_SELINUX_CONTEXT);
825 0 : return;
826 : }
827 :
828 0 : tevent_req_done(req);
829 0 : return;
830 : }
831 :
832 0 : static errno_t selinux_child_parse_response(uint8_t *buf,
833 : ssize_t len,
834 : uint32_t *_child_result)
835 : {
836 0 : size_t p = 0;
837 : uint32_t child_result;
838 :
839 : /* semanage retval */
840 0 : SAFEALIGN_COPY_UINT32_CHECK(&child_result, buf + p, len, &p);
841 :
842 0 : *_child_result = child_result;
843 0 : return EOK;
844 : }
845 :
846 0 : static errno_t selinux_child_recv(struct tevent_req *req)
847 : {
848 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
849 0 : return EOK;
850 : }
851 :
852 : /* A more generic request to gather all SELinux and HBAC rules. Updates
853 : * cache if necessary
854 : */
855 : struct ipa_get_selinux_state {
856 : struct be_ctx *be_ctx;
857 : struct ipa_selinux_ctx *selinux_ctx;
858 : struct sdap_id_op *op;
859 :
860 : struct sysdb_attrs *host;
861 : struct sysdb_attrs *user;
862 :
863 : struct sysdb_attrs *defaults;
864 : struct sysdb_attrs **selinuxmaps;
865 : size_t nmaps;
866 :
867 : struct sysdb_attrs **hbac_rules;
868 : size_t hbac_rule_count;
869 : };
870 :
871 : static errno_t
872 : ipa_get_selinux_maps_offline(struct tevent_req *req);
873 :
874 : static struct tevent_req *
875 0 : ipa_get_selinux_send(TALLOC_CTX *mem_ctx,
876 : struct be_ctx *be_ctx,
877 : struct sysdb_attrs *user,
878 : struct sysdb_attrs *host,
879 : struct ipa_selinux_ctx *selinux_ctx)
880 : {
881 : struct tevent_req *req;
882 : struct tevent_req *subreq;
883 : struct ipa_get_selinux_state *state;
884 : bool offline;
885 0 : int ret = EOK;
886 : time_t now;
887 : time_t refresh_interval;
888 0 : struct ipa_options *ipa_options = selinux_ctx->id_ctx->ipa_options;
889 :
890 0 : DEBUG(SSSDBG_TRACE_FUNC, "Retrieving SELinux user mapping\n");
891 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_get_selinux_state);
892 0 : if (req == NULL) {
893 0 : return NULL;
894 : }
895 :
896 0 : state->be_ctx = be_ctx;
897 0 : state->selinux_ctx = selinux_ctx;
898 0 : state->user = user;
899 0 : state->host = host;
900 :
901 0 : offline = be_is_offline(be_ctx);
902 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Connection status is [%s].\n",
903 : offline ? "offline" : "online");
904 :
905 0 : if (!offline) {
906 0 : refresh_interval = dp_opt_get_int(ipa_options->basic,
907 : IPA_SELINUX_REFRESH);
908 0 : now = time(NULL);
909 0 : if (now < selinux_ctx->last_update + refresh_interval) {
910 : /* SELinux maps were recently updated -> force offline */
911 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
912 : "Performing cached SELinux processing\n");
913 0 : offline = true;
914 : }
915 : }
916 :
917 0 : if (!offline) {
918 0 : state->op = sdap_id_op_create(state,
919 0 : selinux_ctx->id_ctx->sdap_id_ctx->conn->conn_cache);
920 0 : if (!state->op) {
921 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
922 0 : ret = ENOMEM;
923 0 : goto immediate;
924 : }
925 :
926 0 : subreq = sdap_id_op_connect_send(state->op, state, &ret);
927 0 : if (!subreq) {
928 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send failed: "
929 : "%d(%s).\n", ret, strerror(ret));
930 0 : talloc_zfree(state->op);
931 0 : goto immediate;
932 : }
933 :
934 0 : tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req);
935 : } else {
936 0 : ret = ipa_get_selinux_maps_offline(req);
937 0 : goto immediate;
938 : }
939 :
940 0 : return req;
941 :
942 : immediate:
943 0 : if (ret == EOK) {
944 0 : tevent_req_done(req);
945 : } else {
946 0 : tevent_req_error(req, ret);
947 : }
948 0 : tevent_req_post(req, be_ctx->ev);
949 0 : return req;
950 : }
951 :
952 0 : static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
953 : {
954 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
955 : struct tevent_req);
956 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
957 : struct ipa_get_selinux_state);
958 0 : int dp_error = DP_ERR_FATAL;
959 : int ret;
960 0 : struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx;
961 : struct dp_module *access_mod;
962 : struct dp_module *selinux_mod;
963 : const char *hostname;
964 :
965 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
966 0 : talloc_zfree(subreq);
967 :
968 0 : if (dp_error == DP_ERR_OFFLINE) {
969 0 : talloc_zfree(state->op);
970 0 : ret = ipa_get_selinux_maps_offline(req);
971 0 : if (ret == EOK) {
972 0 : tevent_req_done(req);
973 0 : return;
974 : }
975 0 : goto fail;
976 : }
977 :
978 0 : if (ret != EOK) {
979 0 : goto fail;
980 : }
981 :
982 0 : access_mod = dp_target_module(state->be_ctx->provider, DPT_ACCESS);
983 0 : selinux_mod = dp_target_module(state->be_ctx->provider, DPT_SELINUX);
984 0 : if (access_mod == selinux_mod && state->host != NULL) {
985 : /* If the access control module is the same as the selinux module
986 : * and the access control had already discovered the host
987 : */
988 0 : return ipa_get_config_step(req);
989 : }
990 :
991 0 : hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic,
992 : IPA_HOSTNAME);
993 0 : if (hostname == NULL) {
994 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot determine the host name\n");
995 0 : goto fail;
996 : }
997 :
998 0 : subreq = ipa_host_info_send(state, state->be_ctx->ev,
999 : sdap_id_op_handle(state->op),
1000 0 : id_ctx->sdap_id_ctx->opts,
1001 : hostname,
1002 0 : id_ctx->ipa_options->host_map,
1003 : NULL,
1004 0 : state->selinux_ctx->host_search_bases);
1005 0 : if (subreq == NULL) {
1006 0 : ret = ENOMEM;
1007 0 : goto fail;
1008 : }
1009 :
1010 0 : tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req);
1011 0 : return;
1012 :
1013 : fail:
1014 0 : tevent_req_error(req, ret);
1015 : }
1016 :
1017 : static errno_t
1018 0 : ipa_get_selinux_maps_offline(struct tevent_req *req)
1019 : {
1020 : errno_t ret;
1021 : size_t nmaps;
1022 : struct ldb_message **maps;
1023 : struct ldb_message *defaults;
1024 0 : const char *attrs[] = { SYSDB_NAME,
1025 : SYSDB_USER_CATEGORY,
1026 : SYSDB_HOST_CATEGORY,
1027 : SYSDB_ORIG_MEMBER_USER,
1028 : SYSDB_ORIG_MEMBER_HOST,
1029 : SYSDB_SELINUX_SEEALSO,
1030 : SYSDB_SELINUX_USER,
1031 : NULL };
1032 : const char *default_user;
1033 : const char *order;
1034 :
1035 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
1036 : struct ipa_get_selinux_state);
1037 :
1038 : /* read the config entry */
1039 0 : ret = sysdb_search_selinux_config(state, state->be_ctx->domain,
1040 : NULL, &defaults);
1041 0 : if (ret != EOK) {
1042 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_selinux_config failed [%d]: %s\n",
1043 : ret, strerror(ret));
1044 0 : return ret;
1045 : }
1046 :
1047 0 : default_user = ldb_msg_find_attr_as_string(defaults,
1048 : SYSDB_SELINUX_DEFAULT_USER,
1049 : NULL);
1050 0 : order = ldb_msg_find_attr_as_string(defaults, SYSDB_SELINUX_DEFAULT_ORDER,
1051 : NULL);
1052 :
1053 0 : state->defaults = sysdb_new_attrs(state);
1054 0 : if (state->defaults == NULL) {
1055 0 : return ENOMEM;
1056 : }
1057 :
1058 0 : if (default_user) {
1059 0 : ret = sysdb_attrs_add_string(state->defaults,
1060 : IPA_CONFIG_SELINUX_DEFAULT_USER_CTX,
1061 : default_user);
1062 0 : if (ret != EOK) {
1063 0 : return ret;
1064 : }
1065 : }
1066 :
1067 0 : ret = sysdb_attrs_add_string(state->defaults,
1068 : IPA_CONFIG_SELINUX_MAP_ORDER, order);
1069 0 : if (ret != EOK) {
1070 0 : return ret;
1071 : }
1072 :
1073 : /* read all the SELinux rules */
1074 0 : ret = sysdb_get_selinux_usermaps(state, state->be_ctx->domain,
1075 : attrs, &nmaps, &maps);
1076 0 : if (ret != EOK) {
1077 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_selinux_usermaps failed [%d]: %s\n",
1078 : ret, strerror(ret));
1079 0 : return ret;
1080 : }
1081 :
1082 0 : ret = sysdb_msg2attrs(state, nmaps, maps, &state->selinuxmaps);
1083 0 : if (ret != EOK) {
1084 0 : return ret;
1085 : }
1086 0 : state->nmaps = nmaps;
1087 :
1088 : /* read all the HBAC rules */
1089 0 : ret = hbac_get_cached_rules(state, state->be_ctx->domain,
1090 : &state->hbac_rule_count, &state->hbac_rules);
1091 0 : if (ret != EOK) {
1092 0 : DEBUG(SSSDBG_OP_FAILURE, "hbac_get_cached_rules failed [%d]: %s\n",
1093 : ret, strerror(ret));
1094 0 : return ret;
1095 : }
1096 :
1097 0 : return EOK;
1098 : }
1099 :
1100 0 : static void ipa_get_selinux_hosts_done(struct tevent_req *subreq)
1101 : {
1102 : errno_t ret;
1103 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1104 : struct tevent_req);
1105 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
1106 : struct ipa_get_selinux_state);
1107 : size_t host_count, hostgroup_count;
1108 : struct sysdb_attrs **hostgroups;
1109 : struct sysdb_attrs **host;
1110 :
1111 0 : ret = ipa_host_info_recv(subreq, state, &host_count, &host,
1112 : &hostgroup_count, &hostgroups);
1113 0 : talloc_free(subreq);
1114 0 : if (ret != EOK) {
1115 0 : goto done;
1116 : }
1117 0 : state->host = host[0];
1118 :
1119 0 : return ipa_get_config_step(req);
1120 :
1121 : done:
1122 0 : if (ret != EOK) {
1123 0 : tevent_req_error(req, ret);
1124 : }
1125 : }
1126 :
1127 0 : static void ipa_get_config_step(struct tevent_req *req)
1128 : {
1129 : const char *domain;
1130 : struct tevent_req *subreq;
1131 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
1132 : struct ipa_get_selinux_state);
1133 0 : struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx;
1134 :
1135 0 : domain = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic,
1136 : IPA_KRB5_REALM);
1137 0 : subreq = ipa_get_config_send(state, state->be_ctx->ev,
1138 : sdap_id_op_handle(state->op),
1139 0 : id_ctx->sdap_id_ctx->opts,
1140 : domain, NULL);
1141 0 : if (subreq == NULL) {
1142 0 : tevent_req_error(req, ENOMEM);
1143 : }
1144 0 : tevent_req_set_callback(subreq, ipa_get_selinux_config_done, req);
1145 0 : }
1146 :
1147 0 : static void ipa_get_selinux_config_done(struct tevent_req *subreq)
1148 : {
1149 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1150 : struct tevent_req);
1151 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
1152 : struct ipa_get_selinux_state);
1153 0 : struct sdap_id_ctx *id_ctx = state->selinux_ctx->id_ctx->sdap_id_ctx;
1154 : errno_t ret;
1155 :
1156 0 : ret = ipa_get_config_recv(subreq, state, &state->defaults);
1157 0 : talloc_free(subreq);
1158 0 : if (ret != EOK) {
1159 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not get IPA config\n");
1160 0 : goto done;
1161 : }
1162 :
1163 0 : subreq = ipa_selinux_get_maps_send(state, state->be_ctx->ev,
1164 0 : state->be_ctx->domain->sysdb,
1165 : sdap_id_op_handle(state->op),
1166 : id_ctx->opts,
1167 0 : state->selinux_ctx->id_ctx->ipa_options,
1168 0 : state->selinux_ctx->selinux_search_bases);
1169 0 : if (!subreq) {
1170 0 : ret = ENOMEM;
1171 0 : goto done;
1172 : }
1173 0 : tevent_req_set_callback(subreq, ipa_get_selinux_maps_done, req);
1174 0 : return;
1175 :
1176 : done:
1177 0 : if (ret != EOK) {
1178 0 : tevent_req_error(req, ret);
1179 : } else {
1180 0 : tevent_req_done(req);
1181 : }
1182 : }
1183 :
1184 0 : static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
1185 : {
1186 : struct tevent_req *req;
1187 : struct ipa_get_selinux_state *state;
1188 : struct ipa_id_ctx *id_ctx;
1189 : struct dp_module *access_mod;
1190 : struct dp_module *selinux_mod;
1191 :
1192 : const char *tmp_str;
1193 : bool check_hbac;
1194 : errno_t ret;
1195 : int i;
1196 :
1197 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1198 0 : state = tevent_req_data(req, struct ipa_get_selinux_state);
1199 0 : id_ctx = state->selinux_ctx->id_ctx;
1200 :
1201 0 : ret = ipa_selinux_get_maps_recv(subreq, state,
1202 : &state->nmaps, &state->selinuxmaps);
1203 0 : talloc_free(subreq);
1204 0 : if (ret != EOK) {
1205 0 : if (ret == ENOENT) {
1206 : /* This is returned if no SELinux mapping
1207 : * rules were found. In that case no error
1208 : * occurred, but we don't want any more processing.*/
1209 0 : ret = EOK;
1210 : }
1211 0 : goto done;
1212 : }
1213 :
1214 0 : DEBUG(SSSDBG_TRACE_FUNC,
1215 : "Found %zu SELinux user maps\n", state->nmaps);
1216 :
1217 0 : check_hbac = false;
1218 0 : for (i = 0; i < state->nmaps; i++) {
1219 0 : ret = sysdb_attrs_get_string(state->selinuxmaps[i],
1220 : SYSDB_SELINUX_SEEALSO, &tmp_str);
1221 0 : if (ret == EOK) {
1222 0 : check_hbac = true;
1223 0 : break;
1224 : }
1225 : }
1226 :
1227 0 : if (check_hbac) {
1228 0 : access_mod = dp_target_module(state->be_ctx->provider, DPT_ACCESS);
1229 0 : selinux_mod = dp_target_module(state->be_ctx->provider, DPT_SELINUX);
1230 0 : if (access_mod == selinux_mod) {
1231 0 : ret = hbac_get_cached_rules(state, state->be_ctx->domain,
1232 : &state->hbac_rule_count,
1233 : &state->hbac_rules);
1234 : /* Terminates the request */
1235 0 : goto done;
1236 : }
1237 :
1238 0 : DEBUG(SSSDBG_TRACE_FUNC, "SELinux maps referenced an HBAC rule. "
1239 : "Need to refresh HBAC rules\n");
1240 0 : subreq = ipa_hbac_rule_info_send(state, state->be_ctx->ev,
1241 : sdap_id_op_handle(state->op),
1242 0 : id_ctx->sdap_id_ctx->opts,
1243 0 : state->selinux_ctx->hbac_search_bases,
1244 : state->host);
1245 0 : if (subreq == NULL) {
1246 0 : ret = ENOMEM;
1247 0 : goto done;
1248 : }
1249 :
1250 0 : tevent_req_set_callback(subreq, ipa_get_selinux_hbac_done, req);
1251 0 : return;
1252 : }
1253 :
1254 0 : ret = EOK;
1255 : done:
1256 0 : if (ret == EOK) {
1257 0 : tevent_req_done(req);
1258 : } else {
1259 0 : tevent_req_error(req, ret);
1260 : }
1261 : }
1262 :
1263 0 : static void ipa_get_selinux_hbac_done(struct tevent_req *subreq)
1264 : {
1265 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1266 : struct tevent_req);
1267 0 : struct ipa_get_selinux_state *state = tevent_req_data(req,
1268 : struct ipa_get_selinux_state);
1269 : errno_t ret;
1270 :
1271 0 : ret = ipa_hbac_rule_info_recv(subreq, state, &state->hbac_rule_count,
1272 : &state->hbac_rules);
1273 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1274 : "Received %zu HBAC rules\n", state->hbac_rule_count);
1275 0 : talloc_free(subreq);
1276 :
1277 0 : if (ret != EOK) {
1278 0 : tevent_req_error(req, ret);
1279 : } else {
1280 0 : tevent_req_done(req);
1281 : }
1282 0 : }
1283 :
1284 : static errno_t
1285 0 : ipa_get_selinux_recv(struct tevent_req *req,
1286 : TALLOC_CTX *mem_ctx,
1287 : size_t *count,
1288 : struct sysdb_attrs ***maps,
1289 : size_t *hbac_count,
1290 : struct sysdb_attrs ***hbac_rules,
1291 : char **default_user,
1292 : char **map_order)
1293 : {
1294 0 : struct ipa_get_selinux_state *state =
1295 0 : tevent_req_data(req, struct ipa_get_selinux_state);
1296 : const char *tmp_str;
1297 : errno_t ret;
1298 :
1299 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1300 :
1301 0 : ret = sysdb_attrs_get_string(state->defaults,
1302 : IPA_CONFIG_SELINUX_DEFAULT_USER_CTX,
1303 : &tmp_str);
1304 0 : if (ret != EOK && ret != ENOENT) {
1305 0 : return ret;
1306 : }
1307 :
1308 0 : if (ret == EOK) {
1309 0 : *default_user = talloc_strdup(mem_ctx, tmp_str);
1310 0 : if (*default_user == NULL) {
1311 0 : return ENOMEM;
1312 : }
1313 : }
1314 :
1315 0 : ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_MAP_ORDER,
1316 : &tmp_str);
1317 0 : if (ret != EOK) {
1318 0 : return ret;
1319 : }
1320 :
1321 0 : *map_order = talloc_strdup(mem_ctx, tmp_str);
1322 0 : if (*map_order == NULL) {
1323 0 : talloc_zfree(*default_user);
1324 0 : return ENOMEM;
1325 : }
1326 :
1327 0 : *count = state->nmaps;
1328 0 : *maps = talloc_steal(mem_ctx, state->selinuxmaps);
1329 :
1330 0 : *hbac_count = state->hbac_rule_count;
1331 0 : *hbac_rules = talloc_steal(mem_ctx, state->hbac_rules);
1332 :
1333 0 : return EOK;
1334 : }
1335 :
1336 : static errno_t
1337 0 : ipa_selinux_init_attrs(TALLOC_CTX *mem_ctx,
1338 : struct sysdb_ctx *sysdb,
1339 : struct sss_domain_info *ipa_domain,
1340 : struct sss_domain_info *user_domain,
1341 : const char *username,
1342 : const char *hostname,
1343 : struct sysdb_attrs **_user,
1344 : struct sysdb_attrs **_host)
1345 : {
1346 : TALLOC_CTX *tmp_ctx;
1347 : struct ldb_dn *host_dn;
1348 0 : const char *attrs[] = { SYSDB_ORIG_DN,
1349 : SYSDB_ORIG_MEMBEROF,
1350 : NULL };
1351 : size_t count;
1352 : struct ldb_message **msgs;
1353 : struct sysdb_attrs **hosts;
1354 0 : struct sysdb_attrs *user = NULL;
1355 0 : struct sysdb_attrs *host = NULL;
1356 : errno_t ret;
1357 :
1358 0 : tmp_ctx = talloc_new(NULL);
1359 0 : if (tmp_ctx == NULL) {
1360 0 : return ENOMEM;
1361 : }
1362 :
1363 0 : ret = sss_selinux_extract_user(tmp_ctx, user_domain, username, &user);
1364 0 : if (ret != EOK) {
1365 0 : goto done;
1366 : }
1367 :
1368 0 : host_dn = sysdb_custom_dn(tmp_ctx, ipa_domain, hostname, HBAC_HOSTS_SUBDIR);
1369 0 : if (host_dn == NULL) {
1370 0 : goto done;
1371 : }
1372 :
1373 : /* Look up the host to get its originalMemberOf entries */
1374 0 : ret = sysdb_search_entry(tmp_ctx, sysdb, host_dn, LDB_SCOPE_BASE, NULL,
1375 : attrs, &count, &msgs);
1376 0 : if (ret == ENOENT || count == 0) {
1377 0 : host = NULL;
1378 0 : ret = EOK;
1379 0 : goto done;
1380 0 : } else if (ret != EOK) {
1381 0 : goto done;
1382 0 : } else if (count > 1) {
1383 0 : DEBUG(SSSDBG_OP_FAILURE, "More than one result for a BASE search!\n");
1384 0 : goto done;
1385 : }
1386 :
1387 0 : ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &hosts);
1388 0 : talloc_free(msgs);
1389 0 : if (ret != EOK) {
1390 0 : goto done;
1391 : }
1392 :
1393 0 : host = hosts[0];
1394 :
1395 0 : ret = EOK;
1396 :
1397 : done:
1398 0 : if (ret == EOK) {
1399 0 : *_user = talloc_steal(mem_ctx, user);
1400 0 : *_host = talloc_steal(mem_ctx, host);
1401 : }
1402 :
1403 0 : talloc_free(tmp_ctx);
1404 :
1405 0 : return ret;
1406 : }
1407 :
1408 : static errno_t
1409 0 : ipa_selinux_store_config(struct sysdb_ctx *sysdb,
1410 : struct sss_domain_info *ipa_domain,
1411 : const char *default_user,
1412 : const char *map_order,
1413 : size_t map_count,
1414 : struct sysdb_attrs **maps)
1415 : {
1416 0 : bool in_transaction = false;
1417 : errno_t sret;
1418 : errno_t ret;
1419 :
1420 0 : ret = sysdb_transaction_start(sysdb);
1421 0 : if (ret != EOK) {
1422 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1423 0 : goto done;
1424 : }
1425 0 : in_transaction = true;
1426 :
1427 0 : ret = sysdb_delete_usermaps(ipa_domain);
1428 0 : if (ret != EOK) {
1429 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot delete existing maps from sysdb\n");
1430 0 : goto done;
1431 : }
1432 :
1433 0 : ret = sysdb_store_selinux_config(ipa_domain, default_user, map_order);
1434 0 : if (ret != EOK) {
1435 0 : goto done;
1436 : }
1437 :
1438 0 : if (map_count > 0) {
1439 0 : ret = ipa_save_user_maps(sysdb, ipa_domain, map_count, maps);
1440 0 : if (ret != EOK) {
1441 0 : goto done;
1442 : }
1443 : }
1444 :
1445 0 : ret = sysdb_transaction_commit(sysdb);
1446 0 : if (ret != EOK) {
1447 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not commit transaction\n");
1448 0 : goto done;
1449 : }
1450 0 : in_transaction = false;
1451 :
1452 0 : ret = EOK;
1453 :
1454 : done:
1455 0 : if (in_transaction) {
1456 0 : sret = sysdb_transaction_cancel(sysdb);
1457 0 : if (sret != EOK) {
1458 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
1459 : }
1460 : }
1461 :
1462 0 : return ret;
1463 : }
1464 :
1465 : static errno_t
1466 0 : ipa_selinux_create_child_input(TALLOC_CTX *mem_ctx,
1467 : struct sysdb_attrs *user,
1468 : struct sysdb_attrs *host,
1469 : struct sysdb_attrs **maps,
1470 : size_t map_count,
1471 : struct sysdb_attrs **hbac_rules,
1472 : size_t hbac_count,
1473 : const char *map_order,
1474 : struct pam_data *pd,
1475 : struct sss_domain_info *user_domain,
1476 : const char *default_user,
1477 : struct selinux_child_input **_sci)
1478 : {
1479 0 : struct sysdb_attrs **best_match_maps = NULL;
1480 0 : struct map_order_ctx *map_order_ctx = NULL;
1481 0 : struct selinux_child_input *sci = NULL;
1482 : errno_t ret;
1483 :
1484 : /* Process the maps and return list of best matches
1485 : * (maps with highest priority). */
1486 0 : ret = ipa_selinux_process_maps(mem_ctx, user, host, maps, map_count,
1487 : hbac_rules, hbac_count, &best_match_maps);
1488 0 : if (ret != EOK) {
1489 0 : goto done;
1490 : }
1491 :
1492 0 : ret = init_map_order_ctx(mem_ctx, map_order, &map_order_ctx);
1493 0 : if (ret != EOK) {
1494 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1495 : "Failed to create ordered SELinux users array.\n");
1496 0 : goto done;
1497 : }
1498 :
1499 0 : ret = choose_best_seuser(mem_ctx, best_match_maps, pd, user_domain,
1500 : map_order_ctx, default_user, &sci);
1501 0 : if (ret != EOK) {
1502 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1503 : "Failed to evaluate ordered SELinux users array.\n");
1504 0 : goto done;
1505 : }
1506 :
1507 0 : *_sci = sci;
1508 :
1509 0 : ret = EOK;
1510 :
1511 : done:
1512 0 : if (ret != EOK) {
1513 0 : talloc_free(best_match_maps);
1514 0 : talloc_free(map_order_ctx);
1515 0 : talloc_free(sci);
1516 : }
1517 :
1518 0 : return ret;
1519 : }
1520 :
1521 : struct ipa_selinux_handler_state {
1522 : struct be_ctx *be_ctx;
1523 : struct tevent_context *ev;
1524 : struct pam_data *pd;
1525 :
1526 : struct sss_domain_info *user_domain;
1527 : struct sss_domain_info *ipa_domain;
1528 : struct ipa_selinux_ctx *selinux_ctx;
1529 :
1530 : struct sysdb_attrs *user;
1531 : struct sysdb_attrs *host;
1532 : };
1533 :
1534 : static void ipa_selinux_handler_get_done(struct tevent_req *subreq);
1535 : static void ipa_selinux_handler_done(struct tevent_req *subreq);
1536 :
1537 : struct tevent_req *
1538 0 : ipa_selinux_handler_send(TALLOC_CTX *mem_ctx,
1539 : struct ipa_selinux_ctx *selinux_ctx,
1540 : struct pam_data *pd,
1541 : struct dp_req_params *params)
1542 : {
1543 : struct ipa_selinux_handler_state *state;
1544 : struct tevent_req *subreq;
1545 : struct tevent_req *req;
1546 : const char *hostname;
1547 : errno_t ret;
1548 :
1549 0 : req = tevent_req_create(mem_ctx, &state,
1550 : struct ipa_selinux_handler_state);
1551 0 : if (req == NULL) {
1552 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1553 0 : return NULL;
1554 : }
1555 :
1556 0 : state->be_ctx = params->be_ctx;
1557 0 : state->ev = params->ev;
1558 0 : state->pd = pd;
1559 0 : state->user_domain = params->domain;
1560 0 : state->ipa_domain = params->be_ctx->domain;
1561 0 : state->selinux_ctx = selinux_ctx;
1562 :
1563 0 : pd->pam_status = PAM_SYSTEM_ERR;
1564 :
1565 0 : hostname = dp_opt_get_string(selinux_ctx->id_ctx->ipa_options->basic,
1566 : IPA_HOSTNAME);
1567 0 : if (hostname == NULL) {
1568 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot determine this machine's host name\n");
1569 0 : ret = EINVAL;
1570 0 : goto immediately;
1571 : }
1572 :
1573 0 : ret = ipa_selinux_init_attrs(state, state->user_domain->sysdb,
1574 0 : state->ipa_domain, state->user_domain,
1575 0 : pd->user, hostname,
1576 0 : &state->user, &state->host);
1577 0 : if (ret != EOK) {
1578 0 : goto immediately;
1579 : }
1580 :
1581 0 : subreq = ipa_get_selinux_send(state, params->be_ctx, state->user,
1582 0 : state->host, selinux_ctx);
1583 0 : if (subreq == NULL) {
1584 0 : goto immediately;
1585 : }
1586 :
1587 0 : tevent_req_set_callback(subreq, ipa_selinux_handler_get_done, req);
1588 :
1589 0 : return req;
1590 :
1591 : immediately:
1592 : /* TODO For backward compatibility we always return EOK to DP now. */
1593 0 : tevent_req_done(req);
1594 0 : tevent_req_post(req, params->ev);
1595 :
1596 0 : return req;
1597 : }
1598 :
1599 0 : static void ipa_selinux_handler_get_done(struct tevent_req *subreq)
1600 : {
1601 : struct tevent_req *req;
1602 : struct ipa_selinux_handler_state *state;
1603 : struct selinux_child_input *sci;
1604 0 : struct sysdb_attrs **hbac_rules = NULL;
1605 0 : struct sysdb_attrs **maps = NULL;
1606 0 : size_t map_count = 0;
1607 0 : size_t hbac_count = 0;
1608 0 : char *default_user = NULL;
1609 0 : char *map_order = NULL;
1610 : errno_t ret;
1611 :
1612 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1613 0 : state = tevent_req_data(req, struct ipa_selinux_handler_state);
1614 :
1615 0 : ret = ipa_get_selinux_recv(subreq, state, &map_count, &maps,
1616 : &hbac_count, &hbac_rules,
1617 : &default_user, &map_order);
1618 0 : talloc_free(subreq);
1619 0 : if (ret != EOK) {
1620 0 : goto done;
1621 : }
1622 :
1623 0 : ret = ipa_selinux_store_config(state->ipa_domain->sysdb, state->ipa_domain,
1624 : default_user, map_order, map_count, maps);
1625 0 : if (ret != EOK) {
1626 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store SELinux config [%d]: %s\n",
1627 : ret, sss_strerror(ret));
1628 0 : goto done;
1629 : }
1630 :
1631 0 : ret = ipa_selinux_create_child_input(state, state->user, state->host,
1632 : maps, map_count, hbac_rules,
1633 : hbac_count, map_order, state->pd,
1634 : state->user_domain, default_user,
1635 : &sci);
1636 0 : if (ret != EOK) {
1637 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create child input [%d]: %s\n",
1638 : ret, sss_strerror(ret));
1639 0 : goto done;
1640 : }
1641 :
1642 : /* Update the SELinux context in a privileged child as the back end is
1643 : * running unprivileged
1644 : */
1645 0 : subreq = selinux_child_send(state, state->ev, sci);
1646 0 : if (subreq == NULL) {
1647 0 : ret = ENOMEM;
1648 0 : goto done;
1649 : }
1650 0 : tevent_req_set_callback(subreq, ipa_selinux_handler_done, req);
1651 0 : return;
1652 :
1653 : done:
1654 : /* TODO For backward compatibility we always return EOK to DP now. */
1655 0 : tevent_req_done(req);
1656 : }
1657 :
1658 0 : static void ipa_selinux_handler_done(struct tevent_req *subreq)
1659 : {
1660 : struct ipa_selinux_handler_state *state;
1661 : struct tevent_req *req;
1662 : errno_t ret;
1663 :
1664 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1665 0 : state = tevent_req_data(req, struct ipa_selinux_handler_state);
1666 :
1667 0 : ret = selinux_child_recv(subreq);
1668 0 : talloc_free(subreq);
1669 0 : if (ret != EOK) {
1670 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1671 0 : goto done;
1672 : }
1673 :
1674 0 : if (!be_is_offline(state->be_ctx)) {
1675 0 : state->selinux_ctx->last_update = time(NULL);
1676 : }
1677 :
1678 0 : state->pd->pam_status = PAM_SUCCESS;
1679 :
1680 : done:
1681 : /* TODO For backward compatibility we always return EOK to DP now. */
1682 0 : tevent_req_done(req);
1683 0 : }
1684 :
1685 : errno_t
1686 0 : ipa_selinux_handler_recv(TALLOC_CTX *mem_ctx,
1687 : struct tevent_req *req,
1688 : struct pam_data **_data)
1689 : {
1690 0 : struct ipa_selinux_handler_state *state = NULL;
1691 :
1692 0 : state = tevent_req_data(req, struct ipa_selinux_handler_state);
1693 :
1694 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1695 :
1696 0 : *_data = talloc_steal(mem_ctx, state->pd);
1697 :
1698 0 : return EOK;
1699 : }
|