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