summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-05-19 15:23:34 +0200
committerStephen Gallagher <sgallagh@redhat.com>2010-05-23 12:15:59 -0400
commitdfa84d5fcc40edf30b8d371fcd99977d75533bb6 (patch)
tree5e28029fea69408ce2d44e2c0ca301a63bb272af
parenteb812bb807d65309c037c6a806b728c637e9b0fa (diff)
downloadsssd_unused-dfa84d5fcc40edf30b8d371fcd99977d75533bb6.tar.gz
sssd_unused-dfa84d5fcc40edf30b8d371fcd99977d75533bb6.tar.xz
sssd_unused-dfa84d5fcc40edf30b8d371fcd99977d75533bb6.zip
Use new schema for HBAC service checks
-rw-r--r--src/providers/ipa/ipa_access.c830
-rw-r--r--src/providers/ipa/ipa_access.h4
2 files changed, 812 insertions, 22 deletions
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index b8a928a0..9d639e63 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -31,7 +31,8 @@
#include "providers/ipa/ipa_access.h"
#include "providers/ipa/ipa_timerules.h"
-#define IPA_HOST_MEMBEROF "memberOf"
+#define OBJECTCLASS "objectclass"
+#define IPA_MEMBEROF "memberOf"
#define IPA_HOST_SERVERHOSTNAME "serverHostName"
#define IPA_HOST_FQDN "fqdn"
#define IPA_ACCESS_RULE_TYPE "accessRuleType"
@@ -47,14 +48,21 @@
#define IPA_MEMBER_HOST "memberHost"
#define IPA_HOST_CATEGORY "hostCategory"
#define IPA_CN "cn"
+#define IPA_MEMBER_SERVICE "memberService"
+#define IPA_SERVICE_CATEGORY "serviceCategory"
+#define IPA_SERVICEGROUP_MEMBER "member"
#define IPA_HOST_BASE_TMPL "cn=computers,cn=accounts,%s"
#define IPA_HBAC_BASE_TMPL "cn=hbac,%s"
+#define IPA_SERVICES_BASE_TMPL "cn=hbacservices,cn=accounts,%s"
+#define IPA_SERVICEGROUPS_BASE_TMPL "cn=hbacservicegroups,cn=accounts,%s"
#define SYSDB_HBAC_BASE_TMPL "cn=hbac,"SYSDB_TMPL_CUSTOM_BASE
#define HBAC_RULES_SUBDIR "hbac_rules"
#define HBAC_HOSTS_SUBDIR "hbac_hosts"
+#define HBAC_SERVICES_SUBDIR "hbac_services"
+#define HBAC_SERVICEGROUPS_SUBDIR "hbac_servicegroups"
static errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count,
struct ldb_message **msgs,
@@ -98,6 +106,660 @@ static void ipa_access_reply(struct be_req *be_req, int pam_status)
}
}
+struct hbac_get_service_data_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *sdap_ctx;
+ struct sysdb_ctx *sysdb;
+ struct sysdb_handle *handle;
+ const char *basedn;
+ bool offline;
+
+ char *services_filter;
+ char *services_search_base;
+ const char **services_attrs;
+ struct sysdb_attrs **services_reply_list;
+ size_t services_reply_count;
+
+ char *servicegroups_filter;
+ char *servicegroups_search_base;
+ const char **servicegroups_attrs;
+ struct sysdb_attrs **servicegroups_reply_list;
+ size_t servicegroups_reply_count;
+
+ size_t current_item;
+};
+
+static void hbac_get_services_connect_done(struct tevent_req *subreq);
+static void hbac_services_get_done(struct tevent_req *subreq);
+static void hbac_servicegroups_get_done(struct tevent_req *subreq);
+static void hbac_service_data_sysdb_transaction_started(struct tevent_req *subreq);
+static void hbac_services_delete_done(struct tevent_req *subreq);
+static void hbac_servicegroups_delete_done(struct tevent_req *subreq);
+static void hbac_service_store_prepare(struct tevent_req *req);
+static void hbac_service_store_done(struct tevent_req *subreq);
+static void hbac_servicegroup_store_prepare(struct tevent_req *req);
+static void hbac_servicegroup_store_done(struct tevent_req *subreq);
+
+struct tevent_req *hbac_get_service_data_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ bool offline,
+ struct sdap_id_ctx *sdap_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *basedn)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct hbac_get_service_data_state *state;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct hbac_get_service_data_state);
+ if (req == NULL) {
+ DEBUG(1, ("tevent_req_create failed.\n"));
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->offline = offline;
+ state->sdap_ctx = sdap_ctx;
+ state->sysdb = sysdb;
+ state->handle = NULL;
+ state->basedn = basedn;
+
+ state->services_reply_list = NULL;
+ state->services_reply_count = 0;
+
+ state->servicegroups_filter = NULL;
+ state->servicegroups_search_base = NULL;
+ state->servicegroups_attrs = NULL;
+ state->servicegroups_reply_list = NULL;
+ state->servicegroups_reply_count = 0;
+
+ state->current_item = 0;
+
+ state->services_search_base = talloc_asprintf(state, IPA_SERVICES_BASE_TMPL,
+ basedn);
+ if (state->services_search_base == NULL) {
+ DEBUG(1, ("Failed to create service search base.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ state->services_attrs = talloc_array(state, const char *, 7);
+ if (state->services_attrs == NULL) {
+ DEBUG(1, ("Failed to allocate service attribute list.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ state->services_attrs[0] = IPA_CN;
+ state->services_attrs[1] = SYSDB_ORIG_DN;
+ state->services_attrs[2] = IPA_UNIQUE_ID;
+ state->services_attrs[3] = IPA_MEMBEROF;
+ state->services_attrs[4] = SYSDB_ORIG_MEMBEROF;
+ state->services_attrs[5] = OBJECTCLASS;
+ state->services_attrs[6] = NULL;
+
+ state->services_filter = talloc_asprintf(state,
+ "(objectclass=ipaHBACService)");
+ if (state->services_filter == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(9, ("Services filter: [%s].\n", state->services_filter));
+
+ if (offline) {
+ subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL,
+ state->sdap_ctx->be->domain,
+ state->services_filter,
+ HBAC_SERVICES_SUBDIR,
+ state->services_attrs);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_search_custom_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_services_get_done, req);
+
+ return req;
+ }
+
+ if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {
+ subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,
+ sdap_ctx->be, sdap_ctx->service, NULL);
+ if (!subreq) {
+ DEBUG(1, ("sdap_cli_connect_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_get_services_connect_done, req);
+
+ return req;
+ }
+
+ subreq = sdap_get_generic_send(state, state->ev,
+ state->sdap_ctx->opts,
+ state->sdap_ctx->gsh,
+ state->services_search_base,
+ LDAP_SCOPE_SUB,
+ state->services_filter,
+ state->services_attrs,
+ NULL, 0);
+
+ if (subreq == NULL) {
+ DEBUG(1, ("sdap_get_generic_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_services_get_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void hbac_get_services_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+
+ ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,
+ NULL);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_get_generic_send(state, state->ev,
+ state->sdap_ctx->opts,
+ state->sdap_ctx->gsh,
+ state->services_search_base,
+ LDAP_SCOPE_SUB,
+ state->services_filter,
+ state->services_attrs,
+ NULL, 0);
+
+ if (subreq == NULL) {
+ DEBUG(1, ("sdap_get_generic_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_services_get_done, req);
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_services_get_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_message **msgs;
+
+ if (state->offline) {
+ ret = sysdb_search_custom_recv(subreq, state,
+ &state->services_reply_count, &msgs);
+ } else {
+ ret = sdap_get_generic_recv(subreq, state, &state->services_reply_count,
+ &state->services_reply_list);
+ }
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (state->offline) {
+ ret = msgs2attrs_array(state, state->services_reply_count, msgs,
+ &state->services_reply_list);
+ talloc_zfree(msgs);
+ if (ret != EOK) {
+ DEBUG(1, ("msgs2attrs_array failed.\n"));
+ goto fail;
+ }
+ }
+
+ state->servicegroups_search_base = talloc_asprintf(state,
+ IPA_SERVICEGROUPS_BASE_TMPL,
+ state->basedn);
+ if (state->servicegroups_search_base == NULL) {
+ DEBUG(1, ("Failed to create service groups search base.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ state->servicegroups_attrs = talloc_array(state, const char *, 8);
+ if (state->servicegroups_attrs == NULL) {
+ DEBUG(1, ("Failed to allocate servicegroup attribute list.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ state->servicegroups_attrs[0] = IPA_CN;
+ state->servicegroups_attrs[1] = IPA_SERVICEGROUP_MEMBER;
+ state->servicegroups_attrs[2] = SYSDB_ORIG_DN;
+ state->servicegroups_attrs[3] = IPA_UNIQUE_ID;
+ state->servicegroups_attrs[4] = IPA_MEMBEROF;
+ state->servicegroups_attrs[5] = SYSDB_ORIG_MEMBEROF;
+ state->servicegroups_attrs[6] = OBJECTCLASS;
+ state->servicegroups_attrs[7] = NULL;
+
+ state->servicegroups_filter = talloc_asprintf(state,
+ "(objectclass=ipaHBACServiceGroup)");
+ if (state->servicegroups_filter == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(9, ("Services filter: [%s].\n", state->servicegroups_filter));
+
+ if (state->offline) {
+ subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL,
+ state->sdap_ctx->be->domain,
+ state->servicegroups_filter,
+ HBAC_SERVICEGROUPS_SUBDIR,
+ state->servicegroups_attrs);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_search_custom_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_servicegroups_get_done, req);
+
+ return;
+ }
+
+ subreq = sdap_get_generic_send(state, state->ev,
+ state->sdap_ctx->opts,
+ state->sdap_ctx->gsh,
+ state->servicegroups_search_base,
+ LDAP_SCOPE_SUB,
+ state->servicegroups_filter,
+ state->servicegroups_attrs,
+ NULL, 0);
+
+ if (subreq == NULL) {
+ DEBUG(1, ("sdap_get_generic_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_servicegroups_get_done, req);
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_servicegroups_get_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_message **msgs;
+
+ if (state->offline) {
+ ret = sysdb_search_custom_recv(subreq, state,
+ &state->servicegroups_reply_count, &msgs);
+ } else {
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->servicegroups_reply_count,
+ &state->servicegroups_reply_list);
+ }
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (state->offline) {
+ ret = msgs2attrs_array(state, state->servicegroups_reply_count, msgs,
+ &state->servicegroups_reply_list);
+ talloc_zfree(msgs);
+ if (ret != EOK) {
+ DEBUG(1, ("msgs2attrs_array failed.\n"));
+ goto fail;
+ }
+ }
+
+ if ((state->services_reply_count == 0 &&
+ state->servicegroups_reply_count == 0)|| state->offline) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_transaction_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, hbac_service_data_sysdb_transaction_started,
+ req);
+ return;
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_service_data_sysdb_transaction_started(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_dn *services_base_dn;
+
+ ret = sysdb_transaction_recv(subreq, state, &state->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ services_base_dn = sysdb_custom_subtree_dn(state->sysdb, state,
+ state->sdap_ctx->be->domain->name,
+ HBAC_SERVICES_SUBDIR);
+ if (services_base_dn == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(9, ("Trying to delete [%s].\n", ldb_dn_get_linearized(services_base_dn)));
+ subreq = sysdb_delete_recursive_send(state, state->ev, state->handle,
+ services_base_dn, true);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_delete_recursive_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, hbac_services_delete_done, req);
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_services_delete_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_dn *servicegroups_base_dn;
+
+ ret = sysdb_delete_recursive_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ servicegroups_base_dn = sysdb_custom_subtree_dn(state->sysdb, state,
+ state->sdap_ctx->be->domain->name,
+ HBAC_SERVICEGROUPS_SUBDIR);
+ if (servicegroups_base_dn == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(9, ("Trying to delete [%s].\n", ldb_dn_get_linearized(servicegroups_base_dn)));
+ subreq = sysdb_delete_recursive_send(state, state->ev, state->handle,
+ servicegroups_base_dn, true);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_delete_recursive_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, hbac_servicegroups_delete_done, req);
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_servicegroups_delete_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+
+ ret = sysdb_delete_recursive_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->current_item = 0;
+ hbac_service_store_prepare(req);
+}
+
+static void hbac_service_store_prepare(struct tevent_req *req)
+{
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_message_element *el;
+ struct tevent_req *subreq;
+ char *object_name;
+
+ if (state->current_item < state->services_reply_count) {
+
+/* TODO: I would prefer IPA_UNIQUE_ID but currently it is not available */
+ ret = sysdb_attrs_get_el(state->services_reply_list[state->current_item],
+ IPA_CN, &el);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ ret = EINVAL;
+ goto fail;
+ }
+ object_name = talloc_strndup(state, (const char *)el->values[0].data,
+ el->values[0].length);
+ if (object_name == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ DEBUG(9, ("Object name: [%s].\n", object_name));
+
+ ret = sysdb_attrs_replace_name(
+ state->services_reply_list[state->current_item],
+ IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));
+ goto fail;
+ }
+
+ subreq = sysdb_store_custom_send(state, state->ev,
+ state->handle,
+ state->sdap_ctx->be->domain,
+ object_name,
+ HBAC_SERVICES_SUBDIR,
+ state->services_reply_list[state->current_item]);
+
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_store_custom_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_service_store_done, req);
+ return;
+ }
+
+ state->current_item = 0;
+ hbac_servicegroup_store_prepare(req);
+
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_service_store_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+
+ ret = sysdb_store_custom_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->current_item++;
+ hbac_service_store_prepare(req);
+}
+
+static void hbac_servicegroup_store_prepare(struct tevent_req *req)
+{
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+ struct ldb_message_element *el;
+ struct tevent_req *subreq;
+ char *object_name;
+
+ if (state->current_item < state->servicegroups_reply_count) {
+
+/* TODO: I would prefer IPA_UNIQUE_ID but currently it is not available */
+ ret = sysdb_attrs_get_el(state->servicegroups_reply_list[state->current_item],
+ IPA_CN, &el);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ ret = EINVAL;
+ goto fail;
+ }
+ object_name = talloc_strndup(state, (const char *)el->values[0].data,
+ el->values[0].length);
+ if (object_name == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ DEBUG(9, ("Object name: [%s].\n", object_name));
+
+ ret = sysdb_attrs_replace_name(
+ state->servicegroups_reply_list[state->current_item],
+ IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));
+ goto fail;
+ }
+
+ subreq = sysdb_store_custom_send(state, state->ev,
+ state->handle,
+ state->sdap_ctx->be->domain,
+ object_name,
+ HBAC_SERVICEGROUPS_SUBDIR,
+ state->servicegroups_reply_list[state->current_item]);
+
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_store_custom_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, hbac_servicegroup_store_done, req);
+ return;
+ }
+
+ subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
+ if (subreq == NULL) {
+ DEBUG(1, ("sysdb_transaction_commit_send failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
+
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void hbac_servicegroup_store_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int ret;
+
+ ret = sysdb_store_custom_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->current_item++;
+ hbac_servicegroup_store_prepare(req);
+}
+
+static int hbac_get_service_data_recv(struct tevent_req *req,
+ TALLOC_CTX *memctx,
+ size_t *hbac_services_count,
+ struct sysdb_attrs ***hbac_services_list,
+ size_t *hbac_servicegroups_count,
+ struct sysdb_attrs ***hbac_servicegroups_list)
+{
+ struct hbac_get_service_data_state *state = tevent_req_data(req,
+ struct hbac_get_service_data_state);
+ int i;
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *hbac_services_count = state->services_reply_count;
+ *hbac_services_list = talloc_steal(memctx, state->services_reply_list);
+ for (i = 0; i < state->services_reply_count; i++) {
+ talloc_steal(memctx, state->services_reply_list[i]);
+ }
+
+ *hbac_servicegroups_count = state->servicegroups_reply_count;
+ *hbac_servicegroups_list = talloc_steal(memctx,
+ state->servicegroups_reply_list);
+ for (i = 0; i < state->servicegroups_reply_count; i++) {
+ talloc_steal(memctx, state->servicegroups_reply_list[i]);
+ }
+ return EOK;
+}
+
struct hbac_get_user_info_state {
struct tevent_context *ev;
struct be_ctx *be_ctx;;
@@ -407,7 +1069,7 @@ static struct tevent_req *hbac_get_host_info_send(TALLOC_CTX *memctx,
ret = ENOMEM;
goto fail;
}
- state->host_attrs[0] = IPA_HOST_MEMBEROF;
+ state->host_attrs[0] = IPA_MEMBEROF;
state->host_attrs[1] = IPA_HOST_SERVERHOSTNAME;
state->host_attrs[2] = IPA_HOST_FQDN;
state->host_attrs[3] = "objectClass";
@@ -626,7 +1288,7 @@ static void hbac_get_host_memberof_done(struct tevent_req *subreq)
ret = sysdb_attrs_get_el(state->host_reply_list[i],
state->offline ? SYSDB_ORIG_MEMBEROF :
- IPA_HOST_MEMBEROF,
+ IPA_MEMBEROF,
&el);
if (ret != EOK) {
DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
@@ -642,7 +1304,7 @@ static void hbac_get_host_memberof_done(struct tevent_req *subreq)
sizeof(const char *) * (el->num_values + 1));
for(v = 0; v < el->num_values; v++) {
- DEBUG(9, ("%s: [%.*s].\n", IPA_HOST_MEMBEROF, el->values[v].length,
+ DEBUG(9, ("%s: [%.*s].\n", IPA_MEMBEROF, el->values[v].length,
(const char *)el->values[v].data));
hhi[i]->memberof[v] = talloc_strndup(hhi,
(const char *)el->values[v].data,
@@ -727,7 +1389,7 @@ static void hbac_get_host_info_store_prepare(struct tevent_req *req)
ret = sysdb_attrs_replace_name(
state->host_reply_list[state->current_item],
- IPA_HOST_MEMBEROF, SYSDB_ORIG_MEMBEROF);
+ IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);
if (ret != EOK) {
DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));
goto fail;
@@ -870,7 +1532,7 @@ static struct tevent_req *hbac_get_rules_send(TALLOC_CTX *memctx,
goto fail;
}
- state->hbac_attrs = talloc_array(state, const char *, 16);
+ state->hbac_attrs = talloc_array(state, const char *, 18);
if (state->hbac_attrs == NULL) {
DEBUG(1, ("Failed to allocate HBAC attribute list.\n"));
ret = ENOMEM;
@@ -887,11 +1549,13 @@ static struct tevent_req *hbac_get_rules_send(TALLOC_CTX *memctx,
state->hbac_attrs[8] = IPA_UNIQUE_ID;
state->hbac_attrs[9] = IPA_ENABLED_FLAG;
state->hbac_attrs[10] = IPA_CN;
- state->hbac_attrs[11] = "objectclass";
+ state->hbac_attrs[11] = OBJECTCLASS;
state->hbac_attrs[12] = IPA_MEMBER_HOST;
state->hbac_attrs[13] = IPA_HOST_CATEGORY;
- state->hbac_attrs[14] = SYSDB_ORIG_DN;
- state->hbac_attrs[15] = NULL;
+ state->hbac_attrs[14] = IPA_MEMBER_SERVICE;
+ state->hbac_attrs[15] = IPA_SERVICE_CATEGORY;
+ state->hbac_attrs[16] = SYSDB_ORIG_DN;
+ state->hbac_attrs[17] = NULL;
state->hbac_filter = talloc_asprintf(state,
"(&(objectclass=ipaHBACRule)"
@@ -1248,41 +1912,129 @@ enum check_result {
RULE_ERROR
};
-enum check_result check_service(struct pam_data *pd,
+static errno_t get_service_data(const char *cn, size_t count,
+ struct sysdb_attrs **list, const char **dn,
+ struct ldb_message_element **mof)
+{
+ int ret;
+ int i;
+ int j;
+ struct ldb_message_element *el;
+
+ for (i = 0; i < count; i++) {
+ ret = sysdb_attrs_get_el(list[i], IPA_CN, &el);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ return ENOENT;
+ }
+ if (el->num_values == 0) {
+ DEBUG(9, ("No cn found.\n"));
+ return ENOENT;
+ } else {
+ for (j = 0; j < el->num_values; j++) {
+ if (strncmp(cn, (const char *) el->values[j].data,
+ el->values[j].length) == 0) {
+
+ ret = sysdb_attrs_get_string(list[i], SYSDB_ORIG_DN, dn);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_string failed.\n"));
+ return ret;
+ }
+
+ ret = sysdb_attrs_get_el(list[i], SYSDB_ORIG_MEMBEROF, mof);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ return ret;
+ }
+
+ return EOK;
+ }
+ }
+ }
+ }
+
+ return ENOENT;
+}
+
+enum check_result check_service(struct hbac_ctx *hbac_ctx,
struct sysdb_attrs *rule_attrs)
{
int ret;
int i;
+ int g;
struct ldb_message_element *el;
+ const char *service_dn;
+ struct ldb_message_element *service_memberof;
- if (pd->service == NULL) {
+ if (hbac_ctx->pd->service == NULL) {
DEBUG(1, ("No service in pam data, assuming error.\n"));
return RULE_ERROR;
}
- ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_NAME, &el);
+ ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_CATEGORY, &el);
if (ret != EOK) {
DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
return RULE_ERROR;
}
if (el->num_values == 0) {
- DEBUG(9, ("No services in rule specified, assuming rule applies.\n"));
- return RULE_APPLICABLE;
+ DEBUG(9, ("Service category is not set.\n"));
} else {
for (i = 0; i < el->num_values; i++) {
- if (strlen(pd->service) == el->values[i].length &&
- strncasecmp(pd->service, (const char *) el->values[i].data,
+ if (strncasecmp("all", (const char *) el->values[i].data,
el->values[i].length) == 0) {
- DEBUG(9, ("Service [%s] found, rule applies.\n",
- pd->service));
+ DEBUG(9, ("Service category is set to 'all', rule applies.\n"));
return RULE_APPLICABLE;
}
+ DEBUG(9, ("Unsupported service category [%.*s].\n",
+ el->values[i].length,
+ (char *) el->values[i].data));
}
- DEBUG(9, ("No matching service found, rule does not apply.\n"));
+ }
+
+ ret = get_service_data(hbac_ctx->pd->service, hbac_ctx->hbac_services_count,
+ hbac_ctx->hbac_services_list, &service_dn,
+ &service_memberof);
+ if (ret != EOK) {
+ DEBUG(1, ("Cannot find original DN for service [%s].\n",
+ hbac_ctx->pd->service));
+ return RULE_ERROR;
+ }
+ DEBUG(9, ("OriginalDN for service [%s]: [%s].\n", hbac_ctx->pd->service,
+ service_dn));
+
+ ret = sysdb_attrs_get_el(rule_attrs, IPA_MEMBER_SERVICE, &el);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_get_el failed.\n"));
+ return RULE_ERROR;
+ }
+ if (el->num_values == 0) {
+ DEBUG(9, ("No service or service group specified, rule does not apply.\n"));
return RULE_NOT_APPLICABLE;
}
- return RULE_ERROR;
+ for (i = 0; i < el->num_values; i++) {
+ if (strncmp(service_dn, (const char *) el->values[i].data,
+ el->values[i].length) == 0) {
+ DEBUG(9, ("Service [%s] found in the list of allowed "
+ "services.\n", hbac_ctx->pd->service));
+ return RULE_APPLICABLE;
+ }
+
+ for (g = 0; g < service_memberof->num_values; g++) {
+ if (service_memberof->values[g].length == el->values[i].length &&
+ strncmp((const char *) service_memberof->values[g].data,
+ (const char *) el->values[i].data,
+ el->values[i].length) == 0) {
+ DEBUG(9, ("Service [%s] is a member of a group in the list of "
+ "allowed service groups.\n", hbac_ctx->pd->service));
+ return RULE_APPLICABLE;
+ }
+ }
+ }
+
+ DEBUG(9, ("Service [%s] was not found in the list of allowed services and "
+ "service groups.\n", hbac_ctx->pd->service));
+ return RULE_NOT_APPLICABLE;
}
enum check_result check_access_time(struct time_rules_ctx *tr_ctx,
@@ -1569,7 +2321,7 @@ static errno_t check_if_rule_applies(struct hbac_ctx *hbac_ctx,
return EINVAL;
}
- ret = check_service(pd, rule_attrs);
+ ret = check_service(hbac_ctx, rule_attrs);
if (ret != RULE_APPLICABLE) {
goto not_applicable;
}
@@ -1643,6 +2395,7 @@ static int evaluate_ipa_hbac_rules(struct hbac_ctx *hbac_ctx,
static void hbac_get_host_info_done(struct tevent_req *req);
static void hbac_get_rules_done(struct tevent_req *req);
+static void hbac_get_service_data_done(struct tevent_req *req);
static void hbac_get_user_info_done(struct tevent_req *req);
void ipa_access_handler(struct be_req *be_req)
@@ -1778,7 +2531,6 @@ fail:
static void hbac_get_rules_done(struct tevent_req *req)
{
struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);
- struct pam_data *pd = hbac_ctx->pd;
struct be_req *be_req = hbac_ctx->be_req;
int ret;
int pam_status = PAM_SYSTEM_ERR;
@@ -1790,6 +2542,40 @@ static void hbac_get_rules_done(struct tevent_req *req)
goto fail;
}
+ req = hbac_get_service_data_send(hbac_ctx, be_req->be_ctx->ev,
+ hbac_ctx->offline, hbac_ctx->sdap_ctx,
+ be_req->be_ctx->sysdb,
+ hbac_ctx->ldap_basedn);
+ if (req == NULL) {
+ DEBUG(1, ("hbac_get_service_data_send failed.\n"));
+ goto fail;
+ }
+
+ tevent_req_set_callback(req, hbac_get_service_data_done, hbac_ctx);
+ return;
+
+fail:
+ ipa_access_reply(be_req, pam_status);
+}
+
+static void hbac_get_service_data_done(struct tevent_req *req)
+{
+ struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);
+ struct pam_data *pd = hbac_ctx->pd;
+ struct be_req *be_req = hbac_ctx->be_req;
+ int ret;
+ int pam_status = PAM_SYSTEM_ERR;
+
+ ret = hbac_get_service_data_recv(req, hbac_ctx,
+ &hbac_ctx->hbac_services_count,
+ &hbac_ctx->hbac_services_list,
+ &hbac_ctx->hbac_servicegroups_count,
+ &hbac_ctx->hbac_servicegroups_list);
+ talloc_zfree(req);
+ if (ret != EOK) {
+ goto fail;
+ }
+
req = hbac_get_user_info_send(hbac_ctx, be_req->be_ctx->ev, be_req->be_ctx,
pd->user);
if (req == NULL) {
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index e3ba5c30..e3e0c4ff 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -60,6 +60,10 @@ struct hbac_ctx {
const char **groups;
bool offline;
char *ldap_basedn;
+ struct sysdb_attrs **hbac_services_list;
+ size_t hbac_services_count;
+ struct sysdb_attrs **hbac_servicegroups_list;
+ size_t hbac_servicegroups_count;
};
void ipa_access_handler(struct be_req *be_req);