From 65960d578dbd121b322b7674ebac379032107238 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Thu, 2 Feb 2012 11:15:26 -0500
Subject: [PATCH 13/14] Session target in IPA provider

---
 Makefile.am                            |    6 +
 src/db/sysdb.h                         |    7 +-
 src/providers/ipa/ipa_common.c         |   47 +++
 src/providers/ipa/ipa_common.h         |   17 +
 src/providers/ipa/ipa_init.c           |   42 +++
 src/providers/ipa/ipa_selinux_common.c |  103 ++++++
 src/providers/ipa/ipa_selinux_common.h |   39 ++
 src/providers/ipa/ipa_selinux_maps.c   |  217 +++++++++++
 src/providers/ipa/ipa_selinux_maps.h   |   44 +++
 src/providers/ipa/ipa_session.c        |  616 ++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_session.h        |   40 ++
 src/providers/ldap/sdap.h              |    1 +
 12 files changed, 1178 insertions(+), 1 deletions(-)
 create mode 100644 src/providers/ipa/ipa_selinux_common.c
 create mode 100644 src/providers/ipa/ipa_selinux_common.h
 create mode 100644 src/providers/ipa/ipa_selinux_maps.c
 create mode 100644 src/providers/ipa/ipa_selinux_maps.h
 create mode 100644 src/providers/ipa/ipa_session.c
 create mode 100644 src/providers/ipa/ipa_session.h

diff --git a/Makefile.am b/Makefile.am
index 045b986d1e85f65c84371b372e5caf13f1aeb8c2..48e55a3bbf398cbb037247176d9f701addca1561 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -352,7 +352,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 \
@@ -1023,6 +1026,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/db/sysdb.h b/src/db/sysdb.h
index 1ef427271c8b32300fb0e360ea3a419cc2c9de65..6bdf4d8af1f2f1a4b9031333ddc1f177c6897536 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -67,6 +67,8 @@
 #define SYSDB_MEMBER "member"
 #define SYSDB_MEMBERUID "memberUid"
 #define SYSDB_POSIX "isPosix"
+#define SYSDB_USER_CATEGORY "userCategory"
+#define SYSDB_HOST_CATEGORY "hostCategory"
 
 #define SYSDB_DEFAULTGROUP "defaultGroup"
 #define SYSDB_GECOS "gecos"
@@ -93,6 +95,10 @@
 #define SYSDB_NETGROUP_MEMBER "memberNisNetgroup"
 #define SYSDB_DESCRIPTION   "description"
 
+#define SYSDB_SELINUX_SEEALSO "seeAlso"
+#define SYSDB_SELINUX_USER "selinuxUser"
+#define SYSDB_SELINUX_ENABLED "enabled"
+
 #define SYSDB_CACHEDPWD "cachedPassword"
 
 #define SYSDB_UUID "uniqueID"
@@ -102,7 +108,6 @@
 #define SYSDB_ORIG_DN "originalDN"
 #define SYSDB_ORIG_MODSTAMP "originalModifyTimestamp"
 #define SYSDB_ORIG_MEMBEROF "originalMemberOf"
-
 #define SYSDB_ORIG_MEMBER_USER "originalMemberUser"
 #define SYSDB_ORIG_MEMBER_HOST "originalMemberHost"
 
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 562e24078a55ae23524abef1ae15126dbc9e6a0a..259a481c0196fbffebbd2a7d401886deff5b8868 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 },
@@ -581,6 +596,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(6, ("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);
@@ -662,6 +700,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 49afe74db4b7b61a8662c7113e4540618cc1876b..6be972966dab5663d27ce6b96f545a186a8e67f9 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 b3544f749d9b13ff8fef1ca02e11417f22116950..bfcf19b2d3421f348e314758a212e7e7ccbb3197 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(1, ("talloc_zero failed.\n"));
+        return ENOMEM;
+    }
+
+    ret = sssm_ipa_id_init(bectx, ops, (void **) &session_ctx->id_ctx);
+    if (ret != EOK) {
+        DEBUG(1, ("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 0000000000000000000000000000000000000000..15f0b4588c1189061252f4db573dc2b87d9556e4
--- /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 0000000000000000000000000000000000000000..17ccb231282763b6cbe479eb31520def6d1a0fc5
--- /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 0000000000000000000000000000000000000000..87650f6ce80dce2fb2d16bdea2227bc1a025a501
--- /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 0000000000000000000000000000000000000000..efd10bf4e2aad88418d081ba8b15addfba0f9185
--- /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 0000000000000000000000000000000000000000..40e8c186b67afc3eff508e091e87788e447f8a7c
--- /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 0000000000000000000000000000000000000000..e185799f763e8d60b3c209060ca14d757b40f468
--- /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 7bf1805c1798752e87d30e8173ea1b7c4944078b..8ce75b2455d855db657d395c3f25350847839172 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -336,6 +336,7 @@ struct sdap_options {
 
     /* FIXME - should this go to a special struct to avoid mixing with name-service-switch maps? */
     struct sdap_attr_map *sudorule_map;
+    struct sdap_attr_map *selinuxuser_map;
 
     /* supported schema types */
     enum schema_type {
-- 
1.7.6.4

