Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Backend Module -- Access control
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2009 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <sys/param.h>
26 : #include <security/pam_modules.h>
27 :
28 : #include "util/util.h"
29 : #include "providers/ldap/sdap_async.h"
30 : #include "providers/ldap/sdap_access.h"
31 : #include "providers/ipa/ipa_common.h"
32 : #include "providers/ipa/ipa_access.h"
33 : #include "providers/ipa/ipa_hosts.h"
34 : #include "providers/ipa/ipa_hbac_private.h"
35 : #include "providers/ipa/ipa_hbac_rules.h"
36 :
37 : /* External logging function for HBAC. */
38 0 : void hbac_debug_messages(const char *file, int line,
39 : const char *function,
40 : enum hbac_debug_level level,
41 : const char *fmt, ...)
42 : {
43 : int loglevel;
44 :
45 0 : switch(level) {
46 : case HBAC_DBG_FATAL:
47 0 : loglevel = SSSDBG_FATAL_FAILURE;
48 0 : break;
49 : case HBAC_DBG_ERROR:
50 0 : loglevel = SSSDBG_OP_FAILURE;
51 0 : break;
52 : case HBAC_DBG_WARNING:
53 0 : loglevel = SSSDBG_MINOR_FAILURE;
54 0 : break;
55 : case HBAC_DBG_INFO:
56 0 : loglevel = SSSDBG_CONF_SETTINGS;
57 0 : break;
58 : case HBAC_DBG_TRACE:
59 0 : loglevel = SSSDBG_TRACE_INTERNAL;
60 0 : break;
61 : default:
62 0 : loglevel = SSSDBG_UNRESOLVED;
63 0 : break;
64 : }
65 :
66 0 : if (DEBUG_IS_SET(loglevel)) {
67 : va_list ap;
68 :
69 0 : va_start(ap, fmt);
70 0 : sss_vdebug_fn(file, line, function, loglevel, 0, fmt, ap);
71 0 : va_end(ap);
72 : }
73 0 : }
74 :
75 : enum hbac_result {
76 : HBAC_ALLOW = 1,
77 : HBAC_DENY,
78 : HBAC_NOT_APPLICABLE
79 : };
80 :
81 : enum check_result {
82 : RULE_APPLICABLE = 0,
83 : RULE_NOT_APPLICABLE,
84 : RULE_ERROR
85 : };
86 :
87 : struct ipa_fetch_hbac_state {
88 : struct tevent_context *ev;
89 : struct be_ctx *be_ctx;
90 : struct sdap_id_ctx *sdap_ctx;
91 : struct ipa_access_ctx *access_ctx;
92 : struct sdap_id_op *sdap_op;
93 : struct dp_option *ipa_options;
94 : struct time_rules_ctx *tr_ctx;
95 :
96 : struct sdap_search_base **search_bases;
97 :
98 : /* Hosts */
99 : size_t host_count;
100 : struct sysdb_attrs **hosts;
101 : size_t hostgroup_count;
102 : struct sysdb_attrs **hostgroups;
103 : struct sysdb_attrs *ipa_host;
104 :
105 : /* Rules */
106 : size_t rule_count;
107 : struct sysdb_attrs **rules;
108 :
109 : /* Services */
110 : size_t service_count;
111 : struct sysdb_attrs **services;
112 : size_t servicegroup_count;
113 : struct sysdb_attrs **servicegroups;
114 : };
115 :
116 : static errno_t ipa_fetch_hbac_retry(struct tevent_req *req);
117 : static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq);
118 : static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req);
119 : static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq);
120 : static void ipa_fetch_hbac_services_done(struct tevent_req *subreq);
121 : static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq);
122 : static errno_t ipa_purge_hbac(struct sss_domain_info *domain);
123 : static errno_t ipa_save_hbac(struct sss_domain_info *domain,
124 : struct ipa_fetch_hbac_state *state);
125 :
126 : static struct tevent_req *
127 0 : ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx,
128 : struct tevent_context *ev,
129 : struct be_ctx *be_ctx,
130 : struct ipa_access_ctx *access_ctx)
131 : {
132 : struct ipa_fetch_hbac_state *state;
133 : struct tevent_req *req;
134 : time_t now, refresh_interval;
135 : bool offline;
136 : errno_t ret;
137 :
138 0 : req = tevent_req_create(mem_ctx, &state,
139 : struct ipa_fetch_hbac_state);
140 0 : if (req == NULL) {
141 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
142 0 : return NULL;
143 : }
144 :
145 0 : state->ev = ev;
146 0 : state->be_ctx = be_ctx;
147 0 : state->access_ctx = access_ctx;
148 0 : state->sdap_ctx = access_ctx->sdap_ctx;
149 0 : state->ipa_options = access_ctx->ipa_options;
150 0 : state->tr_ctx = access_ctx->tr_ctx;
151 0 : state->search_bases = access_ctx->hbac_search_bases;
152 :
153 0 : if (state->search_bases == NULL) {
154 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC search base found.\n");
155 0 : ret = EINVAL;
156 0 : goto immediately;
157 : }
158 :
159 0 : state->sdap_op = sdap_id_op_create(state, state->sdap_ctx->conn->conn_cache);
160 0 : if (state->sdap_op == NULL) {
161 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
162 0 : ret = ENOMEM;
163 0 : goto immediately;
164 : }
165 :
166 0 : offline = be_is_offline(be_ctx);
167 0 : DEBUG(SSSDBG_TRACE_ALL, "Connection status is [%s].\n",
168 : offline ? "offline" : "online");
169 :
170 0 : refresh_interval = dp_opt_get_int(state->ipa_options, IPA_HBAC_REFRESH);
171 0 : now = time(NULL);
172 :
173 0 : if (offline || now < access_ctx->last_update + refresh_interval) {
174 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing cached HBAC evaluation\n");
175 0 : ret = EOK;
176 0 : goto immediately;
177 : }
178 :
179 0 : ret = ipa_fetch_hbac_retry(req);
180 0 : if (ret != EAGAIN) {
181 0 : goto immediately;
182 : }
183 :
184 0 : return req;
185 :
186 : immediately:
187 0 : if (ret == EOK) {
188 0 : tevent_req_done(req);
189 : } else {
190 0 : tevent_req_error(req, ret);
191 : }
192 0 : tevent_req_post(req, ev);
193 :
194 0 : return req;
195 : }
196 :
197 0 : static errno_t ipa_fetch_hbac_retry(struct tevent_req *req)
198 : {
199 : struct ipa_fetch_hbac_state *state;
200 : struct tevent_req *subreq;
201 : int ret;
202 :
203 0 : state = tevent_req_data(req, struct ipa_fetch_hbac_state);
204 :
205 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
206 0 : if (subreq == NULL) {
207 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
208 : "%d(%s)\n", ret, strerror(ret));
209 0 : return ret;
210 : }
211 :
212 0 : tevent_req_set_callback(subreq, ipa_fetch_hbac_connect_done, req);
213 :
214 0 : return EAGAIN;
215 : }
216 :
217 0 : static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq)
218 : {
219 0 : struct tevent_req *req = NULL;
220 : int dp_error;
221 : errno_t ret;
222 :
223 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
224 :
225 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
226 0 : talloc_zfree(subreq);
227 0 : if (ret != EOK) {
228 0 : goto done;
229 : }
230 :
231 0 : if (dp_error == DP_ERR_OFFLINE) {
232 0 : ret = EOK;
233 0 : goto done;
234 : }
235 :
236 0 : ret = ipa_fetch_hbac_hostinfo(req);
237 0 : if (ret == EAGAIN) {
238 0 : return;
239 : }
240 :
241 : done:
242 0 : if (ret != EOK) {
243 0 : tevent_req_error(req, ret);
244 0 : return;
245 : }
246 :
247 0 : tevent_req_done(req);
248 : }
249 :
250 0 : static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req)
251 : {
252 : struct ipa_fetch_hbac_state *state;
253 : struct tevent_req *subreq;
254 : const char *hostname;
255 : bool srchost;
256 :
257 0 : state = tevent_req_data(req, struct ipa_fetch_hbac_state);
258 :
259 0 : srchost = dp_opt_get_bool(state->ipa_options, IPA_HBAC_SUPPORT_SRCHOST);
260 0 : if (srchost) {
261 : /* Support srchost
262 : * -> we don't want any particular host,
263 : * we want all hosts
264 : */
265 0 : hostname = NULL;
266 :
267 : /* THIS FEATURE IS DEPRECATED */
268 0 : DEBUG(SSSDBG_MINOR_FAILURE, "WARNING: Using deprecated option "
269 : "ipa_hbac_support_srchost.\n");
270 0 : sss_log(SSS_LOG_NOTICE, "WARNING: Using deprecated option "
271 : "ipa_hbac_support_srchost.\n");
272 : } else {
273 0 : hostname = dp_opt_get_string(state->ipa_options, IPA_HOSTNAME);
274 : }
275 :
276 0 : subreq = ipa_host_info_send(state, state->ev,
277 : sdap_id_op_handle(state->sdap_op),
278 0 : state->sdap_ctx->opts, hostname,
279 0 : state->access_ctx->host_map,
280 0 : state->access_ctx->hostgroup_map,
281 0 : state->access_ctx->host_search_bases);
282 0 : if (subreq == NULL) {
283 0 : return ENOMEM;
284 : }
285 :
286 0 : tevent_req_set_callback(subreq, ipa_fetch_hbac_hostinfo_done, req);
287 :
288 0 : return EAGAIN;
289 : }
290 :
291 0 : static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq)
292 : {
293 0 : struct ipa_fetch_hbac_state *state = NULL;
294 0 : struct tevent_req *req = NULL;
295 : errno_t ret;
296 :
297 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
298 0 : state = tevent_req_data(req, struct ipa_fetch_hbac_state);
299 :
300 0 : ret = ipa_host_info_recv(subreq, state,
301 : &state->host_count, &state->hosts,
302 : &state->hostgroup_count, &state->hostgroups);
303 0 : talloc_zfree(subreq);
304 0 : if (ret != EOK) {
305 0 : goto done;
306 : }
307 :
308 0 : subreq = ipa_hbac_service_info_send(state, state->ev,
309 : sdap_id_op_handle(state->sdap_op),
310 0 : state->sdap_ctx->opts,
311 : state->search_bases);
312 0 : if (subreq == NULL) {
313 0 : ret = ENOMEM;
314 0 : goto done;
315 : }
316 :
317 0 : tevent_req_set_callback(subreq, ipa_fetch_hbac_services_done, req);
318 :
319 0 : return;
320 :
321 : done:
322 0 : if (ret != EOK) {
323 0 : tevent_req_error(req, ret);
324 0 : return;
325 : }
326 :
327 0 : tevent_req_done(req);
328 : }
329 :
330 0 : static void ipa_fetch_hbac_services_done(struct tevent_req *subreq)
331 : {
332 : struct ipa_fetch_hbac_state *state;
333 : struct tevent_req *req;
334 : const char *ipa_hostname;
335 : const char *hostname;
336 : errno_t ret;
337 : size_t i;
338 :
339 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
340 0 : state = tevent_req_data(req, struct ipa_fetch_hbac_state);
341 :
342 0 : ret = ipa_hbac_service_info_recv(subreq, state,
343 : &state->service_count, &state->services,
344 : &state->servicegroup_count, &state->servicegroups);
345 0 : talloc_zfree(subreq);
346 0 : if (ret != EOK) {
347 0 : goto done;
348 : }
349 :
350 : /* Get the ipa_host attrs */
351 0 : state->ipa_host = NULL;
352 0 : ipa_hostname = dp_opt_get_cstring(state->ipa_options, IPA_HOSTNAME);
353 0 : if (ipa_hostname == NULL) {
354 0 : DEBUG(SSSDBG_CRIT_FAILURE,
355 : "Missing ipa_hostname, this should never happen.\n");
356 0 : ret = EINVAL;
357 0 : goto done;
358 : }
359 :
360 0 : for (i = 0; i < state->host_count; i++) {
361 0 : ret = sysdb_attrs_get_string(state->hosts[i], SYSDB_FQDN, &hostname);
362 0 : if (ret != EOK) {
363 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
364 0 : goto done;
365 : }
366 :
367 0 : if (strcasecmp(hostname, ipa_hostname) == 0) {
368 0 : state->ipa_host = state->hosts[i];
369 0 : break;
370 : }
371 : }
372 :
373 0 : if (state->ipa_host == NULL) {
374 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
375 0 : ret = EINVAL;
376 0 : goto done;
377 : }
378 :
379 0 : subreq = ipa_hbac_rule_info_send(state, state->ev,
380 : sdap_id_op_handle(state->sdap_op),
381 0 : state->sdap_ctx->opts,
382 : state->search_bases,
383 : state->ipa_host);
384 0 : if (subreq == NULL) {
385 0 : ret = ENOMEM;
386 0 : goto done;
387 : }
388 :
389 0 : tevent_req_set_callback(subreq, ipa_fetch_hbac_rules_done, req);
390 :
391 0 : return;
392 :
393 : done:
394 0 : if (ret != EOK) {
395 0 : tevent_req_error(req, ret);
396 0 : return;
397 : }
398 :
399 0 : tevent_req_done(req);
400 : }
401 :
402 0 : static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq)
403 : {
404 0 : struct ipa_fetch_hbac_state *state = NULL;
405 0 : struct tevent_req *req = NULL;
406 : int dp_error;
407 : errno_t ret;
408 : bool found;
409 :
410 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
411 0 : state = tevent_req_data(req, struct ipa_fetch_hbac_state);
412 :
413 0 : ret = ipa_hbac_rule_info_recv(subreq, state,
414 : &state->rule_count, &state->rules);
415 0 : talloc_zfree(subreq);
416 0 : if (ret == ENOENT) {
417 : /* Set ret to EOK so we can safely call sdap_id_op_done. */
418 0 : found = false;
419 0 : ret = EOK;
420 0 : } else if (ret == EOK) {
421 0 : found = true;
422 : } else {
423 0 : goto done;
424 : }
425 :
426 0 : ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
427 0 : if (dp_error == DP_ERR_OK && ret != EOK) {
428 : /* retry */
429 0 : ret = ipa_fetch_hbac_retry(req);
430 0 : if (ret != EAGAIN) {
431 0 : tevent_req_error(req, ret);
432 : }
433 0 : return;
434 0 : } else if (ret != EOK) {
435 0 : tevent_req_error(req, ret);
436 0 : return;
437 : }
438 :
439 0 : if (found == false) {
440 : /* No rules were found that apply to this host. */
441 0 : ret = ipa_purge_hbac(state->be_ctx->domain);
442 0 : if (ret != EOK) {
443 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove HBAC rules\n");
444 0 : goto done;
445 : }
446 :
447 0 : ret = ENOENT;
448 0 : goto done;
449 : }
450 :
451 0 : ret = ipa_save_hbac(state->be_ctx->domain, state);
452 0 : if (ret != EOK) {
453 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save HBAC rules\n");
454 0 : goto done;
455 : }
456 :
457 0 : ret = EOK;
458 :
459 : done:
460 0 : if (ret != EOK) {
461 0 : tevent_req_error(req, ret);
462 0 : return;
463 : }
464 :
465 0 : tevent_req_done(req);
466 : }
467 :
468 0 : static errno_t ipa_fetch_hbac_recv(struct tevent_req *req)
469 : {
470 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
471 :
472 0 : return EOK;
473 : }
474 :
475 0 : static errno_t ipa_purge_hbac(struct sss_domain_info *domain)
476 : {
477 : TALLOC_CTX *tmp_ctx;
478 : struct ldb_dn *base_dn;
479 : errno_t ret;
480 :
481 0 : tmp_ctx = talloc_new(NULL);
482 0 : if (tmp_ctx == NULL) {
483 0 : return ENOMEM;
484 : }
485 :
486 : /* Delete any rules in the sysdb so offline logins are also denied. */
487 0 : base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, HBAC_RULES_SUBDIR);
488 0 : if (base_dn == NULL) {
489 0 : ret = ENOMEM;
490 0 : goto done;
491 : }
492 :
493 0 : ret = sysdb_delete_recursive(domain->sysdb, base_dn, true);
494 0 : if (ret != EOK) {
495 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n");
496 0 : goto done;
497 : }
498 :
499 0 : ret = EOK;
500 :
501 : done:
502 0 : talloc_free(tmp_ctx);
503 0 : return ret;
504 : }
505 :
506 0 : static errno_t ipa_save_hbac(struct sss_domain_info *domain,
507 : struct ipa_fetch_hbac_state *state)
508 : {
509 0 : bool in_transaction = false;
510 : errno_t ret;
511 : errno_t sret;
512 :
513 0 : ret = sysdb_transaction_start(domain->sysdb);
514 0 : if (ret != EOK) {
515 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not start transaction\n");
516 0 : goto done;
517 : }
518 0 : in_transaction = true;
519 :
520 : /* Save the hosts */
521 0 : ret = ipa_hbac_sysdb_save(domain, HBAC_HOSTS_SUBDIR, SYSDB_FQDN,
522 : state->host_count, state->hosts,
523 : HBAC_HOSTGROUPS_SUBDIR, SYSDB_NAME,
524 : state->hostgroup_count, state->hostgroups);
525 0 : if (ret != EOK) {
526 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts [%d]: %s\n",
527 : ret, sss_strerror(ret));
528 0 : goto done;
529 : }
530 :
531 : /* Save the services */
532 0 : ret = ipa_hbac_sysdb_save(domain, HBAC_SERVICES_SUBDIR, IPA_CN,
533 : state->service_count, state->services,
534 : HBAC_SERVICEGROUPS_SUBDIR, IPA_CN,
535 : state->servicegroup_count,
536 : state->servicegroups);
537 0 : if (ret != EOK) {
538 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services [%d]: %s\n",
539 : ret, sss_strerror(ret));
540 0 : goto done;
541 : }
542 : /* Save the rules */
543 0 : ret = ipa_hbac_sysdb_save(domain, HBAC_RULES_SUBDIR, IPA_UNIQUE_ID,
544 : state->rule_count, state->rules,
545 : NULL, NULL, 0, NULL);
546 0 : if (ret != EOK) {
547 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error saving rules [%d]: %s\n",
548 : ret, sss_strerror(ret));
549 0 : goto done;
550 : }
551 :
552 0 : ret = sysdb_transaction_commit(domain->sysdb);
553 0 : if (ret != EOK) {
554 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
555 0 : goto done;
556 : }
557 0 : in_transaction = false;
558 :
559 0 : state->access_ctx->last_update = time(NULL);
560 :
561 0 : ret = EOK;
562 :
563 : done:
564 0 : if (in_transaction) {
565 0 : sret = sysdb_transaction_cancel(domain->sysdb);
566 0 : if (sret != EOK) {
567 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
568 : }
569 : }
570 :
571 0 : return ret;
572 : }
573 :
574 0 : errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx,
575 : struct dp_option *ipa_options,
576 : struct pam_data *pd)
577 : {
578 : TALLOC_CTX *tmp_ctx;
579 : struct hbac_ctx hbac_ctx;
580 : struct hbac_rule **hbac_rules;
581 : struct hbac_eval_req *eval_req;
582 : enum hbac_eval_result result;
583 0 : struct hbac_info *info = NULL;
584 : errno_t ret;
585 :
586 0 : tmp_ctx = talloc_new(NULL);
587 0 : if (tmp_ctx == NULL) {
588 0 : return ENOMEM;
589 : }
590 :
591 0 : hbac_ctx.be_ctx = be_ctx;
592 0 : hbac_ctx.ipa_options = ipa_options;
593 0 : hbac_ctx.pd = pd;
594 :
595 : /* Get HBAC rules from the sysdb */
596 0 : ret = hbac_get_cached_rules(tmp_ctx, be_ctx->domain,
597 : &hbac_ctx.rule_count, &hbac_ctx.rules);
598 0 : if (ret != EOK) {
599 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve rules from the cache\n");
600 0 : goto done;
601 : }
602 :
603 0 : ret = hbac_ctx_to_rules(tmp_ctx, &hbac_ctx, &hbac_rules, &eval_req);
604 0 : if (ret == EPERM) {
605 0 : DEBUG(SSSDBG_CRIT_FAILURE,
606 : "DENY rules detected. Denying access to all users\n");
607 0 : ret = ERR_ACCESS_DENIED;
608 0 : goto done;
609 0 : } else if (ret != EOK) {
610 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct HBAC rules\n");
611 0 : goto done;
612 : }
613 :
614 0 : hbac_enable_debug(hbac_debug_messages);
615 :
616 0 : result = hbac_evaluate(hbac_rules, eval_req, &info);
617 0 : if (result == HBAC_EVAL_ALLOW) {
618 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Access granted by HBAC rule [%s]\n",
619 : info->rule_name);
620 0 : ret = EOK;
621 0 : goto done;
622 0 : } else if (result == HBAC_EVAL_ERROR) {
623 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error [%s] occurred in rule [%s]\n",
624 : hbac_error_string(info->code), info->rule_name);
625 0 : ret = EIO;
626 0 : goto done;
627 0 : } else if (result == HBAC_EVAL_OOM) {
628 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Insufficient memory\n");
629 0 : ret = ENOMEM;
630 0 : goto done;
631 : }
632 :
633 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Access denied by HBAC rules\n");
634 0 : ret = ERR_ACCESS_DENIED;
635 :
636 : done:
637 0 : hbac_free_info(info);
638 0 : talloc_free(tmp_ctx);
639 0 : return ret;
640 : }
641 :
642 0 : errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
643 : struct sss_domain_info *domain,
644 : size_t *_rule_count,
645 : struct sysdb_attrs ***_rules)
646 : {
647 : errno_t ret;
648 : struct ldb_message **msgs;
649 : struct sysdb_attrs **rules;
650 : size_t rule_count;
651 : TALLOC_CTX *tmp_ctx;
652 : char *filter;
653 0 : const char *attrs[] = { OBJECTCLASS,
654 : IPA_CN,
655 : SYSDB_ORIG_DN,
656 : IPA_UNIQUE_ID,
657 : IPA_ENABLED_FLAG,
658 : IPA_ACCESS_RULE_TYPE,
659 : IPA_MEMBER_USER,
660 : IPA_USER_CATEGORY,
661 : IPA_MEMBER_SERVICE,
662 : IPA_SERVICE_CATEGORY,
663 : IPA_SOURCE_HOST,
664 : IPA_SOURCE_HOST_CATEGORY,
665 : IPA_EXTERNAL_HOST,
666 : IPA_MEMBER_HOST,
667 : IPA_HOST_CATEGORY,
668 : NULL };
669 :
670 0 : tmp_ctx = talloc_new(NULL);
671 0 : if (tmp_ctx == NULL) return ENOMEM;
672 :
673 0 : filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
674 0 : if (filter == NULL) {
675 0 : ret = ENOMEM;
676 0 : goto done;
677 : }
678 :
679 0 : ret = sysdb_search_custom(tmp_ctx, domain, filter,
680 : HBAC_RULES_SUBDIR, attrs,
681 : &rule_count, &msgs);
682 0 : if (ret != EOK && ret != ENOENT) {
683 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n");
684 0 : goto done;
685 0 : } if (ret == ENOENT) {
686 0 : rule_count = 0;
687 : }
688 :
689 0 : ret = sysdb_msg2attrs(tmp_ctx, rule_count, msgs, &rules);
690 0 : if (ret != EOK) {
691 0 : DEBUG(SSSDBG_CRIT_FAILURE,
692 : "Could not convert ldb message to sysdb_attrs\n");
693 0 : goto done;
694 : }
695 :
696 0 : if (_rules) *_rules = talloc_steal(mem_ctx, rules);
697 0 : if (_rule_count) *_rule_count = rule_count;
698 :
699 0 : ret = EOK;
700 : done:
701 0 : talloc_free(tmp_ctx);
702 0 : return ret;
703 : }
704 :
705 : struct ipa_pam_access_handler_state {
706 : struct tevent_context *ev;
707 : struct be_ctx *be_ctx;
708 : struct ipa_access_ctx *access_ctx;
709 : struct pam_data *pd;
710 : };
711 :
712 : static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq);
713 : static void ipa_pam_access_handler_done(struct tevent_req *subreq);
714 :
715 : struct tevent_req *
716 0 : ipa_pam_access_handler_send(TALLOC_CTX *mem_ctx,
717 : struct ipa_access_ctx *access_ctx,
718 : struct pam_data *pd,
719 : struct dp_req_params *params)
720 : {
721 : struct ipa_pam_access_handler_state *state;
722 : struct tevent_req *subreq;
723 : struct tevent_req *req;
724 :
725 0 : req = tevent_req_create(mem_ctx, &state,
726 : struct ipa_pam_access_handler_state);
727 0 : if (req == NULL) {
728 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
729 0 : return NULL;
730 : }
731 :
732 0 : state->pd = pd;
733 0 : state->ev = params->ev;
734 0 : state->be_ctx = params->be_ctx;
735 0 : state->access_ctx = access_ctx;
736 :
737 0 : subreq = sdap_access_send(state, params->ev, params->be_ctx,
738 : params->domain, access_ctx->sdap_access_ctx,
739 0 : access_ctx->sdap_ctx->conn, pd);
740 0 : if (subreq == NULL) {
741 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
742 0 : goto immediately;
743 : }
744 :
745 0 : tevent_req_set_callback(subreq, ipa_pam_access_handler_sdap_done, req);
746 :
747 0 : return req;
748 :
749 : immediately:
750 : /* TODO For backward compatibility we always return EOK to DP now. */
751 0 : tevent_req_done(req);
752 0 : tevent_req_post(req, params->ev);
753 :
754 0 : return req;
755 : }
756 :
757 0 : static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq)
758 : {
759 : struct ipa_pam_access_handler_state *state;
760 : struct tevent_req *req;
761 : errno_t ret;
762 :
763 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
764 0 : state = tevent_req_data(req, struct ipa_pam_access_handler_state);
765 :
766 0 : ret = sdap_access_recv(subreq);
767 0 : talloc_free(subreq);
768 0 : switch (ret) {
769 : case EOK:
770 : /* Account wasn't locked. Continue below to HBAC processing. */
771 0 : break;
772 : case ERR_ACCESS_DENIED:
773 : /* Account was locked. Return permission denied here. */
774 0 : state->pd->pam_status = PAM_PERM_DENIED;
775 0 : goto done;
776 : case ERR_ACCOUNT_EXPIRED:
777 0 : state->pd->pam_status = PAM_ACCT_EXPIRED;
778 0 : goto done;
779 : default:
780 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result "
781 : "[%d]: %s.\n", ret, sss_strerror(ret));
782 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
783 0 : break;
784 : }
785 :
786 0 : subreq = ipa_fetch_hbac_send(state, state->ev, state->be_ctx,
787 : state->access_ctx);
788 0 : if (subreq == NULL) {
789 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
790 0 : goto done;
791 : }
792 :
793 0 : tevent_req_set_callback(subreq, ipa_pam_access_handler_done, req);
794 :
795 0 : return;
796 :
797 : done:
798 : /* TODO For backward compatibility we always return EOK to DP now. */
799 0 : tevent_req_done(req);
800 : }
801 :
802 0 : static void ipa_pam_access_handler_done(struct tevent_req *subreq)
803 : {
804 : struct ipa_pam_access_handler_state *state;
805 : struct tevent_req *req;
806 : errno_t ret;
807 :
808 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
809 0 : state = tevent_req_data(req, struct ipa_pam_access_handler_state);
810 :
811 0 : ret = ipa_fetch_hbac_recv(subreq);
812 0 : talloc_free(subreq);
813 :
814 0 : if (ret == ENOENT) {
815 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC rules find, denying access\n");
816 0 : state->pd->pam_status = PAM_PERM_DENIED;
817 0 : goto done;
818 0 : } else if (ret != EOK) {
819 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to fetch HBAC rules [%d]: %s\n",
820 : ret, sss_strerror(ret));
821 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
822 0 : goto done;
823 : }
824 :
825 0 : ret = ipa_hbac_evaluate_rules(state->be_ctx,
826 0 : state->access_ctx->ipa_options, state->pd);
827 0 : if (ret == EOK) {
828 0 : state->pd->pam_status = PAM_SUCCESS;
829 0 : } else if (ret == ERR_ACCESS_DENIED) {
830 0 : state->pd->pam_status = PAM_PERM_DENIED;
831 : } else {
832 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
833 : }
834 :
835 : done:
836 : /* TODO For backward compatibility we always return EOK to DP now. */
837 0 : tevent_req_done(req);
838 0 : }
839 :
840 : errno_t
841 0 : ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
842 : struct tevent_req *req,
843 : struct pam_data **_data)
844 : {
845 0 : struct ipa_pam_access_handler_state *state = NULL;
846 :
847 0 : state = tevent_req_data(req, struct ipa_pam_access_handler_state);
848 :
849 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
850 :
851 0 : *_data = talloc_steal(mem_ctx, state->pd);
852 :
853 0 : return EOK;
854 : }
|