summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Zeleny <jzeleny@redhat.com>2012-02-05 15:59:20 -0500
committerStephen Gallagher <sgallagh@redhat.com>2012-02-06 08:25:22 -0500
commit1a853121ca2ba8ede6df429ee76942131ffb0f65 (patch)
treeb724db01bf92a61809c25a62c634f0e8da5dc257
parent2d0550acbe07024d034fb616c1ec5b81929c4844 (diff)
downloadsssd-1a853121ca2ba8ede6df429ee76942131ffb0f65.tar.gz
sssd-1a853121ca2ba8ede6df429ee76942131ffb0f65.tar.xz
sssd-1a853121ca2ba8ede6df429ee76942131ffb0f65.zip
Session target in IPA provider
-rw-r--r--Makefile.am6
-rw-r--r--src/providers/ipa/ipa_common.c47
-rw-r--r--src/providers/ipa/ipa_common.h17
-rw-r--r--src/providers/ipa/ipa_init.c42
-rw-r--r--src/providers/ipa/ipa_selinux_common.c103
-rw-r--r--src/providers/ipa/ipa_selinux_common.h39
-rw-r--r--src/providers/ipa/ipa_selinux_maps.c217
-rw-r--r--src/providers/ipa/ipa_selinux_maps.h44
-rw-r--r--src/providers/ipa/ipa_session.c616
-rw-r--r--src/providers/ipa/ipa_session.h40
-rw-r--r--src/providers/ldap/sdap.h1
11 files changed, 1172 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 388edb7c0..c0b4c7000 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -361,7 +361,10 @@ dist_noinst_HEADERS = \
src/providers/ipa/ipa_common.h \
src/providers/ipa/ipa_config.h \
src/providers/ipa/ipa_access.h \
+ src/providers/ipa/ipa_session.h \
src/providers/ipa/ipa_hosts.h \
+ src/providers/ipa/ipa_selinux_common.h \
+ src/providers/ipa/ipa_selinux_maps.h \
src/providers/ipa/ipa_auth.h \
src/providers/ipa/ipa_dyndns.h \
src/providers/ipa/ipa_id.h \
@@ -1080,6 +1083,9 @@ libsss_ipa_la_SOURCES = \
src/providers/ipa/ipa_hbac_services.c \
src/providers/ipa/ipa_hbac_users.c \
src/providers/ipa/ipa_hbac_common.c \
+ src/providers/ipa/ipa_session.c \
+ src/providers/ipa/ipa_selinux_maps.c \
+ src/providers/ipa/ipa_selinux_common.c \
src/providers/ldap/ldap_id.c \
src/providers/ldap/ldap_id_enum.c \
src/providers/ldap/ldap_id_cleanup.c \
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 58db9e78d..02485b801 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <arpa/inet.h>
+#include "db/sysdb_selinux.h"
#include "providers/ipa/ipa_common.h"
#include "providers/ldap/sdap_async_private.h"
#include "util/sss_krb5.h"
@@ -39,6 +40,7 @@ struct dp_option ipa_basic_opts[] = {
{ "ipa_dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING},
{ "ipa_hbac_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING},
{ "ipa_host_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ipa_selinux_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING},
{ "ipa_hbac_refresh", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER },
{ "ipa_hbac_treat_deny_as", DP_OPT_STRING, { "DENY_ALL" }, NULL_STRING },
@@ -181,6 +183,19 @@ struct sdap_attr_map ipa_host_map[] = {
{ "ipa_host_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
};
+static struct sdap_attr_map ipa_selinux_user_map[] = {
+ {"ipa_selinux_usermap_object_class", "ipaselinuxusermap", SYSDB_SELINUX_USERMAP_CLASS, NULL},
+ {"ipa_selinux_usermap_name", "cn", SYSDB_NAME, NULL},
+ {"ipa_selinux_usermap_member_user", "memberUser", SYSDB_ORIG_MEMBER_USER, NULL},
+ {"ipa_selinux_usermap_member_host", "memberHost", SYSDB_ORIG_MEMBER_HOST, NULL},
+ {"ipa_selinux_usermap_see_also", "seeAlso", SYSDB_SELINUX_SEEALSO, NULL},
+ {"ipa_selinux_usermap_selinux_user", "ipaSELinuxUser", SYSDB_SELINUX_USER, NULL},
+ {"ipa_selinux_usermap_enabled", "ipaEnabledFlag", SYSDB_SELINUX_ENABLED, NULL},
+ {"ipa_selinux_usermap_user_category", "userCategory", SYSDB_USER_CATEGORY, NULL},
+ {"ipa_selinux_usermap_host_category", "hostCategory", SYSDB_HOST_CATEGORY, NULL},
+ {"ipa_selinux_usermap_uuid", "ipaUniqueID", SYSDB_UUID, NULL}
+};
+
struct dp_option ipa_def_krb5_opts[] = {
{ "krb5_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
@@ -605,6 +620,29 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
&ipa_opts->hbac_search_bases);
if (ret != EOK) goto done;
+ if (NULL == dp_opt_get_string(ipa_opts->basic,
+ IPA_SELINUX_SEARCH_BASE)) {
+ value = talloc_asprintf(tmpctx, "cn=selinux,%s", basedn);
+ if (!value) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dp_opt_set_string(ipa_opts->basic, IPA_SELINUX_SEARCH_BASE, value);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS, ("Option %s set to %s\n",
+ ipa_opts->basic[IPA_SELINUX_SEARCH_BASE].opt_name,
+ dp_opt_get_string(ipa_opts->basic,
+ IPA_SELINUX_SEARCH_BASE)));
+ }
+ ret = sdap_parse_search_base(ipa_opts->basic, ipa_opts->basic,
+ IPA_SELINUX_SEARCH_BASE,
+ &ipa_opts->selinux_search_bases);
+ if (ret != EOK) goto done;
+
value = dp_opt_get_string(ipa_opts->id->basic, SDAP_DEREF);
if (value != NULL) {
ret = deref_string_to_val(value, &i);
@@ -686,6 +724,15 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
goto done;
}
+ ret = sdap_get_map(ipa_opts->id,
+ cdb, conf_path,
+ ipa_selinux_user_map,
+ IPA_OPTS_SELINUX_USERMAP,
+ &ipa_opts->id->selinuxuser_map);
+ if (ret != EOK) {
+ goto done;
+ }
+
ret = EOK;
*_opts = ipa_opts->id;
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 49afe74db..6be972966 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -52,6 +52,7 @@ enum ipa_basic_opt {
IPA_DYNDNS_IFACE,
IPA_HBAC_SEARCH_BASE,
IPA_HOST_SEARCH_BASE,
+ IPA_SELINUX_SEARCH_BASE,
IPA_KRB5_REALM,
IPA_HBAC_REFRESH,
IPA_HBAC_DENY_METHOD,
@@ -82,6 +83,21 @@ enum ipa_host_attrs {
IPA_OPTS_HOST /* attrs counter */
};
+enum ipa_selinux_usermap_attrs {
+ IPA_OC_SELINUX_USERMAP = 0,
+ IPA_AT_SELINUX_USERMAP_NAME,
+ IPA_AT_SELINUX_USERMAP_MEMBER_USER,
+ IPA_AT_SELINUX_USERMAP_MEMBER_HOST,
+ IPA_AT_SELINUX_USERMAP_SEE_ALSO,
+ IPA_AT_SELINUX_USERMAP_SELINUX_USER,
+ IPA_AT_SELINUX_USERMAP_ENABLED,
+ IPA_AT_SELINUX_USERMAP_USERCAT,
+ IPA_AT_SELINUX_USERMAP_HOSTCAT,
+ IPA_AT_SELINUX_USERMAP_UUID,
+
+ IPA_OPTS_SELINUX_USERMAP /* attrs counter */
+};
+
struct ipa_auth_ctx {
struct krb5_ctx *krb5_auth_ctx;
struct sdap_id_ctx *sdap_id_ctx;
@@ -99,6 +115,7 @@ struct ipa_options {
struct sdap_search_base **host_search_bases;
struct sdap_search_base **hbac_search_bases;
+ struct sdap_search_base **selinux_search_bases;
struct ipa_service *service;
/* id provider */
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index b3544f749..0484200cd 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -34,6 +34,7 @@
#include "providers/ipa/ipa_auth.h"
#include "providers/ipa/ipa_access.h"
#include "providers/ipa/ipa_dyndns.h"
+#include "providers/ipa/ipa_session.h"
struct ipa_options *ipa_options = NULL;
@@ -59,6 +60,11 @@ struct bet_ops ipa_access_ops = {
.finalize = NULL
};
+struct bet_ops ipa_session_ops = {
+ .handler = ipa_session_handler,
+ .finalize = NULL
+};
+
int common_ipa_init(struct be_ctx *bectx)
{
const char *ipa_servers;
@@ -393,3 +399,39 @@ done:
}
return ret;
}
+
+int sssm_ipa_session_init(struct be_ctx *bectx,
+ struct bet_ops **ops,
+ void **pvt_data)
+{
+ int ret;
+ struct ipa_session_ctx *session_ctx;
+ struct ipa_options *opts;
+
+ session_ctx = talloc_zero(bectx, struct ipa_session_ctx);
+ if (session_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n"));
+ return ENOMEM;
+ }
+
+ ret = sssm_ipa_id_init(bectx, ops, (void **) &session_ctx->id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ipa_id_init failed.\n"));
+ goto done;
+ }
+
+ opts = session_ctx->id_ctx->ipa_options;
+
+ session_ctx->hbac_search_bases = opts->hbac_search_bases;
+ session_ctx->host_search_bases = opts->host_search_bases;
+ session_ctx->selinux_search_bases = opts->selinux_search_bases;
+
+ *ops = &ipa_session_ops;
+ *pvt_data = session_ctx;
+
+done:
+ if (ret != EOK) {
+ talloc_free(session_ctx);
+ }
+ return ret;
+}
diff --git a/src/providers/ipa/ipa_selinux_common.c b/src/providers/ipa/ipa_selinux_common.c
new file mode 100644
index 000000000..15f0b4588
--- /dev/null
+++ b/src/providers/ipa/ipa_selinux_common.c
@@ -0,0 +1,103 @@
+/*
+ SSSD
+
+ IPA Backend Module -- SELinux common routines
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "db/sysdb_selinux.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ipa/ipa_selinux_common.h"
+
+
+errno_t ipa_selinux_map_merge(struct sysdb_attrs *map,
+ struct sysdb_attrs *rule,
+ const char *attr)
+{
+ struct ldb_message_element *map_el;
+ struct ldb_message_element *rule_el;
+ size_t total_cnt;
+ errno_t ret;
+ int i = 0;
+
+ ret = sysdb_attrs_get_el(map, attr, &map_el);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_el(rule, attr, &rule_el);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ total_cnt = map_el->num_values + rule_el->num_values;
+ map_el->values = talloc_realloc(map->a, map_el->values,
+ struct ldb_val, total_cnt);
+ if (map_el->values == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ while (map_el->num_values < total_cnt)
+ {
+ map_el->values[map_el->num_values] = ldb_val_dup(map_el->values,
+ &rule_el->values[i]);
+ map_el->num_values++;
+ i++;
+ }
+
+ ret = EOK;
+done:
+ return ret;
+}
+
+errno_t ipa_save_user_maps(struct sysdb_ctx *sysdb,
+ size_t map_count,
+ struct sysdb_attrs **maps)
+{
+ errno_t ret;
+ int i;
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret) {
+ goto done;
+ }
+
+ for (i = 0; i < map_count; i++) {
+ ret = sysdb_store_selinux_usermap(sysdb, maps[i]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Failed to store user map %d. "
+ "Ignoring.\n", i));
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC, ("User map %d processed.\n", i));
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction!\n"));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
diff --git a/src/providers/ipa/ipa_selinux_common.h b/src/providers/ipa/ipa_selinux_common.h
new file mode 100644
index 000000000..17ccb2312
--- /dev/null
+++ b/src/providers/ipa/ipa_selinux_common.h
@@ -0,0 +1,39 @@
+/*
+ SSSD
+
+ IPA Backend Module -- SELinux common routines
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef IPA_SELINUX_COMMON_H_
+#define IPA_SELINUX_COMMON_H_
+
+errno_t ipa_selinux_map_merge(struct sysdb_attrs *map,
+ struct sysdb_attrs *rule,
+ const char *attr);
+
+errno_t ipa_save_host(struct sysdb_ctx *sysdb,
+ struct sysdb_attrs *host);
+
+errno_t ipa_save_user_maps(struct sysdb_ctx *sysdb,
+ size_t map_count,
+ struct sysdb_attrs **maps);
+
+#endif /* IPA_SELINUX_COMMON_H_ */
diff --git a/src/providers/ipa/ipa_selinux_maps.c b/src/providers/ipa/ipa_selinux_maps.c
new file mode 100644
index 000000000..87650f6ce
--- /dev/null
+++ b/src/providers/ipa/ipa_selinux_maps.c
@@ -0,0 +1,217 @@
+/*
+ SSSD
+
+ IPA Backend Module -- SELinux user maps (maps retrieval)
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "providers/ipa/ipa_common.h"
+#include "providers/ipa/ipa_selinux_maps.h"
+
+struct ipa_selinux_get_maps_state {
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct sdap_handle *sh;
+ struct sdap_options *opts;
+ const char **attrs;
+
+ struct sdap_search_base **search_bases;
+ int search_base_iter;
+
+ char *cur_filter;
+ char *maps_filter;
+
+ size_t map_count;
+ struct sysdb_attrs **maps;
+};
+
+static errno_t
+ipa_selinux_get_maps_next(struct tevent_req *req,
+ struct ipa_selinux_get_maps_state *state);
+static void
+ipa_selinux_get_maps_done(struct tevent_req *subreq);
+
+struct tevent_req *ipa_selinux_get_maps_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ struct sdap_options *opts,
+ struct sdap_search_base **search_bases)
+{
+ struct tevent_req *req;
+ struct ipa_selinux_get_maps_state *state;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ipa_selinux_get_maps_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->sysdb = sysdb;
+ state->sh = sh;
+ state->opts = opts;
+ state->search_bases = search_bases;
+ state->search_base_iter = 0;
+ state->map_count = 0;
+ state->maps = NULL;
+
+ ret = build_attrs_from_map(state, opts->selinuxuser_map,
+ IPA_OPTS_SELINUX_USERMAP, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ state->cur_filter = NULL;
+ state->maps_filter = talloc_asprintf(state,
+ "(&(objectclass=%s)(%s=TRUE))",
+ opts->selinuxuser_map[IPA_OC_SELINUX_USERMAP].name,
+ opts->selinuxuser_map[IPA_AT_SELINUX_USERMAP_ENABLED].name);
+ if (state->maps_filter == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = ipa_selinux_get_maps_next(req, state);
+ if (ret == EOK) {
+ ret = EINVAL;
+ }
+
+ if (ret != EAGAIN) {
+ goto fail;
+ }
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t
+ipa_selinux_get_maps_next(struct tevent_req *req,
+ struct ipa_selinux_get_maps_state *state)
+{
+ struct sdap_search_base *base;
+ struct tevent_req *subreq;
+
+ base = state->search_bases[state->search_base_iter];
+ if (base == NULL) {
+ return EOK;
+ }
+
+ talloc_zfree(state->cur_filter);
+ state->cur_filter = sdap_get_id_specific_filter(state, state->maps_filter,
+ base->filter);
+ if (state->cur_filter == NULL) {
+ return ENOMEM;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Trying to fetch SELinux maps with following "
+ "parameters: [%d][%s][%s]\n", base->scope,
+ base->filter, base->basedn));
+ subreq = sdap_get_generic_send(state, state->ev, state->opts,
+ state->sh, base->basedn,
+ base->scope, state->cur_filter,
+ state->attrs,
+ state->opts->selinuxuser_map,
+ IPA_OPTS_SELINUX_USERMAP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_ENUM_SEARCH_TIMEOUT));
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, ipa_selinux_get_maps_done, req);
+ return EAGAIN;
+}
+
+static void ipa_selinux_get_maps_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_selinux_get_maps_state *state = tevent_req_data(req,
+ struct ipa_selinux_get_maps_state);
+ struct sysdb_attrs **results;
+ size_t total_count;
+ size_t count;
+ int i;
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &results);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (count > 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("Found %d user maps in current search base\n",
+ count));
+
+ total_count = count + state->map_count;
+ state->maps = talloc_realloc(state, state->maps, struct sysdb_attrs *, total_count);
+ if (state->maps == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ i = 0;
+ while (state->map_count < total_count) {
+ state->maps[state->map_count] = talloc_steal(state->maps, results[i]);
+ state->map_count++;
+ i++;
+ }
+ }
+
+ state->search_base_iter++;
+ ret = ipa_selinux_get_maps_next(req, state);
+ if (ret == EAGAIN) {
+ return;
+ } else if (ret != EOK) {
+ goto done;
+ }
+
+ if (state->map_count == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("No SELinux user maps found!\n"));
+ ret = ENOENT;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ tevent_req_done(req);
+ }
+}
+
+errno_t
+ipa_selinux_get_maps_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *count,
+ struct sysdb_attrs ***maps)
+{
+ struct ipa_selinux_get_maps_state *state =
+ tevent_req_data(req, struct ipa_selinux_get_maps_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *count = state->map_count;
+ *maps = talloc_steal(mem_ctx, state->maps);
+
+ return EOK;
+}
diff --git a/src/providers/ipa/ipa_selinux_maps.h b/src/providers/ipa/ipa_selinux_maps.h
new file mode 100644
index 000000000..efd10bf4e
--- /dev/null
+++ b/src/providers/ipa/ipa_selinux_maps.h
@@ -0,0 +1,44 @@
+/*
+ SSSD
+
+ IPA Backend Module -- SELinux user maps (maps retrieval)
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef IPA_SELINUX_MAPS_H_
+#define IPA_SELINUX_MAPS_H_
+
+#include "providers/ldap/sdap_async.h"
+
+struct tevent_req *
+ipa_selinux_get_maps_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ struct sdap_options *opts,
+ struct sdap_search_base **search_bases);
+
+errno_t
+ipa_selinux_get_maps_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *count,
+ struct sysdb_attrs ***maps);
+
+#endif /* IPA_SELINUX_MAPS_H_ */
diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c
new file mode 100644
index 000000000..40e8c186b
--- /dev/null
+++ b/src/providers/ipa/ipa_session.c
@@ -0,0 +1,616 @@
+/*
+ SSSD
+
+ IPA Backend Module -- session loading
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <security/pam_modules.h>
+
+#include "db/sysdb_selinux.h"
+#include "util/sss_selinux.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ipa/ipa_common.h"
+#include "providers/ipa/ipa_config.h"
+#include "providers/ipa/ipa_session.h"
+#include "providers/ipa/ipa_hosts.h"
+#include "providers/ipa/ipa_hbac_rules.h"
+#include "providers/ipa/ipa_selinux_common.h"
+#include "providers/ipa/ipa_selinux_maps.h"
+
+/* FIXME: this is temporary until host map is implemented in ipa_common.c */
+#include "providers/ipa/ipa_hbac_private.h"
+
+struct ipa_get_selinux_state {
+ struct be_req *be_req;
+ struct pam_data *pd;
+ struct ipa_session_ctx *session_ctx;
+ struct sdap_id_op *op;
+
+ /* Just tmp stuff so we can free it after query */
+ const char **attrs;
+
+ const char *hostname;
+ struct sysdb_attrs *host;
+ struct sysdb_attrs *user;
+
+ struct sysdb_attrs *defaults;
+
+ struct sysdb_attrs **possible_match;
+ struct sysdb_attrs **confirmed_match;
+};
+
+static struct
+tevent_req *ipa_get_selinux_send(struct be_req *breq,
+ struct pam_data *pd,
+ struct ipa_session_ctx *session_ctx);
+static void ipa_session_handler_done(struct tevent_req *subreq);
+static errno_t ipa_get_selinux_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *count,
+ struct sysdb_attrs ***maps,
+ char **default_user,
+ char **map_order);
+
+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_selinux_maps_done(struct tevent_req *subreq);
+static void ipa_get_selinux_hbac_done(struct tevent_req *subreq);
+static void ipa_get_selinux_config_done(struct tevent_req *subreq);
+
+void ipa_session_handler(struct be_req *be_req)
+{
+ struct ipa_session_ctx *session_ctx;
+ struct tevent_req *req;
+ struct pam_data *pd;
+
+ pd = talloc_get_type(be_req->req_data, struct pam_data);
+
+ session_ctx = talloc_get_type(
+ be_req->be_ctx->bet_info[BET_SESSION].pvt_bet_data,
+ struct ipa_session_ctx);
+
+
+ req = ipa_get_selinux_send(be_req, pd, session_ctx);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ tevent_req_set_callback(req, ipa_session_handler_done, be_req);
+
+ return;
+
+fail:
+ be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
+}
+
+static void ipa_session_handler_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ struct sysdb_ctx *sysdb = breq->be_ctx->sysdb;
+ errno_t ret, sret;
+ size_t map_count;
+ struct sysdb_attrs **maps;
+ bool in_transaction = false;
+ char *default_user;
+ char *map_order;
+
+ ret = ipa_get_selinux_recv(req, breq, &map_count, &maps,
+ &default_user, &map_order);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) goto fail;
+ in_transaction = true;
+
+ if (default_user != NULL && map_order != NULL) {
+ ret = sysdb_store_selinux_config(sysdb, default_user, map_order);
+ if (ret != EOK) {
+ goto fail;
+ }
+ }
+
+ if (map_count > 0 && maps != NULL) {
+ ret = ipa_save_user_maps(sysdb, map_count, maps);
+ if (ret != EOK) {
+ goto fail;
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ 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;
+
+
+ breq->fn(breq, DP_ERR_OK, EOK, "Success");
+ return;
+
+fail:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n"));
+ }
+ }
+ if (ret == EAGAIN) {
+ breq->fn(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
+ } else {
+ breq->fn(breq, DP_ERR_FATAL, ret, NULL);
+ }
+}
+
+static struct tevent_req *ipa_get_selinux_send(struct be_req *breq,
+ struct pam_data *pd,
+ struct ipa_session_ctx *session_ctx)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct be_ctx *bctx = breq->be_ctx;
+ struct ipa_get_selinux_state *state;
+ bool offline;
+ int ret = EOK;
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Retrieving SELinux user mapping\n"));
+ req = tevent_req_create(breq, &state, struct ipa_get_selinux_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->be_req = breq;
+ state->pd = pd;
+ state->session_ctx = session_ctx;
+
+ offline = be_is_offline(bctx);
+ DEBUG(SSSDBG_TRACE_INTERNAL, ("Connection status is [%s].\n",
+ offline ? "offline" : "online"));
+
+ if (!offline) {
+ state->op = sdap_id_op_create(state, session_ctx->id_ctx->sdap_id_ctx->conn_cache);
+ if (!state->op) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n"));
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ subreq = sdap_id_op_connect_send(state->op, state, &ret);
+ if (!subreq) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_connect_send failed: "
+ "%d(%s).\n", ret, strerror(ret)));
+ talloc_zfree(state->op);
+ goto immediate;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req);
+ } else {
+ ret = EAGAIN;
+ goto immediate;
+ }
+
+ return req;
+
+immediate:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, bctx->ev);
+ return req;
+}
+
+static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_selinux_state *state = tevent_req_data(req,
+ struct ipa_get_selinux_state);
+ int dp_error = DP_ERR_FATAL;
+ int ret;
+ struct ipa_id_ctx *id_ctx = state->session_ctx->id_ctx;
+ struct be_ctx *bctx = state->be_req->be_ctx;
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+
+ if (dp_error == DP_ERR_OFFLINE) {
+ talloc_zfree(state->op);
+ ret = EAGAIN;
+ }
+
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ state->hostname = dp_opt_get_string(state->session_ctx->id_ctx->ipa_options->basic,
+ IPA_HOSTNAME);
+
+ /* FIXME: detect if HBAC is configured
+ * - if yes, we can skip host retrieval and get it directly from sysdb
+ */
+ state->attrs = talloc_array(state, const char *, 3);
+ if (state->attrs == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ state->attrs[0] = "objectClass";
+ state->attrs[1] = IPA_MEMBEROF;
+ state->attrs[2] = NULL;
+
+ subreq = ipa_host_info_send(state, bctx->ev, bctx->sysdb,
+ sdap_id_op_handle(state->op),
+ id_ctx->sdap_id_ctx->opts,
+ state->hostname,
+ state->attrs, false, state->session_ctx->host_search_bases);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req);
+
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+}
+
+static void ipa_get_selinux_hosts_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_selinux_state *state = tevent_req_data(req,
+ struct ipa_get_selinux_state);
+ struct be_ctx *bctx = state->be_req->be_ctx;
+ struct sdap_id_ctx *id_ctx = state->session_ctx->id_ctx->sdap_id_ctx;
+ size_t host_count, hostgroup_count;
+ struct sysdb_attrs **hostgroups;
+ struct sysdb_attrs **host;
+
+ ret = ipa_host_info_recv(subreq, state, &host_count, &host,
+ &hostgroup_count, &hostgroups);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+ state->host = host[0];
+
+ ret = sysdb_attrs_add_string(state->host, SYSDB_NAME, state->hostname);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sss_selinux_extract_user(state, bctx->sysdb,
+ state->pd->user, &state->user);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ subreq = ipa_selinux_get_maps_send(state, bctx->ev, bctx->sysdb,
+ sdap_id_op_handle(state->op),
+ id_ctx->opts,
+ state->session_ctx->selinux_search_bases);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_maps_done, req);
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct ipa_get_selinux_state *state;
+
+ struct be_ctx *bctx;
+ struct ipa_id_ctx *id_ctx;
+
+ struct sysdb_attrs **results;
+ size_t count;
+ const char *domain;
+ const char *tmp_str;
+ size_t conf_cnt = 0;
+ size_t pos_cnt = 0;
+ errno_t ret;
+ int i;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_get_selinux_state);
+ bctx = state->be_req->be_ctx;
+ id_ctx = state->session_ctx->id_ctx;
+
+ ret = ipa_selinux_get_maps_recv(subreq, state, &count, &results);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ if (ret == ENOENT) {
+ /* This is returned if no SELinux mapping
+ * rules were found. In that case no error
+ * occurred, but we don't want any more processing.*/
+ ret = EOK;
+ }
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Found %d SELinux user maps in total, "
+ "filtering ...\n", count));
+ state->confirmed_match = talloc_zero_array(state, struct sysdb_attrs *,
+ count + 1);
+ state->possible_match = talloc_zero_array(state, struct sysdb_attrs *,
+ count + 1);
+ if (state->confirmed_match == NULL || state->possible_match == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (sss_selinux_match(results[i], state->user, state->host)) {
+ state->confirmed_match[conf_cnt] = talloc_steal(state->confirmed_match,
+ results[i]);
+ conf_cnt++;
+ continue;
+ }
+
+ ret = sysdb_attrs_get_string(results[i], SYSDB_SELINUX_SEEALSO, &tmp_str);
+ if (ret == ENOENT) {
+ continue;
+ }
+
+ state->possible_match[pos_cnt] = talloc_steal(state->possible_match,
+ results[i]);
+ pos_cnt++;
+ }
+ DEBUG(SSSDBG_TRACE_FUNC, ("Filtering done. Results: %d confirmed and %d "
+ "possible maps remained.\n", conf_cnt, pos_cnt));
+
+ /* Don't shrink the confirmed list, it could be later filled by HBAC rules */
+ state->possible_match = talloc_realloc(state, state->possible_match,
+ struct sysdb_attrs *, pos_cnt + 1);
+ if (state->possible_match == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* This will free all rules that are neither confirmed nor possible */
+ talloc_free(results);
+
+ if (pos_cnt) {
+ /* FIXME: detect if HBAC is configured
+ * - if yes, we can skip HBAC retrieval and get it directly from sysdb
+ */
+ subreq = ipa_hbac_rule_info_send(state, false, bctx->ev,
+ sdap_id_op_handle(state->op),
+ id_ctx->sdap_id_ctx->opts,
+ state->session_ctx->hbac_search_bases,
+ state->host);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_hbac_done, req);
+ return;
+ }
+
+ domain = dp_opt_get_string(state->session_ctx->id_ctx->ipa_options->basic,
+ IPA_KRB5_REALM);
+ subreq = ipa_get_config_send(state, bctx->ev,
+ sdap_id_op_handle(state->op),
+ id_ctx->sdap_id_ctx->opts,
+ domain, NULL);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_config_done, req);
+
+ return;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void ipa_get_selinux_hbac_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_selinux_state *state = tevent_req_data(req,
+ struct ipa_get_selinux_state);
+ struct be_ctx *bctx = state->be_req->be_ctx;
+ struct ipa_id_ctx *id_ctx = state->session_ctx->id_ctx;
+ struct sysdb_attrs **rules;
+ struct sysdb_attrs *usermap;
+ const char *hbac_dn;
+ const char *seealso_dn;
+ const char *domain;
+ size_t rule_count;
+ size_t conf_cnt;
+ size_t pos_cnt;
+ errno_t ret;
+ int i, j;
+
+ ret = ipa_hbac_rule_info_recv(subreq, state, &rule_count,
+ &rules);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+ for (conf_cnt = 0 ; state->confirmed_match[conf_cnt]; conf_cnt++) ;
+ for (pos_cnt = 0 ; state->possible_match[pos_cnt]; pos_cnt++) ;
+
+ for (i = 0; i < rule_count; i++) {
+ if (!sss_selinux_match(rules[i], state->user, state->host)) {
+ continue;
+ }
+
+ ret = sysdb_attrs_get_string(rules[i], SYSDB_ORIG_DN, &hbac_dn);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* HBAC rule matched, find if it is in the "possible" list */
+ for (j = 0; state->possible_match[j]; 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) {
+ state->confirmed_match[conf_cnt++] = talloc_steal(
+ state->confirmed_match,
+ usermap);
+ /* Just to boost the following lookup */
+ state->possible_match[j] = NULL;
+
+ ret = ipa_selinux_map_merge(usermap, rules[i], SYSDB_ORIG_MEMBER_USER);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = ipa_selinux_map_merge(usermap, rules[i], SYSDB_ORIG_MEMBER_HOST);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+ }
+ }
+
+ /* Now we can dispose all possible rules, since they aren't possible any more */
+ talloc_zfree(state->possible_match);
+
+ domain = dp_opt_get_string(state->session_ctx->id_ctx->ipa_options->basic,
+ IPA_KRB5_REALM);
+ subreq = ipa_get_config_send(state, bctx->ev,
+ sdap_id_op_handle(state->op),
+ id_ctx->sdap_id_ctx->opts,
+ domain, NULL);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_get_selinux_config_done, req);
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void ipa_get_selinux_config_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_get_selinux_state *state = tevent_req_data(req,
+ struct ipa_get_selinux_state);
+ errno_t ret;
+
+ ret = ipa_get_config_recv(subreq, state, &state->defaults);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ tevent_req_done(req);
+ }
+}
+
+static errno_t
+ipa_get_selinux_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *count,
+ struct sysdb_attrs ***maps,
+ char **default_user,
+ char **map_order)
+{
+ struct ipa_get_selinux_state *state =
+ tevent_req_data(req, struct ipa_get_selinux_state);
+ const char *tmp_str;
+ errno_t ret;
+ int i;
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (state->defaults != NULL) {
+ ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_DEFAULT_MAP,
+ &tmp_str);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *default_user = talloc_strdup(mem_ctx, tmp_str);
+ if (*default_user == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_MAP_ORDER,
+ &tmp_str);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *map_order = talloc_strdup(mem_ctx, tmp_str);
+ if (*map_order == NULL) {
+ talloc_zfree(*default_user);
+ return ENOMEM;
+ }
+ } else {
+ *map_order = NULL;
+ *default_user = NULL;
+ }
+
+ if (state->confirmed_match != NULL) {
+ for (i = 0; state->confirmed_match[i]; i++) ;
+
+ *count = i;
+ *maps = talloc_steal(mem_ctx, state->confirmed_match);
+ } else {
+ *count = 0;
+ *maps = NULL;
+ }
+
+ return EOK;
+}
diff --git a/src/providers/ipa/ipa_session.h b/src/providers/ipa/ipa_session.h
new file mode 100644
index 000000000..e185799f7
--- /dev/null
+++ b/src/providers/ipa/ipa_session.h
@@ -0,0 +1,40 @@
+/*
+ SSSD
+
+ IPA Backend Module -- session loading
+
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2011 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _IPA_SESSION_H_
+#define _IPA_SESSION_H_
+
+#include "providers/ldap/ldap_common.h"
+
+struct ipa_session_ctx {
+ struct ipa_id_ctx *id_ctx;
+
+ struct sdap_search_base **selinux_search_bases;
+ struct sdap_search_base **host_search_bases;
+ struct sdap_search_base **hbac_search_bases;
+};
+
+void ipa_session_handler(struct be_req *be_req);
+
+#endif
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 0a0f996d1..19d9ed9ad 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -353,6 +353,7 @@ struct sdap_options {
struct sdap_attr_map *sudorule_map;
struct sdap_attr_map *autofs_mobject_map;
struct sdap_attr_map *autofs_entry_map;
+ struct sdap_attr_map *selinuxuser_map;
/* supported schema types */
enum schema_type {