LCOV - code coverage report
Current view: top level - providers/ipa - ipa_access.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 344 0.0 %
Date: 2015-10-19 Functions: 0 15 0.0 %

          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_hbac.h"
      34             : #include "providers/ipa/ipa_hosts.h"
      35             : #include "providers/ipa/ipa_hbac_private.h"
      36             : #include "providers/ipa/ipa_hbac_rules.h"
      37             : 
      38             : /* External logging function for HBAC. */
      39           0 : void hbac_debug_messages(const char *file, int line,
      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           0 :         char *message = NULL;
      69             :         int ret;
      70             : 
      71           0 :         va_start(ap, fmt);
      72           0 :         ret = vasprintf(&message, fmt, ap);
      73           0 :         va_end(ap);
      74           0 :         if (ret < 0) {
      75             :             /* ENOMEM */
      76           0 :             free(message);
      77           0 :             return;
      78             :         }
      79             : 
      80           0 :         debug_fn(__FILE__, __LINE__, "hbac", loglevel, "[%s:%i] %s",
      81             :                  file, line, message);
      82           0 :         free(message);
      83             :     }
      84             : }
      85             : 
      86           0 : static void ipa_access_reply(struct hbac_ctx *hbac_ctx, int pam_status)
      87             : {
      88           0 :     struct be_req *be_req = hbac_ctx->be_req;
      89             :     struct pam_data *pd;
      90           0 :     pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
      91           0 :     pd->pam_status = pam_status;
      92             : 
      93             :     /* destroy HBAC context now to release all used resources and LDAP connection */
      94           0 :     talloc_zfree(hbac_ctx);
      95             : 
      96           0 :     if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {
      97           0 :         be_req_terminate(be_req, DP_ERR_OK, pam_status, NULL);
      98             :     } else {
      99           0 :         be_req_terminate(be_req, DP_ERR_FATAL, pam_status, NULL);
     100             :     }
     101           0 : }
     102             : 
     103             : enum hbac_result {
     104             :     HBAC_ALLOW = 1,
     105             :     HBAC_DENY,
     106             :     HBAC_NOT_APPLICABLE
     107             : };
     108             : 
     109             : enum check_result {
     110             :     RULE_APPLICABLE = 0,
     111             :     RULE_NOT_APPLICABLE,
     112             :     RULE_ERROR
     113             : };
     114             : 
     115             : static void ipa_hbac_check(struct tevent_req *req);
     116             : static int hbac_retry(struct hbac_ctx *hbac_ctx);
     117             : static void hbac_connect_done(struct tevent_req *subreq);
     118             : static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret);
     119             : 
     120             : static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx);
     121             : 
     122             : static void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx);
     123             : 
     124           0 : void ipa_access_handler(struct be_req *be_req)
     125             : {
     126             :     struct pam_data *pd;
     127             :     struct ipa_access_ctx *ipa_access_ctx;
     128             :     struct tevent_req *req;
     129             :     struct sss_domain_info *dom;
     130           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
     131             : 
     132           0 :     pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
     133             : 
     134           0 :     ipa_access_ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
     135             :                                      struct ipa_access_ctx);
     136             : 
     137           0 :     dom = be_ctx->domain;
     138           0 :     if (strcasecmp(pd->domain, be_ctx->domain->name) != 0) {
     139             :         /* Subdomain request, verify subdomain */
     140           0 :         dom = find_domain_by_name(be_ctx->domain, pd->domain, true);
     141             :     }
     142             : 
     143             :     /* First, verify that this account isn't locked.
     144             :      * We need to do this in case the auth phase was
     145             :      * skipped (such as during GSSAPI single-sign-on
     146             :      * or SSH public key exchange.
     147             :      */
     148           0 :     req = sdap_access_send(be_req, be_ctx->ev, be_ctx, dom,
     149             :                            ipa_access_ctx->sdap_access_ctx,
     150           0 :                            ipa_access_ctx->sdap_access_ctx->id_ctx->conn,
     151             :                            pd);
     152           0 :     if (!req) {
     153           0 :         be_req_terminate(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
     154           0 :         return;
     155             :     }
     156           0 :     tevent_req_set_callback(req, ipa_hbac_check, be_req);
     157             : }
     158             : 
     159           0 : static void ipa_hbac_check(struct tevent_req *req)
     160             : {
     161             :     struct be_req *be_req;
     162             :     struct be_ctx *be_ctx;
     163             :     struct pam_data *pd;
     164           0 :     struct hbac_ctx *hbac_ctx = NULL;
     165             :     struct ipa_access_ctx *ipa_access_ctx;
     166             :     int ret;
     167             : 
     168           0 :     be_req = tevent_req_callback_data(req, struct be_req);
     169           0 :     be_ctx = be_req_get_be_ctx(be_req);
     170           0 :     pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
     171             : 
     172           0 :     ret = sdap_access_recv(req);
     173           0 :     talloc_zfree(req);
     174             : 
     175           0 :     switch(ret) {
     176             :     case EOK:
     177             :         /* Account wasn't locked. Continue below
     178             :          * to HBAC processing.
     179             :          */
     180           0 :         break;
     181             :     case ERR_ACCESS_DENIED:
     182             :         /* Account was locked. Return permission denied
     183             :          * here.
     184             :          */
     185           0 :         pd->pam_status = PAM_PERM_DENIED;
     186           0 :         be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
     187           0 :         return;
     188             :     case ERR_ACCOUNT_EXPIRED:
     189           0 :         pd->pam_status = PAM_ACCT_EXPIRED;
     190           0 :         be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
     191           0 :         return;
     192             :     default:
     193             :         /* We got an unexpected error. Return it as-is */
     194           0 :         pd->pam_status = PAM_SYSTEM_ERR;
     195           0 :         be_req_terminate(be_req, DP_ERR_FATAL, pd->pam_status,
     196             :                          sss_strerror(ret));
     197           0 :         return;
     198             :     }
     199             : 
     200           0 :     hbac_ctx = talloc_zero(be_req, struct hbac_ctx);
     201           0 :     if (hbac_ctx == NULL) {
     202           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     203           0 :         ret = ENOMEM;
     204           0 :         goto fail;
     205             :     }
     206             : 
     207           0 :     hbac_ctx->be_req = be_req;
     208           0 :     hbac_ctx->pd = pd;
     209           0 :     ipa_access_ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
     210             :                                      struct ipa_access_ctx);
     211           0 :     hbac_ctx->access_ctx = ipa_access_ctx;
     212           0 :     hbac_ctx->sdap_ctx = ipa_access_ctx->sdap_ctx;
     213           0 :     hbac_ctx->ipa_options = ipa_access_ctx->ipa_options;
     214           0 :     hbac_ctx->tr_ctx = ipa_access_ctx->tr_ctx;
     215           0 :     hbac_ctx->search_bases = ipa_access_ctx->hbac_search_bases;
     216           0 :     if (hbac_ctx->search_bases == NULL) {
     217           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC search base found.\n");
     218           0 :         ret = EINVAL;
     219           0 :         goto fail;
     220             :     }
     221             : 
     222           0 :     ret = hbac_retry(hbac_ctx);
     223           0 :     if (ret != EOK) {
     224           0 :         goto fail;
     225             :     }
     226             : 
     227           0 :     return;
     228             : 
     229             : fail:
     230           0 :     if (hbac_ctx) {
     231             :         /* Return an proper error */
     232           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     233             :     } else {
     234           0 :         be_req_terminate(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
     235             :     }
     236             : }
     237             : 
     238           0 : static int hbac_retry(struct hbac_ctx *hbac_ctx)
     239             : {
     240             :     struct tevent_req *subreq;
     241             :     int ret;
     242             :     bool offline;
     243             :     time_t now, refresh_interval;
     244           0 :     struct ipa_access_ctx *access_ctx = hbac_ctx->access_ctx;
     245           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     246             : 
     247           0 :     offline = be_is_offline(be_ctx);
     248           0 :     DEBUG(SSSDBG_TRACE_ALL,
     249             :           "Connection status is [%s].\n", offline ? "offline" : "online");
     250             : 
     251           0 :     refresh_interval = dp_opt_get_int(hbac_ctx->ipa_options,
     252             :                                       IPA_HBAC_REFRESH);
     253             : 
     254           0 :     now = time(NULL);
     255           0 :     if (now < access_ctx->last_update + refresh_interval) {
     256             :         /* Simulate offline mode and just go to the cache */
     257           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Performing cached HBAC evaluation\n");
     258           0 :         offline = true;
     259             :     }
     260             : 
     261           0 :     if (!offline) {
     262           0 :         if (hbac_ctx->sdap_op == NULL) {
     263           0 :             hbac_ctx->sdap_op = sdap_id_op_create(hbac_ctx,
     264           0 :                                           hbac_ctx->sdap_ctx->conn->conn_cache);
     265           0 :             if (hbac_ctx->sdap_op == NULL) {
     266           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_create failed.\n");
     267           0 :                 return EIO;
     268             :             }
     269             :         }
     270             : 
     271           0 :         subreq = sdap_id_op_connect_send(hbac_ctx->sdap_op, hbac_ctx, &ret);
     272           0 :         if (!subreq) {
     273           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     274             :                   "sdap_id_op_connect_send failed: %d(%s).\n", ret, strerror(ret));
     275           0 :             talloc_zfree(hbac_ctx->sdap_op);
     276           0 :             return ret;
     277             :         }
     278             : 
     279           0 :         tevent_req_set_callback(subreq, hbac_connect_done, hbac_ctx);
     280             :     } else {
     281             :         /* Evaluate the rules based on what we have in the
     282             :          * sysdb
     283             :          */
     284           0 :         ipa_hbac_evaluate_rules(hbac_ctx);
     285           0 :         return EOK;
     286             :     }
     287           0 :     return EOK;
     288             : }
     289             : 
     290           0 : static void hbac_connect_done(struct tevent_req *subreq)
     291             : {
     292           0 :     struct hbac_ctx *hbac_ctx = tevent_req_callback_data(subreq, struct hbac_ctx);
     293             :     int ret, dp_error;
     294             : 
     295           0 :     ret = sdap_id_op_connect_recv(subreq, &dp_error);
     296           0 :     talloc_zfree(subreq);
     297             : 
     298           0 :     if (dp_error == DP_ERR_OFFLINE) {
     299             :         /* switching to offline mode */
     300           0 :         talloc_zfree(hbac_ctx->sdap_op);
     301             : 
     302           0 :         ipa_hbac_evaluate_rules(hbac_ctx);
     303           0 :         return;
     304           0 :     } else if (ret != EOK) {
     305           0 :         goto fail;
     306             :     }
     307             : 
     308           0 :     ret = hbac_get_host_info_step(hbac_ctx);
     309           0 :     if (ret != EOK) {
     310           0 :         goto fail;
     311             :     }
     312             : 
     313           0 :     return;
     314             : 
     315             : fail:
     316           0 :     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     317             : }
     318             : 
     319           0 : static void hbac_clear_rule_data(struct hbac_ctx *hbac_ctx)
     320             : {
     321           0 :     hbac_ctx->host_count = 0;
     322           0 :     talloc_zfree(hbac_ctx->hosts);
     323             : 
     324           0 :     hbac_ctx->hostgroup_count = 0;
     325           0 :     talloc_zfree(hbac_ctx->hostgroups);
     326             : 
     327           0 :     hbac_ctx->service_count = 0;
     328           0 :     talloc_zfree(hbac_ctx->services);
     329             : 
     330           0 :     hbac_ctx->servicegroup_count = 0;
     331           0 :     talloc_zfree(hbac_ctx->servicegroups);
     332             : 
     333           0 :     hbac_ctx->rule_count = 0;
     334           0 :     talloc_zfree(hbac_ctx->rules);
     335           0 : }
     336             : 
     337             : /* Check whether the current HBAC request is processed in off-line mode */
     338           0 : static inline bool hbac_ctx_is_offline(struct hbac_ctx *ctx)
     339             : {
     340           0 :     return ctx == NULL || ctx->sdap_op == NULL;
     341             : }
     342             : 
     343             : /* Check the step result code and continue, retry, get offline result or abort accordingly */
     344           0 : static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret)
     345             : {
     346             :     int dp_error;
     347             : 
     348           0 :     if (ret == EOK) {
     349           0 :         return true;
     350             :     }
     351             : 
     352           0 :     if (hbac_ctx_is_offline(hbac_ctx)) {
     353             :         /* already offline => the error is fatal */
     354           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     355           0 :         return false;
     356             :     }
     357             : 
     358           0 :     ret = sdap_id_op_done(hbac_ctx->sdap_op, ret, &dp_error);
     359           0 :     if (ret != EOK) {
     360           0 :         if (dp_error == DP_ERR_OFFLINE) {
     361             :             /* switching to offline mode */
     362           0 :             talloc_zfree(hbac_ctx->sdap_op);
     363             : 
     364             :             /* Free any of the results we've gotten */
     365           0 :             hbac_clear_rule_data(hbac_ctx);
     366             : 
     367           0 :             dp_error = DP_ERR_OK;
     368             :         }
     369             : 
     370           0 :         if (dp_error == DP_ERR_OK) {
     371             :             /* retry */
     372           0 :             ret = hbac_retry(hbac_ctx);
     373           0 :             if (ret == EOK) {
     374           0 :                 return false;
     375             :             }
     376             :         }
     377             :     }
     378             : 
     379           0 :     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     380           0 :     return false;
     381             : }
     382             : 
     383             : static void hbac_get_service_info_step(struct tevent_req *req);
     384             : static void hbac_get_rule_info_step(struct tevent_req *req);
     385             : static void hbac_sysdb_save (struct tevent_req *req);
     386             : 
     387           0 : static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
     388             : {
     389           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     390             :     const char *hostname;
     391             :     struct tevent_req *req;
     392             : 
     393           0 :     if (dp_opt_get_bool(hbac_ctx->ipa_options, IPA_HBAC_SUPPORT_SRCHOST)) {
     394             :         /* Support srchost
     395             :          * -> we don't want any particular host,
     396             :          *    we want all hosts
     397             :          */
     398           0 :         hostname = NULL;
     399             : 
     400             :         /* THIS FEATURE IS DEPRECATED */
     401           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "WARNING: Using deprecated option "
     402             :                     "ipa_hbac_support_srchost.\n");
     403           0 :         sss_log(SSS_LOG_NOTICE, "WARNING: Using deprecated option "
     404             :                     "ipa_hbac_support_srchost.\n");
     405             :     } else {
     406           0 :         hostname = dp_opt_get_string(hbac_ctx->ipa_options, IPA_HOSTNAME);
     407             :     }
     408             : 
     409           0 :     req = ipa_host_info_send(hbac_ctx, be_ctx->ev,
     410             :                              sdap_id_op_handle(hbac_ctx->sdap_op),
     411           0 :                              hbac_ctx->sdap_ctx->opts,
     412             :                              hostname,
     413           0 :                              hbac_ctx->access_ctx->host_map,
     414           0 :                              hbac_ctx->access_ctx->hostgroup_map,
     415           0 :                              hbac_ctx->access_ctx->host_search_bases);
     416           0 :     if (req == NULL) {
     417           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not get host info\n");
     418           0 :         return ENOMEM;
     419             :     }
     420           0 :     tevent_req_set_callback(req, hbac_get_service_info_step, hbac_ctx);
     421             : 
     422           0 :     return EOK;
     423             : }
     424             : 
     425           0 : static void hbac_get_service_info_step(struct tevent_req *req)
     426             : {
     427             :     errno_t ret;
     428           0 :     struct hbac_ctx *hbac_ctx =
     429           0 :             tevent_req_callback_data(req, struct hbac_ctx);
     430           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     431             : 
     432           0 :     ret = ipa_host_info_recv(req, hbac_ctx,
     433             :                              &hbac_ctx->host_count,
     434             :                              &hbac_ctx->hosts,
     435             :                              &hbac_ctx->hostgroup_count,
     436             :                              &hbac_ctx->hostgroups);
     437           0 :     talloc_zfree(req);
     438           0 :     if (!hbac_check_step_result(hbac_ctx, ret)) {
     439           0 :         return;
     440             :     }
     441             : 
     442             :     /* Get services and service groups */
     443           0 :     req = ipa_hbac_service_info_send(hbac_ctx, be_ctx->ev,
     444             :                                     sdap_id_op_handle(hbac_ctx->sdap_op),
     445           0 :                                      hbac_ctx->sdap_ctx->opts,
     446             :                                     hbac_ctx->search_bases);
     447           0 :     if (req == NULL) {
     448           0 :         DEBUG(SSSDBG_CRIT_FAILURE,"Could not get service info\n");
     449           0 :         goto fail;
     450             :     }
     451           0 :     tevent_req_set_callback(req, hbac_get_rule_info_step, hbac_ctx);
     452           0 :     return;
     453             : 
     454             : fail:
     455           0 :     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     456             : }
     457             : 
     458           0 : static void hbac_get_rule_info_step(struct tevent_req *req)
     459             : {
     460             :     errno_t ret;
     461             :     size_t i;
     462             :     const char *ipa_hostname;
     463             :     const char *hostname;
     464           0 :     struct hbac_ctx *hbac_ctx =
     465           0 :             tevent_req_callback_data(req, struct hbac_ctx);
     466           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     467             : 
     468           0 :     ret = ipa_hbac_service_info_recv(req, hbac_ctx,
     469             :                                      &hbac_ctx->service_count,
     470             :                                      &hbac_ctx->services,
     471             :                                      &hbac_ctx->servicegroup_count,
     472             :                                      &hbac_ctx->servicegroups);
     473           0 :     talloc_zfree(req);
     474           0 :     if (!hbac_check_step_result(hbac_ctx, ret)) {
     475           0 :         return;
     476             :     }
     477             : 
     478             :     /* Get the ipa_host attrs */
     479           0 :     hbac_ctx->ipa_host = NULL;
     480           0 :     ipa_hostname = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME);
     481           0 :     if (ipa_hostname == NULL) {
     482           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     483             :               "Missing ipa_hostname, this should never happen.\n");
     484           0 :         goto fail;
     485             :     }
     486             : 
     487           0 :     for (i = 0; i < hbac_ctx->host_count; i++) {
     488           0 :         ret = sysdb_attrs_get_string(hbac_ctx->hosts[i],
     489             :                                      SYSDB_FQDN,
     490             :                                      &hostname);
     491           0 :         if (ret != EOK) {
     492           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
     493           0 :             goto fail;
     494             :         }
     495             : 
     496           0 :         if (strcasecmp(hostname, ipa_hostname) == 0) {
     497           0 :             hbac_ctx->ipa_host = hbac_ctx->hosts[i];
     498           0 :             break;
     499             :         }
     500             :     }
     501           0 :     if (hbac_ctx->ipa_host == NULL) {
     502           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
     503           0 :         goto fail;
     504             :     }
     505             : 
     506             : 
     507             :     /* Get the list of applicable rules */
     508           0 :     req = ipa_hbac_rule_info_send(hbac_ctx,
     509             :                                   be_ctx->ev,
     510             :                                   sdap_id_op_handle(hbac_ctx->sdap_op),
     511           0 :                                   hbac_ctx->sdap_ctx->opts,
     512             :                                   hbac_ctx->search_bases,
     513             :                                   hbac_ctx->ipa_host);
     514           0 :     if (req == NULL) {
     515           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not get rules\n");
     516           0 :         goto fail;
     517             :     }
     518             : 
     519           0 :     tevent_req_set_callback(req, hbac_sysdb_save, hbac_ctx);
     520           0 :     return;
     521             : 
     522             : fail:
     523           0 :     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     524             : }
     525             : 
     526           0 : static void hbac_sysdb_save(struct tevent_req *req)
     527             : {
     528             :     errno_t ret;
     529           0 :     bool in_transaction = false;
     530           0 :     struct hbac_ctx *hbac_ctx =
     531           0 :             tevent_req_callback_data(req, struct hbac_ctx);
     532           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     533           0 :     struct sss_domain_info *domain = be_ctx->domain;
     534             :     struct ldb_dn *base_dn;
     535           0 :     struct ipa_access_ctx *access_ctx =
     536           0 :             talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
     537             :                             struct ipa_access_ctx);
     538             :     TALLOC_CTX *tmp_ctx;
     539             : 
     540           0 :     ret = ipa_hbac_rule_info_recv(req, hbac_ctx,
     541             :                                   &hbac_ctx->rule_count,
     542             :                                   &hbac_ctx->rules);
     543           0 :     talloc_zfree(req);
     544           0 :     if (ret == ENOENT) {
     545             :         /* No rules were found that apply to this
     546             :          * host.
     547             :          */
     548             : 
     549           0 :         tmp_ctx = talloc_new(NULL);
     550           0 :         if (tmp_ctx == NULL) {
     551           0 :             ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     552           0 :             return;
     553             :         }
     554             :         /* Delete any rules in the sysdb so offline logins
     555             :          * are also denied.
     556             :          */
     557           0 :         base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, HBAC_RULES_SUBDIR);
     558           0 :         if (base_dn == NULL) {
     559           0 :             talloc_free(tmp_ctx);
     560           0 :             ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     561           0 :             return;
     562             :         }
     563             : 
     564           0 :         ret = sysdb_delete_recursive(domain->sysdb, base_dn, true);
     565           0 :         talloc_free(tmp_ctx);
     566           0 :         if (ret != EOK) {
     567           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n");
     568           0 :             ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     569           0 :             return;
     570             :         }
     571             : 
     572             :         /* If no rules are found, we default to DENY */
     573           0 :         ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
     574           0 :         return;
     575             :     }
     576             : 
     577           0 :     if (!hbac_check_step_result(hbac_ctx, ret)) {
     578           0 :         return;
     579             :     }
     580             : 
     581           0 :     ret = sysdb_transaction_start(domain->sysdb);
     582           0 :     if (ret != EOK) {
     583           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Could not start transaction\n");
     584           0 :         goto fail;
     585             :     }
     586           0 :     in_transaction = true;
     587             : 
     588             :     /* Save the hosts */
     589           0 :     ret = ipa_hbac_sysdb_save(domain,
     590             :                               HBAC_HOSTS_SUBDIR, SYSDB_FQDN,
     591             :                               hbac_ctx->host_count, hbac_ctx->hosts,
     592             :                               HBAC_HOSTGROUPS_SUBDIR, SYSDB_NAME,
     593             :                               hbac_ctx->hostgroup_count,
     594             :                               hbac_ctx->hostgroups);
     595           0 :     if (ret != EOK) {
     596           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts: [%d][%s]\n",
     597             :                   ret, strerror(ret));
     598           0 :         goto fail;
     599             :     }
     600             : 
     601             :     /* Save the services */
     602           0 :     ret = ipa_hbac_sysdb_save(domain,
     603             :                               HBAC_SERVICES_SUBDIR, IPA_CN,
     604             :                               hbac_ctx->service_count, hbac_ctx->services,
     605             :                               HBAC_SERVICEGROUPS_SUBDIR, IPA_CN,
     606             :                               hbac_ctx->servicegroup_count,
     607             :                               hbac_ctx->servicegroups);
     608           0 :     if (ret != EOK) {
     609           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services:  [%d][%s]\n",
     610             :                   ret, strerror(ret));
     611           0 :         goto fail;
     612             :     }
     613             :     /* Save the rules */
     614           0 :     ret = ipa_hbac_sysdb_save(domain,
     615             :                               HBAC_RULES_SUBDIR, IPA_UNIQUE_ID,
     616             :                               hbac_ctx->rule_count,
     617             :                               hbac_ctx->rules,
     618             :                               NULL, NULL, 0, NULL);
     619           0 :     if (ret != EOK) {
     620           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error saving rules:  [%d][%s]\n",
     621             :                   ret, strerror(ret));
     622           0 :         goto fail;
     623             :     }
     624             : 
     625           0 :     ret = sysdb_transaction_commit(domain->sysdb);
     626           0 :     if (ret != EOK) {
     627           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
     628           0 :         goto fail;
     629             :     }
     630           0 :     in_transaction = false;
     631             : 
     632             :     /* We don't need the rule data any longer,
     633             :      * the rest of the processing relies on
     634             :      * sysdb lookups.
     635             :      */
     636           0 :     hbac_clear_rule_data(hbac_ctx);
     637             : 
     638             : 
     639           0 :     access_ctx->last_update = time(NULL);
     640             : 
     641             :     /* Now evaluate the request against the rules */
     642           0 :     ipa_hbac_evaluate_rules(hbac_ctx);
     643             : 
     644           0 :     return;
     645             : 
     646             : fail:
     647           0 :     if (in_transaction) {
     648           0 :         ret = sysdb_transaction_cancel(domain->sysdb);
     649           0 :         if (ret != EOK) {
     650           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel transaction\n");
     651             :         }
     652             :     }
     653           0 :     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     654             : }
     655             : 
     656           0 : void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx)
     657             : {
     658           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
     659             :     errno_t ret;
     660             :     struct hbac_rule **hbac_rules;
     661             :     struct hbac_eval_req *eval_req;
     662             :     enum hbac_eval_result result;
     663             :     struct hbac_info *info;
     664             : 
     665             :     /* Get HBAC rules from the sysdb */
     666           0 :     ret = hbac_get_cached_rules(hbac_ctx, be_ctx->domain,
     667             :                                 &hbac_ctx->rule_count, &hbac_ctx->rules);
     668           0 :     if (ret != EOK) {
     669           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve rules from the cache\n");
     670           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     671             :     }
     672             : 
     673           0 :     ret = hbac_ctx_to_rules(hbac_ctx, hbac_ctx,
     674             :                             &hbac_rules, &eval_req);
     675           0 :     if (ret == EPERM) {
     676           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     677             :               "DENY rules detected. Denying access to all users\n");
     678           0 :         ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
     679           0 :         return;
     680           0 :     } else if (ret != EOK) {
     681           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct HBAC rules\n");
     682           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     683           0 :         return;
     684             :     }
     685             : 
     686           0 :     hbac_enable_debug(hbac_debug_messages);
     687             : 
     688           0 :     result = hbac_evaluate(hbac_rules, eval_req, &info);
     689           0 :     if (result == HBAC_EVAL_ALLOW) {
     690           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Access granted by HBAC rule [%s]\n",
     691             :                   info->rule_name);
     692           0 :         hbac_free_info(info);
     693           0 :         ipa_access_reply(hbac_ctx, PAM_SUCCESS);
     694           0 :         return;
     695           0 :     } else if (result == HBAC_EVAL_ERROR) {
     696           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error [%s] occurred in rule [%s]\n",
     697             :                   hbac_error_string(info->code),
     698             :                   info->rule_name);
     699           0 :         hbac_free_info(info);
     700           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     701           0 :         return;
     702           0 :     } else if (result == HBAC_EVAL_OOM) {
     703           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Insufficient memory\n");
     704           0 :         ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     705           0 :         return;
     706             :     }
     707             : 
     708           0 :     DEBUG(SSSDBG_MINOR_FAILURE, "Access denied by HBAC rules\n");
     709           0 :     hbac_free_info(info);
     710           0 :     ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
     711             : }
     712             : 
     713           0 : errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
     714             :                               struct sss_domain_info *domain,
     715             :                               size_t *_rule_count,
     716             :                               struct sysdb_attrs ***_rules)
     717             : {
     718             :     errno_t ret;
     719             :     struct ldb_message **msgs;
     720             :     struct sysdb_attrs **rules;
     721             :     size_t rule_count;
     722             :     TALLOC_CTX *tmp_ctx;
     723             :     char *filter;
     724           0 :     const char *attrs[] = { OBJECTCLASS,
     725             :                             IPA_CN,
     726             :                             SYSDB_ORIG_DN,
     727             :                             IPA_UNIQUE_ID,
     728             :                             IPA_ENABLED_FLAG,
     729             :                             IPA_ACCESS_RULE_TYPE,
     730             :                             IPA_MEMBER_USER,
     731             :                             IPA_USER_CATEGORY,
     732             :                             IPA_MEMBER_SERVICE,
     733             :                             IPA_SERVICE_CATEGORY,
     734             :                             IPA_SOURCE_HOST,
     735             :                             IPA_SOURCE_HOST_CATEGORY,
     736             :                             IPA_EXTERNAL_HOST,
     737             :                             IPA_MEMBER_HOST,
     738             :                             IPA_HOST_CATEGORY,
     739             :                             NULL };
     740             : 
     741           0 :     tmp_ctx = talloc_new(NULL);
     742           0 :     if (tmp_ctx == NULL) return ENOMEM;
     743             : 
     744           0 :     filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
     745           0 :     if (filter == NULL) {
     746           0 :         ret = ENOMEM;
     747           0 :         goto done;
     748             :     }
     749             : 
     750           0 :     ret = sysdb_search_custom(tmp_ctx, domain, filter,
     751             :                               HBAC_RULES_SUBDIR, attrs,
     752             :                               &rule_count, &msgs);
     753           0 :     if (ret != EOK && ret != ENOENT) {
     754           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n");
     755           0 :         goto done;
     756           0 :     } if (ret == ENOENT) {
     757           0 :        rule_count = 0;
     758             :     }
     759             : 
     760           0 :     ret = sysdb_msg2attrs(tmp_ctx, rule_count, msgs, &rules);
     761           0 :     if (ret != EOK) {
     762           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     763             :               "Could not convert ldb message to sysdb_attrs\n");
     764           0 :         goto done;
     765             :     }
     766             : 
     767           0 :     if (_rules) *_rules = talloc_steal(mem_ctx, rules);
     768           0 :     if (_rule_count) *_rule_count = rule_count;
     769             : 
     770           0 :     ret = EOK;
     771             : done:
     772           0 :     talloc_free(tmp_ctx);
     773           0 :     return ret;
     774             : }

Generated by: LCOV version 1.10