[SSSD] [PATCH] Process SELinux mapping while offline
Jakub Hrozek
jhrozek at redhat.com
Tue Jan 8 13:51:07 UTC 2013
On Tue, Jan 08, 2013 at 01:37:50PM +0100, Sumit Bose wrote:
> On Tue, Jan 08, 2013 at 12:44:54PM +0100, Sumit Bose wrote:
> > On Mon, Jan 07, 2013 at 12:29:14AM +0100, Jakub Hrozek wrote:
> > > This patchset fixes the SELinux processing so that it works also offline
> > > for cases described in #1626 for example.
> > >
> > > The code was architected in an extremely strange way where every request
> > > would store a per-request/per-user score attribute in the selinux mapping
> > > objects themselves and the responder would just pick the highest score.
> > >
> > > At the same time, the scores were only calculated when the mappings were
> > > downloaded and only for rules that matched, which pretty much broke offline
> > > support. I intend to fix the architecture by only making the provider only
> > > download and store the rules and let the responder pick the context. But I'm
> > > not sure if I can do that right during the current time constraints. I filed
> > > #1743 to track that effort and I'll be sending some patches for master so
> > > far, but I'd like to include this patchset to fix the functionality at last.
> > >
> > > I also noticed that the rules are downloaded on *every login*, without
> > > any timeout in between, so I filed #1744 to either reuse
> > > IPA_HBAC_REFRESH or introduce a similar timeout for performance reasons.
> > >
> > > [PATCH 1/4] SYSDB: Remove duplicate selinux defines
> > > Some constants were defined in both sysdb.h and sysdb_selinux.h. This
> > > patch removes the duplicates.
> >
> > ACK
>
> sorry, ACK was too early, this patch breaks make check. Following patch
> fixes it:
>
> diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
> index 01c32f4..66ca8ba 100644
> --- a/src/providers/ipa/ipa_opts.h
> +++ b/src/providers/ipa/ipa_opts.h
> @@ -28,6 +28,7 @@
> #include "db/sysdb_sudo.h"
> #include "db/sysdb_autofs.h"
> #include "db/sysdb_services.h"
> +#include "db/sysdb_selinux.h"
>
> struct dp_option ipa_basic_opts[] = {
> { "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
>
>
>
> bye,
> Sumit
>
> >
> > >
> > > [PATCH 2/4] SYSDB: Split a function to read all SELinux maps
> > > This function will be reused in the DP to read maps from cache when
> > > offline.
> >
> > ACK
> >
> > >
> > > [PATCH 3/4] SELINUX: Process maps even when offline
> > > The patch is quite big, but I couldn't split it in a meaningful way,
> > > sorry. The patch changes the ipa_get_selinux{send,recv} to only provide
> > > data independently on the offline stat and moves all the processing to
> > > the ipa_selinux_handler. The scores are calculated
> >
> > see comments below
> > >
> > > [PATCH 4/4] IPA: Rename IPA_CONFIG_SELINUX_DEFAULT_MAP
> > > The option IPA_CONFIG_SELINUX_DEFAULT_MAP was misnamed. It doesn't
> > > describe any map, but the default context the user should obtain when
> > > nothing else matches.
> >
> > ACK
> >
> > I'll run some test now. Is there anything I should test explicitly?
> >
> > bye,
> > Sumit
> >
Thank you for the review. A new patchset is attached.
-------------- next part --------------
>From d416a056f03bb927bf0e8c5e23a99369c22d6253 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 11:34:46 -0500
Subject: [PATCH 1/4] SYSDB: Remove duplicate selinux defines
---
src/db/sysdb.h | 5 -----
src/db/sysdb_selinux.h | 1 +
src/providers/ipa/ipa_opts.h | 1 +
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 35888977f28b205da51d332d76517908fa364f8a..9db831456d8e228107872bd732f80493ff09b03b 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -100,11 +100,6 @@
#define SYSDB_FQDN "fqdn"
#define SYSDB_SERVERHOSTNAME "serverHostname"
-#define SYSDB_SELINUX_SEEALSO "seeAlso"
-#define SYSDB_SELINUX_USER "selinuxUser"
-#define SYSDB_SELINUX_ENABLED "enabled"
-#define SYSDB_SELINUX_HOST_PRIORITY "hostPriority"
-
#define SYSDB_CACHEDPWD "cachedPassword"
#define SYSDB_UUID "uniqueID"
diff --git a/src/db/sysdb_selinux.h b/src/db/sysdb_selinux.h
index 39bb67a1921d8e22d49802b6dd09e51b102f18a5..c7dbbe98c2e76a072a79443ad68322f437e6597a 100644
--- a/src/db/sysdb_selinux.h
+++ b/src/db/sysdb_selinux.h
@@ -34,6 +34,7 @@
#define SYSDB_SELINUX_ENABLED "enabled"
#define SYSDB_SELINUX_DEFAULT_USER "user"
#define SYSDB_SELINUX_DEFAULT_ORDER "order"
+#define SYSDB_SELINUX_HOST_PRIORITY "hostPriority"
enum selinux_entity_type {
SELINUX_CONFIG,
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 01c32f462919b2b63c6e888b0cd221eab9e344b6..66ca8ba7d1308b9e91e77f01fc309a0ba6a0927d 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -28,6 +28,7 @@
#include "db/sysdb_sudo.h"
#include "db/sysdb_autofs.h"
#include "db/sysdb_services.h"
+#include "db/sysdb_selinux.h"
struct dp_option ipa_basic_opts[] = {
{ "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
--
1.8.0.2
-------------- next part --------------
>From 68a8e26e0646c00eab8e634c5401055ca3de4b96 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 23:44:30 +0100
Subject: [PATCH 2/4] SYSDB: Split a function to read all SELinux maps
---
src/db/sysdb_selinux.c | 66 ++++++++++++++++++++++++++++++++------------------
src/db/sysdb_selinux.h | 6 +++++
2 files changed, 49 insertions(+), 23 deletions(-)
diff --git a/src/db/sysdb_selinux.c b/src/db/sysdb_selinux.c
index 857b17d956babc07670901d06f7219ce8a6f72a5..a6b4809f67f43cbb8d71ad66a39a8b6776a2e0d2 100644
--- a/src/db/sysdb_selinux.c
+++ b/src/db/sysdb_selinux.c
@@ -292,12 +292,53 @@ done:
return ret;
}
+errno_t
+sysdb_get_selinux_usermaps(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char **attrs,
+ size_t *count,
+ struct ldb_message ***messages)
+{
+ errno_t ret;
+ char *filter;
+ struct ldb_dn *basedn;
+ struct sss_domain_info *domain;
+
+ domain = sysdb_ctx_get_domain(sysdb);
+ basedn = ldb_dn_new_fmt(mem_ctx, sysdb_ctx_get_ldb(sysdb),
+ SYSDB_TMPL_SELINUX_BASE, domain->name);
+ if (!basedn) {
+ return ENOMEM;
+ }
+
+ filter = talloc_asprintf(mem_ctx, "(%s=%s)",
+ SYSDB_OBJECTCLASS, SYSDB_SELINUX_USERMAP_CLASS);
+ if (filter == NULL) {
+ talloc_free(basedn);
+ return ENOMEM;
+ }
+
+ ret = sysdb_search_entry(mem_ctx, sysdb, basedn, LDB_SCOPE_SUBTREE, filter,
+ attrs, count, messages);
+ talloc_free(basedn);
+ talloc_free(filter);
+ if (ret == ENOENT) {
+ *count = 0;
+ *messages = NULL;
+ } else if (ret) {
+ return ret;
+ }
+
+ return EOK;
+}
+
errno_t sysdb_search_selinux_usermap_by_username(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *username,
struct ldb_message ***_usermaps)
{
TALLOC_CTX *tmp_ctx;
+ struct ldb_message **msgs = NULL;
const char *attrs[] = { SYSDB_NAME,
SYSDB_USER_CATEGORY,
SYSDB_HOST_CATEGORY,
@@ -306,18 +347,14 @@ errno_t sysdb_search_selinux_usermap_by_username(TALLOC_CTX *mem_ctx,
SYSDB_SELINUX_HOST_PRIORITY,
SYSDB_SELINUX_USER,
NULL };
- struct ldb_message **msgs = NULL;
struct sysdb_attrs *user;
struct sysdb_attrs *tmp_attrs;
struct ldb_message **usermaps = NULL;
- struct sss_domain_info *domain;
- struct ldb_dn *basedn;
size_t msgs_count = 0;
size_t usermaps_cnt;
uint32_t priority = 0;
uint32_t host_priority = 0;
uint32_t top_priority = 0;
- char *filter;
errno_t ret;
int i;
@@ -333,25 +370,8 @@ errno_t sysdb_search_selinux_usermap_by_username(TALLOC_CTX *mem_ctx,
}
/* Now extract all SELinux user maps */
- domain = sysdb_ctx_get_domain(sysdb);
- basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(sysdb),
- SYSDB_TMPL_SELINUX_BASE, domain->name);
- if (!basedn) {
- ret = ENOMEM;
- goto done;
- }
-
- filter = talloc_asprintf(tmp_ctx, "(objectclass=%s)", SYSDB_SELINUX_USERMAP_CLASS);
- if (filter == NULL) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = sysdb_search_entry(tmp_ctx, sysdb, basedn, LDB_SCOPE_SUBTREE, filter,
- attrs, &msgs_count, &msgs);
- if (ret == ENOENT) {
- msgs_count = 0;
- } else if (ret) {
+ ret = sysdb_get_selinux_usermaps(tmp_ctx, sysdb, attrs, &msgs_count, &msgs);
+ if (ret) {
goto done;
}
diff --git a/src/db/sysdb_selinux.h b/src/db/sysdb_selinux.h
index c7dbbe98c2e76a072a79443ad68322f437e6597a..5fcbb56ef20f1ee11b979fc6e0b4ea87adfa939e 100644
--- a/src/db/sysdb_selinux.h
+++ b/src/db/sysdb_selinux.h
@@ -48,6 +48,12 @@ errno_t sysdb_store_selinux_config(struct sysdb_ctx *sysdb,
const char *default_map,
const char *order);
+errno_t sysdb_get_selinux_usermaps(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char **attrs,
+ size_t *count,
+ struct ldb_message ***messages);
+
errno_t sysdb_search_selinux_usermap_by_mapname(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *name,
--
1.8.0.2
-------------- next part --------------
>From 9c8250d8626178c397fd38a765e27570d2c5497b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 23:52:19 +0100
Subject: [PATCH 3/4] SELINUX: Process maps even when offline
Changes the ipa_get_selinux{send,recv} request so that it only delivers
data and moves processing to the IPA selinux handler.
---
src/providers/ipa/ipa_selinux.c | 655 ++++++++++++++++++++++++++--------------
1 file changed, 429 insertions(+), 226 deletions(-)
diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
index b64de90b1236b7828753d79b8402a4fab0dfeeae..909ef056cbccca80bcc512e3fca858b1f4577c51 100644
--- a/src/providers/ipa/ipa_selinux.c
+++ b/src/providers/ipa/ipa_selinux.c
@@ -37,52 +37,53 @@
#include "providers/ipa/ipa_selinux_common.h"
#include "providers/ipa/ipa_selinux_maps.h"
-struct ipa_get_selinux_state {
- struct be_req *be_req;
- struct pam_data *pd;
- struct ipa_selinux_ctx *selinux_ctx;
- struct sdap_id_op *op;
-
- const char *hostname;
- struct sysdb_attrs *host;
- struct sysdb_attrs *user;
-
- struct sysdb_attrs *defaults;
- struct sysdb_attrs **selinuxmaps;
- size_t nmaps;
-
- struct sysdb_attrs **possible_match;
- size_t possible_matches;
-};
-
-static struct
-tevent_req *ipa_get_selinux_send(struct be_req *breq,
- struct pam_data *pd,
- struct ipa_selinux_ctx *selinux_ctx);
-static void ipa_selinux_handler_done(struct tevent_req *subreq);
+static struct tevent_req *
+ipa_get_selinux_send(struct be_req *breq,
+ struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct ipa_selinux_ctx *selinux_ctx);
static errno_t ipa_get_selinux_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *count,
struct sysdb_attrs ***maps,
+ size_t *hbac_count,
+ struct sysdb_attrs ***hbac_rules,
char **default_user,
char **map_order);
+static struct ipa_selinux_op_ctx *
+ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+ struct be_req *be_req, const char *username,
+ const char *hostname);
+static void ipa_selinux_handler_done(struct tevent_req *subreq);
+
static void ipa_get_selinux_connect_done(struct tevent_req *subreq);
static void ipa_get_selinux_hosts_done(struct tevent_req *subreq);
static void ipa_get_config_step(struct tevent_req *req);
static void ipa_get_selinux_config_done(struct tevent_req *subreq);
static void ipa_get_selinux_maps_done(struct tevent_req *subreq);
static void ipa_get_selinux_hbac_done(struct tevent_req *subreq);
-static int
-ipa_get_selinux_hbac_process(struct ipa_get_selinux_state *state,
- struct sysdb_attrs **rules,
- size_t rule_count);
+static errno_t ipa_selinux_process_maps(struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct sysdb_attrs **selinux_maps,
+ size_t selinux_map_count,
+ struct sysdb_attrs **hbac_rules,
+ size_t hbac_rule_count);
+
+struct ipa_selinux_op_ctx {
+ struct be_req *be_req;
+
+ struct sysdb_attrs *user;
+ struct sysdb_attrs *host;
+};
void ipa_selinux_handler(struct be_req *be_req)
{
struct ipa_selinux_ctx *selinux_ctx;
+ struct ipa_selinux_op_ctx *op_ctx;
struct tevent_req *req;
struct pam_data *pd;
+ const char *hostname;
pd = talloc_get_type(be_req->req_data, struct pam_data);
@@ -90,23 +91,96 @@ void ipa_selinux_handler(struct be_req *be_req)
be_req->be_ctx->bet_info[BET_SELINUX].pvt_bet_data,
struct ipa_selinux_ctx);
+ hostname = dp_opt_get_string(selinux_ctx->id_ctx->ipa_options->basic,
+ IPA_HOSTNAME);
+ if (!hostname) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Cannot determine this machine's host name\n"));
+ goto fail;
+ }
- req = ipa_get_selinux_send(be_req, pd, selinux_ctx);
+ op_ctx = ipa_selinux_create_op_ctx(be_req, be_req->sysdb, be_req,
+ pd->user, hostname);
+ if (op_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Cannot create op context\n"));
+ goto fail;
+ }
+
+ req = ipa_get_selinux_send(be_req, op_ctx->user, op_ctx->host, selinux_ctx);
if (req == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Cannot initiate the search\n"));
goto fail;
}
- tevent_req_set_callback(req, ipa_selinux_handler_done, be_req);
-
+ tevent_req_set_callback(req, ipa_selinux_handler_done, op_ctx);
return;
fail:
be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
}
+static struct ipa_selinux_op_ctx *
+ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+ struct be_req *be_req, const char *username,
+ const char *hostname)
+{
+ struct ipa_selinux_op_ctx *op_ctx;
+ struct ldb_dn *host_dn;
+ const char *attrs[] = { SYSDB_ORIG_DN,
+ SYSDB_ORIG_MEMBEROF,
+ NULL };
+ size_t count;
+ struct ldb_message **msgs;
+ struct sysdb_attrs **hosts;
+ errno_t ret;
+
+ op_ctx = talloc_zero(mem_ctx, struct ipa_selinux_op_ctx);
+ if (op_ctx == NULL) {
+ return NULL;
+ }
+ op_ctx->be_req = be_req;
+
+ ret = sss_selinux_extract_user(op_ctx, sysdb, username, &op_ctx->user);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ host_dn = sysdb_custom_dn(sysdb, op_ctx, hostname, HBAC_HOSTS_SUBDIR);
+ if (host_dn == NULL) {
+ goto fail;
+ }
+
+ /* Look up the host to get its originalMemberOf entries */
+ ret = sysdb_search_entry(op_ctx, sysdb, host_dn,
+ LDB_SCOPE_BASE, NULL,
+ attrs, &count, &msgs);
+ if (ret == ENOENT || count == 0) {
+ op_ctx->host = NULL;
+ return op_ctx;
+ } else if (ret != EOK) {
+ goto fail;
+ } else if (count > 1) {
+ DEBUG(SSSDBG_OP_FAILURE, ("More than one result for a BASE search!\n"));
+ goto fail;
+ }
+
+ ret = sysdb_msg2attrs(op_ctx, count, msgs, &hosts);
+ talloc_free(msgs);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ op_ctx->host = hosts[0];
+ return op_ctx;
+
+fail:
+ talloc_free(op_ctx);
+ return NULL;
+}
+
static void ipa_selinux_handler_done(struct tevent_req *req)
{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx);
+ struct be_req *breq = op_ctx->be_req;
struct sysdb_ctx *sysdb = breq->be_ctx->sysdb;
errno_t ret, sret;
size_t map_count = 0;
@@ -115,13 +189,23 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
char *default_user = NULL;
struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data);
char *map_order = NULL;
+ size_t hbac_count = 0;
+ struct sysdb_attrs **hbac_rules = 0;
ret = ipa_get_selinux_recv(req, breq, &map_count, &maps,
+ &hbac_count, &hbac_rules,
&default_user, &map_order);
if (ret != EOK) {
goto fail;
}
+ ret = ipa_selinux_process_maps(op_ctx->user, op_ctx->host,
+ maps, map_count,
+ hbac_rules, hbac_count);
+ if (ret != EOK) {
+ goto fail;
+ }
+
ret = sysdb_transaction_start(sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
@@ -153,11 +237,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req)
DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n"));
goto fail;
}
-
- /* Just in case more code will follow after this place in the future */
in_transaction = false;
-
pd->pam_status = PAM_SUCCESS;
breq->fn(breq, DP_ERR_OK, EOK, "Success");
return;
@@ -176,9 +257,195 @@ fail:
}
}
-static struct tevent_req *ipa_get_selinux_send(struct be_req *breq,
- struct pam_data *pd,
- struct ipa_selinux_ctx *selinux_ctx)
+static errno_t
+ipa_selinux_process_seealso_maps(struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct sysdb_attrs **seealso_rules,
+ size_t seealso_rules_count,
+ struct sysdb_attrs **hbac_rules,
+ size_t hbac_rule_count);
+static errno_t
+ipa_selinux_process_maps(struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct sysdb_attrs **selinux_maps,
+ size_t selinux_map_count,
+ struct sysdb_attrs **hbac_rules,
+ size_t hbac_rule_count)
+{
+ TALLOC_CTX *tmp_ctx;
+ int i;
+ errno_t ret;
+ uint32_t priority = 0;
+ struct sysdb_attrs **seealso_rules;
+ size_t num_seealso_rules;
+ const char *seealso_str;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ seealso_rules = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
+ selinux_map_count + 1);
+ if (seealso_rules == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ num_seealso_rules = 0;
+
+ for (i = 0; i < selinux_map_count; i++) {
+ if (sss_selinux_match(selinux_maps[i], user,
+ host, &priority)) {
+ priority &= ~(SELINUX_PRIORITY_USER_NAME |
+ SELINUX_PRIORITY_USER_GROUP |
+ SELINUX_PRIORITY_USER_CAT);
+ ret = sysdb_attrs_add_uint32(selinux_maps[i],
+ SYSDB_SELINUX_HOST_PRIORITY,
+ priority);
+ if (ret != EOK) {
+ goto done;
+ }
+ continue;
+ }
+
+ ret = sysdb_attrs_get_string(selinux_maps[i],
+ SYSDB_SELINUX_SEEALSO, &seealso_str);
+ if (ret == ENOENT) {
+ continue;
+ } else if (ret != EOK) {
+ goto done;
+ }
+
+ seealso_rules[num_seealso_rules] = selinux_maps[i];
+ num_seealso_rules++;
+ }
+
+ ret = ipa_selinux_process_seealso_maps(user, host,
+ seealso_rules, num_seealso_rules,
+ hbac_rules, hbac_rule_count);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t
+ipa_selinux_process_seealso_maps(struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct sysdb_attrs **seealso_rules,
+ size_t seealso_rules_count,
+ struct sysdb_attrs **hbac_rules,
+ size_t hbac_rule_count)
+{
+ int i, j;
+ errno_t ret;
+ struct ldb_message_element *el;
+ uint32_t priority = 0;
+ struct sysdb_attrs *usermap;
+ const char *seealso_dn;
+ const char *hbac_dn;
+
+ for (i = 0; i < hbac_rule_count; i++) {
+ ret = sysdb_attrs_get_string(hbac_rules[i], SYSDB_ORIG_DN, &hbac_dn);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* We need to do this translation for further processing. We have to
+ * do it manually because no map was used to retrieve HBAC rules.
+ */
+ ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_HOST, &el);
+ if (ret != EOK) return ret;
+ el->name = SYSDB_ORIG_MEMBER_HOST;
+
+ ret = sysdb_attrs_get_el(hbac_rules[i], IPA_MEMBER_USER, &el);
+ if (ret != EOK) return ret;
+ el->name = SYSDB_ORIG_MEMBER_USER;
+
+ DEBUG(SSSDBG_TRACE_ALL,
+ ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn));
+
+ if (!sss_selinux_match(hbac_rules[i], user, host, &priority)) {
+ DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n"));
+ continue;
+ }
+
+ /* HBAC rule matched, find if it is in the "possible" list */
+ for (j = 0; j < seealso_rules_count; j++) {
+ usermap = seealso_rules[j];
+ if (usermap == NULL) {
+ continue;
+ }
+
+ ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (strcasecmp(hbac_dn, seealso_dn) == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its"
+ "attributes to SELinux user map [%s]\n",
+ hbac_dn, seealso_dn));
+ priority &= ~(SELINUX_PRIORITY_USER_NAME |
+ SELINUX_PRIORITY_USER_GROUP |
+ SELINUX_PRIORITY_USER_CAT);
+ ret = sysdb_attrs_add_uint32(usermap,
+ SYSDB_SELINUX_HOST_PRIORITY,
+ priority);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_ORIG_MEMBER_USER);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_USER_CATEGORY);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* Speed up the next iteration */
+ seealso_rules[j] = NULL;
+ }
+ }
+ }
+
+ return EOK;
+}
+
+/* A more generic request to gather all SELinux and HBAC rules. Updates
+ * cache if necessary
+ */
+struct ipa_get_selinux_state {
+ struct be_req *be_req;
+ struct ipa_selinux_ctx *selinux_ctx;
+ struct sdap_id_op *op;
+
+ struct sysdb_attrs *host;
+ struct sysdb_attrs *user;
+
+ struct sysdb_attrs *defaults;
+ struct sysdb_attrs **selinuxmaps;
+ size_t nmaps;
+
+ struct sysdb_attrs **hbac_rules;
+ size_t hbac_rule_count;
+};
+
+static errno_t
+ipa_get_selinux_maps_offline(struct tevent_req *req);
+
+static struct tevent_req *
+ipa_get_selinux_send(struct be_req *breq,
+ struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct ipa_selinux_ctx *selinux_ctx)
{
struct tevent_req *req;
struct tevent_req *subreq;
@@ -194,8 +461,9 @@ static struct tevent_req *ipa_get_selinux_send(struct be_req *breq,
}
state->be_req = breq;
- state->pd = pd;
state->selinux_ctx = selinux_ctx;
+ state->user = user;
+ state->host = host;
offline = be_is_offline(bctx);
DEBUG(SSSDBG_TRACE_INTERNAL, ("Connection status is [%s].\n",
@@ -219,7 +487,7 @@ static struct tevent_req *ipa_get_selinux_send(struct be_req *breq,
tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req);
} else {
- ret = EAGAIN;
+ ret = ipa_get_selinux_maps_offline(req);
goto immediate;
}
@@ -248,67 +516,45 @@ static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
const char *access_name;
const char *selinux_name;
- struct ldb_dn *host_dn;
- const char *attrs[] = { SYSDB_ORIG_DN,
- SYSDB_ORIG_MEMBEROF,
- NULL };
- size_t count;
- struct ldb_message **msgs;
- struct sysdb_attrs **hosts;
+ const char *hostname;
ret = sdap_id_op_connect_recv(subreq, &dp_error);
talloc_zfree(subreq);
if (dp_error == DP_ERR_OFFLINE) {
talloc_zfree(state->op);
- ret = EAGAIN;
+ ret = ipa_get_selinux_maps_offline(req);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ return;
+ }
+ goto fail;
}
if (ret != EOK) {
goto fail;
}
- state->hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic,
- IPA_HOSTNAME);
-
access_name = state->be_req->be_ctx->bet_info[BET_ACCESS].mod_name;
selinux_name = state->be_req->be_ctx->bet_info[BET_SELINUX].mod_name;
- if (strcasecmp(access_name, selinux_name) == 0) {
- host_dn = sysdb_custom_dn(bctx->sysdb, state, state->hostname, HBAC_HOSTS_SUBDIR);
- if (host_dn == NULL) {
- ret = ENOMEM;
- goto fail;
- }
-
- /* Look up the host to get its originalMemberOf entries */
- ret = sysdb_search_entry(state, bctx->sysdb, host_dn,
- LDB_SCOPE_BASE, NULL,
- attrs, &count, &msgs);
- if (ret == ENOENT || count == 0) {
- /* We need to query the server */
- goto server;
- } else if (ret != EOK) {
- goto fail;
- } else if (count > 1) {
- DEBUG(SSSDBG_OP_FAILURE, ("More than one result for a BASE search!\n"));
- ret = EIO;
- goto fail;
- }
-
- ret = sysdb_msg2attrs(state, count, msgs, &hosts);
- if (ret != EOK) {
- goto fail;
- }
-
- state->host = hosts[0];
+ if (strcasecmp(access_name, selinux_name) == 0 && state->host != NULL) {
+ /* If the access control module is the same as the selinux module
+ * and the access control had already discovered the host
+ */
return ipa_get_config_step(req);
}
-server:
+ hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic,
+ IPA_HOSTNAME);
+ if (hostname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot determine the host name\n"));
+ goto fail;
+ }
+
subreq = ipa_host_info_send(state, bctx->ev, bctx->sysdb,
sdap_id_op_handle(state->op),
id_ctx->sdap_id_ctx->opts,
- state->hostname,
+ hostname,
id_ctx->ipa_options->host_map,
NULL,
state->selinux_ctx->host_search_bases);
@@ -318,13 +564,92 @@ server:
}
tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req);
-
return;
fail:
tevent_req_error(req, ret);
}
+static errno_t
+ipa_get_selinux_maps_offline(struct tevent_req *req)
+{
+ errno_t ret;
+ size_t nmaps;
+ struct ldb_message **maps;
+ struct ldb_message *defaults;
+ const char *attrs[] = { SYSDB_NAME,
+ SYSDB_USER_CATEGORY,
+ SYSDB_HOST_CATEGORY,
+ SYSDB_ORIG_MEMBER_USER,
+ SYSDB_ORIG_MEMBER_HOST,
+ SYSDB_SELINUX_SEEALSO,
+ SYSDB_SELINUX_USER,
+ NULL };
+ const char *default_user;
+ const char *order;
+
+ struct ipa_get_selinux_state *state = tevent_req_data(req,
+ struct ipa_get_selinux_state);
+
+ /* read the config entry */
+ ret = sysdb_search_selinux_config(state, state->be_req->be_ctx->sysdb,
+ NULL, &defaults);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_selinux_config failed [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ default_user = ldb_msg_find_attr_as_string(defaults,
+ SYSDB_SELINUX_DEFAULT_USER,
+ NULL);
+ order = ldb_msg_find_attr_as_string(defaults, SYSDB_SELINUX_DEFAULT_ORDER,
+ NULL);
+
+ state->defaults = sysdb_new_attrs(state);
+ if (state->defaults == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_attrs_add_string(state->defaults,
+ IPA_CONFIG_SELINUX_DEFAULT_MAP, default_user);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sysdb_attrs_add_string(state->defaults,
+ IPA_CONFIG_SELINUX_MAP_ORDER, order);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* read all the SELinux rules */
+ ret = sysdb_get_selinux_usermaps(state, state->be_req->be_ctx->sysdb,
+ attrs, &nmaps, &maps);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_get_selinux_usermaps failed [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ ret = sysdb_msg2attrs(state, nmaps, maps, &state->selinuxmaps);
+ if (ret != EOK) {
+ return ret;
+ }
+ state->nmaps = nmaps;
+
+ /* read all the HBAC rules */
+ ret = hbac_get_cached_rules(state, state->be_req->be_ctx->sysdb,
+ &state->hbac_rule_count, &state->hbac_rules);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("hbac_get_cached_rules failed [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ return EOK;
+}
+
static void ipa_get_selinux_hosts_done(struct tevent_req *subreq)
{
errno_t ret;
@@ -354,7 +679,6 @@ done:
static void ipa_get_config_step(struct tevent_req *req)
{
- errno_t ret;
const char *domain;
struct tevent_req *subreq;
struct ipa_get_selinux_state *state = tevent_req_data(req,
@@ -362,13 +686,6 @@ static void ipa_get_config_step(struct tevent_req *req)
struct be_ctx *bctx = state->be_req->be_ctx;
struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx;
- ret = sss_selinux_extract_user(state, bctx->sysdb,
- state->pd->user, &state->user);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
domain = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic,
IPA_KRB5_REALM);
subreq = ipa_get_config_send(state, bctx->ev,
@@ -428,11 +745,9 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
char *selinux_name;
char *access_name;
- struct sysdb_attrs **rules;
- size_t rule_count;
const char *tmp_str;
- uint32_t priority = 0;
+ bool check_hbac;
errno_t ret;
int i;
@@ -456,54 +771,29 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_FUNC,
("Found %d SELinux user maps\n", state->nmaps));
- state->possible_match = talloc_zero_array(state, struct sysdb_attrs *,
- state->nmaps + 1);
- if (state->possible_match == NULL) {
- ret = ENOMEM;
- goto done;
- }
+ check_hbac = false;
for (i = 0; i < state->nmaps; i++) {
- if (sss_selinux_match(state->selinuxmaps[i], state->user,
- state->host, &priority)) {
- priority &= ~(SELINUX_PRIORITY_USER_NAME |
- SELINUX_PRIORITY_USER_GROUP |
- SELINUX_PRIORITY_USER_CAT);
- ret = sysdb_attrs_add_uint32(state->selinuxmaps[i],
- SYSDB_SELINUX_HOST_PRIORITY,
- priority);
- if (ret != EOK) {
- goto done;
- }
- continue;
- }
-
ret = sysdb_attrs_get_string(state->selinuxmaps[i],
SYSDB_SELINUX_SEEALSO, &tmp_str);
- if (ret == ENOENT) {
- continue;
+ if (ret == EOK) {
+ check_hbac = true;
+ break;
}
-
- state->possible_match[state->possible_matches] = state->selinuxmaps[i];
- state->possible_matches++;
}
- if (state->possible_matches) {
+ if (check_hbac) {
access_name = state->be_req->be_ctx->bet_info[BET_ACCESS].mod_name;
selinux_name = state->be_req->be_ctx->bet_info[BET_SELINUX].mod_name;
if (strcasecmp(access_name, selinux_name) == 0) {
ret = hbac_get_cached_rules(state, state->be_req->be_ctx->sysdb,
- &rule_count, &rules);
- if (ret != EOK) {
- goto done;
- }
-
- ret = ipa_get_selinux_hbac_process(state, rules, rule_count);
+ &state->hbac_rule_count, &state->hbac_rules);
+ /* Terminates the request */
goto done;
}
- DEBUG(SSSDBG_TRACE_FUNC, ("%d SELinux maps referenced an HBAC rule. "
- "Need to refresh HBAC rules\n", state->possible_matches));
+ DEBUG(SSSDBG_TRACE_FUNC, ("SELinux maps referenced an HBAC rule. "
+ "Need to refresh HBAC rules\n"));
subreq = ipa_hbac_rule_info_send(state, false, bctx->ev,
sdap_id_op_handle(state->op),
id_ctx->sdap_id_ctx->opts,
@@ -533,22 +823,14 @@ static void ipa_get_selinux_hbac_done(struct tevent_req *subreq)
struct tevent_req);
struct ipa_get_selinux_state *state = tevent_req_data(req,
struct ipa_get_selinux_state);
- struct sysdb_attrs **rules;
- size_t rule_count;
errno_t ret;
- ret = ipa_hbac_rule_info_recv(subreq, state, &rule_count,
- &rules);
+ ret = ipa_hbac_rule_info_recv(subreq, state, &state->hbac_rule_count,
+ &state->hbac_rules);
DEBUG(SSSDBG_TRACE_INTERNAL,
- ("Received %d HBAC rules\n", rule_count));
+ ("Received %d HBAC rules\n", state->hbac_rule_count));
talloc_free(subreq);
- if (ret != EOK) {
- goto done;
- }
- ret = ipa_get_selinux_hbac_process(state, rules, rule_count);
-
-done:
if (ret != EOK) {
tevent_req_error(req, ret);
} else {
@@ -556,100 +838,13 @@ done:
}
}
-static int
-ipa_get_selinux_hbac_process(struct ipa_get_selinux_state *state,
- struct sysdb_attrs **rules,
- size_t rule_count)
-{
- int i, j;
- errno_t ret;
- uint32_t priority = 0;
- const char *hbac_dn;
- const char *seealso_dn;
- struct sysdb_attrs *usermap;
- struct ldb_message_element *el;
-
- for (i = 0; i < rule_count; i++) {
- ret = sysdb_attrs_get_string(rules[i], SYSDB_ORIG_DN, &hbac_dn);
- if (ret != EOK) {
- goto done;
- }
-
- /* We need to do this translation for further processing. We have to
- * do it manually because no map was used to retrieve HBAC rules.
- */
- ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_HOST, &el);
- if (ret != EOK) goto done;
- el->name = SYSDB_ORIG_MEMBER_HOST;
-
- ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_USER, &el);
- if (ret != EOK) goto done;
- el->name = SYSDB_ORIG_MEMBER_USER;
-
- DEBUG(SSSDBG_TRACE_ALL,
- ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn));
-
- if (!sss_selinux_match(rules[i], state->user, state->host, &priority)) {
- DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n"));
- continue;
- }
-
-
- /* HBAC rule matched, find if it is in the "possible" list */
- for (j = 0; j < state->possible_matches; j++) {
- usermap = state->possible_match[j];
- if (usermap == NULL) {
- continue;
- }
-
- ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn);
- if (ret != EOK) {
- goto done;
- }
-
- if (strcasecmp(hbac_dn, seealso_dn) == 0) {
- DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its"
- "attributes to SELinux user map [%s]\n",
- hbac_dn, seealso_dn));
- priority &= ~(SELINUX_PRIORITY_USER_NAME |
- SELINUX_PRIORITY_USER_GROUP |
- SELINUX_PRIORITY_USER_CAT);
- ret = sysdb_attrs_add_uint32(usermap,
- SYSDB_SELINUX_HOST_PRIORITY,
- priority);
- if (ret != EOK) {
- goto done;
- }
-
- ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_ORIG_MEMBER_USER);
- if (ret != EOK) {
- goto done;
- }
-
- ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_USER_CATEGORY);
- if (ret != EOK) {
- goto done;
- }
-
- /* Just to boost the following lookup */
- state->possible_match[j] = NULL;
- }
- }
- }
-
- /* Now we can dispose all possible rules, since they aren't possible any more */
- talloc_zfree(state->possible_match);
-
- ret = EOK;
-done:
- return ret;
-}
-
static errno_t
ipa_get_selinux_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *count,
struct sysdb_attrs ***maps,
+ size_t *hbac_count,
+ struct sysdb_attrs ***hbac_rules,
char **default_user,
char **map_order)
{
@@ -698,5 +893,13 @@ ipa_get_selinux_recv(struct tevent_req *req,
*maps = NULL;
}
+ if (state->hbac_rules != NULL) {
+ *hbac_count = state->hbac_rule_count;
+ *hbac_rules = talloc_steal(mem_ctx, state->hbac_rules);
+ } else {
+ *hbac_count = 0;
+ *hbac_rules = NULL;
+ }
+
return EOK;
}
--
1.8.0.2
-------------- next part --------------
>From 3e133f3a23e328df1e8d01b65a9cb648643c1e93 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 23:58:04 +0100
Subject: [PATCH 4/4] IPA: Rename IPA_CONFIG_SELINUX_DEFAULT_MAP
It is not a map, but a default context. The name should reflect that.
---
src/providers/ipa/ipa_config.c | 2 +-
src/providers/ipa/ipa_config.h | 2 +-
src/providers/ipa/ipa_selinux.c | 6 ++++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/providers/ipa/ipa_config.c b/src/providers/ipa/ipa_config.c
index 25f1e37bc2b7ea030bd429a1e7125f86b548ad27..05231cc763c28c2867688530a6d4c17d2fd30933 100644
--- a/src/providers/ipa/ipa_config.c
+++ b/src/providers/ipa/ipa_config.c
@@ -61,7 +61,7 @@ ipa_get_config_send(TALLOC_CTX *mem_ctx,
goto done;
}
state->attrs[0] = IPA_CONFIG_MIGRATION_ENABLED;
- state->attrs[1] = IPA_CONFIG_SELINUX_DEFAULT_MAP;
+ state->attrs[1] = IPA_CONFIG_SELINUX_DEFAULT_USER_CTX;
state->attrs[2] = IPA_CONFIG_SELINUX_MAP_ORDER;
state->attrs[3] = NULL;
} else {
diff --git a/src/providers/ipa/ipa_config.h b/src/providers/ipa/ipa_config.h
index 9a25984b6e3736a1d2b977b882dea2fc45f08606..2f1e147d7edab0aca2a16269c6a73bc607b21bd5 100644
--- a/src/providers/ipa/ipa_config.h
+++ b/src/providers/ipa/ipa_config.h
@@ -31,7 +31,7 @@
#include "providers/ldap/ldap_common.h"
#include "db/sysdb.h"
-#define IPA_CONFIG_SELINUX_DEFAULT_MAP "ipaSELinuxUserMapDefault"
+#define IPA_CONFIG_SELINUX_DEFAULT_USER_CTX "ipaSELinuxUserMapDefault"
#define IPA_CONFIG_SELINUX_MAP_ORDER "ipaSELinuxUserMapOrder"
#define IPA_CONFIG_MIGRATION_ENABLED "ipaMigrationEnabled"
#define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s"
diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
index 909ef056cbccca80bcc512e3fca858b1f4577c51..d1dbe576589d311dbaf2b589cb88eb61083e882a 100644
--- a/src/providers/ipa/ipa_selinux.c
+++ b/src/providers/ipa/ipa_selinux.c
@@ -612,7 +612,8 @@ ipa_get_selinux_maps_offline(struct tevent_req *req)
}
ret = sysdb_attrs_add_string(state->defaults,
- IPA_CONFIG_SELINUX_DEFAULT_MAP, default_user);
+ IPA_CONFIG_SELINUX_DEFAULT_USER_CTX,
+ default_user);
if (ret != EOK) {
return ret;
}
@@ -856,7 +857,8 @@ ipa_get_selinux_recv(struct tevent_req *req,
TEVENT_REQ_RETURN_ON_ERROR(req);
if (state->defaults != NULL) {
- ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_DEFAULT_MAP,
+ ret = sysdb_attrs_get_string(state->defaults,
+ IPA_CONFIG_SELINUX_DEFAULT_USER_CTX,
&tmp_str);
if (ret != EOK && ret != ENOENT) {
return ret;
--
1.8.0.2
More information about the sssd-devel
mailing list