[SSSD] [PATCHES] Add backend part of user views

Sumit Bose sbose at redhat.com
Tue Oct 14 09:16:28 UTC 2014


On Wed, Oct 01, 2014 at 08:14:21PM +0200, Sumit Bose wrote:
> On Mon, Sep 29, 2014 at 07:38:54PM +0200, Jakub Hrozek wrote:
> > On Mon, Sep 29, 2014 at 03:00:44PM +0200, Sumit Bose wrote:
> > > > Hi,
> > > > I'm sending two more trivial debug patches to squash in. Otherwise its an
> > > > code wise ack. I'm running some tests now.
> > > > 
> > > 
> > > Thank you. Jakub, in case there are no other issues, can you add them
> > > when committing the patches, or shall I send a new round?
> > > 
> > > bye,
> > > Sumit
> > 
> > I will run the patches through the IPA CI engine with Tomas' help. If
> > there are no regressions, I will squash in the patches and push, if
> > there are, we would do another round.
> 
> Hi,
> 
> this new series of patches contain fixes for various issues found by
> Pavel, Jakub and Alexander. There is an additional 9th patch which
> contains support for searching in the override values, e.g. if the user
> name is overridden we have to first search in the override data and the
> continue with the original object. See commit message for details.

Please find attached the latest version of the patches with even more
fixes for issue found by Alexander, Jakub and Pavel. I tired to keep the
original structure of the patches but a new patch sneaked in which adds
some new sysdb interface which allow to add attribute values with
detection of duplicates.

bye,
Sumit

> 
> bye,
> Sumit
> > _______________________________________________
> > sssd-devel mailing list
> > sssd-devel at lists.fedorahosted.org
> > https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From aed23ae26a5e8f4cf328c8c12b79501952f5653a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 16 Sep 2014 15:18:53 +0200
Subject: [PATCH 01/10] sysdb: add sysdb_update_view_name()

---
 Makefile.am          |   1 +
 src/db/sysdb.h       |  11 ++++
 src/db/sysdb_views.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 194 insertions(+)
 create mode 100644 src/db/sysdb_views.c

diff --git a/Makefile.am b/Makefile.am
index ee6e39b..2e0c190 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -668,6 +668,7 @@ libsss_util_la_SOURCES = \
     src/db/sysdb_services.c \
     src/db/sysdb_autofs.c \
     src/db/sysdb_subdomains.c \
+    src/db/sysdb_views.c \
     src/db/sysdb_ranges.c \
     src/db/sysdb_idmap.c \
     src/db/sysdb_gpo.c \
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c93119c..b87b956 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -36,11 +36,13 @@
 #define SYSDB_CUSTOM_CONTAINER "cn=custom"
 #define SYSDB_NETGROUP_CONTAINER "cn=Netgroups"
 #define SYSDB_RANGE_CONTAINER "cn=ranges"
+#define SYSDB_VIEW_CONTAINER "cn=views"
 #define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER","SYSDB_DOM_BASE
 #define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER","SYSDB_DOM_BASE
 #define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER","SYSDB_DOM_BASE
 #define SYSDB_TMPL_NETGROUP_BASE SYSDB_NETGROUP_CONTAINER","SYSDB_DOM_BASE
 #define SYSDB_TMPL_RANGE_BASE SYSDB_RANGE_CONTAINER","SYSDB_BASE
+#define SYSDB_TMPL_VIEW_BASE SYSDB_VIEW_CONTAINER","SYSDB_BASE
 
 #define SYSDB_SUBDOMAIN_CLASS "subdomain"
 #define SYSDB_USER_CLASS "user"
@@ -145,6 +147,10 @@
 #define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires"
 #define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl"
 
+#define SYSDB_VIEW_CLASS "view"
+#define SYSDB_VIEW_NAME "viewName"
+#define SYSDB_DEFAULT_VIEW_NAME "default"
+
 #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
 
 #define SYSDB_UC "objectclass="SYSDB_USER_CLASS
@@ -412,6 +418,11 @@ errno_t sysdb_range_create(struct sysdb_ctx *sysdb, struct range_info *range);
 errno_t sysdb_update_ranges(struct sysdb_ctx *sysdb,
                             struct range_info **ranges);
 
+errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name);
+
+errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+                            char **view_name);
+
 /* Sysdb initialization.
  * call this function *only* once to initialize the database and get
  * the sysdb ctx */
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
new file mode 100644
index 0000000..4708a22
--- /dev/null
+++ b/src/db/sysdb_views.c
@@ -0,0 +1,182 @@
+/*
+   SSSD
+
+   System Database - View and Override related calls
+
+   Copyright (C) 2014 Sumit Bose <sbose at redhat.com>
+
+   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 "util/util.h"
+#include "db/sysdb_private.h"
+
+/* In general is should not be possible that there is a view container without
+ * a view name set. But to be on the safe side we return both information
+ * separately. */
+static errno_t sysdb_get_view_name_ex(TALLOC_CTX *mem_ctx,
+                                      struct sysdb_ctx *sysdb,
+                                      char **_view_name,
+                                      bool *view_container_exists)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    const char *tmp_str;
+    struct ldb_dn *view_base_dn;
+    struct ldb_result *res;
+    const char *attrs[] = {SYSDB_VIEW_NAME,
+                           NULL};
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    view_base_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_TMPL_VIEW_BASE);
+    if (view_base_dn == NULL) {
+        ret = EIO;
+        goto done;
+    }
+    ret = ldb_search(sysdb->ldb, tmp_ctx, &res, view_base_dn, LDB_SCOPE_BASE,
+                     attrs, NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    if (res->count > 1) {
+        DEBUG(SSSDBG_OP_FAILURE, "Base search returned [%d] results, "
+                                 "expected 1.\n", res->count);
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (res->count == 0) {
+        *view_container_exists = false;
+        ret = ENOENT;
+        goto done;
+    } else {
+        *view_container_exists = true;
+        tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_VIEW_NAME,
+                                              NULL);
+        if (tmp_str == NULL) {
+            ret = ENOENT;
+            goto done;
+        }
+    }
+
+    *_view_name = talloc_strdup(mem_ctx, tmp_str);
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
+                            char **view_name)
+{
+    bool view_container_exists;
+
+    return sysdb_get_view_name_ex(mem_ctx, sysdb, view_name,
+                                  &view_container_exists);
+}
+
+errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb,
+                               const char *view_name)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    char *tmp_str;
+    bool view_container_exists = false;
+    bool add_view_name = false;
+    struct ldb_message *msg;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sysdb_get_view_name_ex(tmp_ctx, sysdb, &tmp_str,
+                                 &view_container_exists);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name_ex failed.\n");
+        goto done;
+    }
+
+    if (ret == EOK) {
+        if (strcmp(tmp_str, view_name) == 0) {
+            /* view name already known, mothing to do */
+            DEBUG(SSSDBG_TRACE_ALL, "View name already in place.\n");
+            ret = EOK;
+            goto done;
+        } else {
+            /* view name changed */
+            /* not supported atm */
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "View name changed from [%s] to [%s]. NOT SUPPORTED.\n",
+                  tmp_str, view_name);
+            ret = ENOTSUP;
+            goto done;
+        }
+    }
+
+    add_view_name = true;
+
+    msg = ldb_msg_new(tmp_ctx);
+    if (msg == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_TMPL_VIEW_BASE);
+    if (msg->dn == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    ret = ldb_msg_add_empty(msg, SYSDB_VIEW_NAME,
+                            add_view_name ? LDB_FLAG_MOD_ADD
+                                          : LDB_FLAG_MOD_REPLACE,
+                            NULL);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    ret = ldb_msg_add_string(msg, SYSDB_VIEW_NAME, view_name);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    if (view_container_exists) {
+        ret = ldb_modify(sysdb->ldb, msg);
+    } else {
+        ret = ldb_add(sysdb->ldb, msg);
+    }
+    if (ret != LDB_SUCCESS) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to %s view container",
+                                    view_container_exists ? "modify" : "add");
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
-- 
1.8.3.1

-------------- next part --------------
From 5775621a63f545b1d9415406e3e471c0897d3143 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 16 Sep 2014 15:22:08 +0200
Subject: [PATCH 02/10] Add sdap_deref_search_with_filter_send()

---
 src/providers/ldap/sdap_async.c | 76 ++++++++++++++++++++++++++++++++++++++---
 src/providers/ldap/sdap_async.h | 17 +++++++++
 2 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 8979de4..560d137 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1692,9 +1692,10 @@ struct sdap_x_deref_search_state {
 static struct tevent_req *
 sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
                          struct sdap_options *opts, struct sdap_handle *sh,
-                         const char *base_dn, const char *deref_attr,
-                         const char **attrs, struct sdap_attr_map_info *maps,
-                         int num_maps, int timeout)
+                         const char *base_dn, const char *filter,
+                         const char *deref_attr, const char **attrs,
+                         struct sdap_attr_map_info *maps, int num_maps,
+                         int timeout)
 {
     struct tevent_req *req = NULL;
     struct tevent_req *subreq = NULL;
@@ -1728,7 +1729,9 @@ sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
     DEBUG(SSSDBG_TRACE_FUNC,
           "Dereferencing entry [%s] using OpenLDAP deref\n", base_dn);
     subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
-                                       LDAP_SCOPE_BASE, NULL, attrs,
+                                       filter == NULL ? LDAP_SCOPE_BASE
+                                                      : LDAP_SCOPE_SUBTREE,
+                                       filter, attrs,
                                        false, state->ctrls, NULL, 0, timeout,
                                        true, sdap_x_deref_parse_entry,
                                        state);
@@ -2532,6 +2535,69 @@ struct sdap_deref_search_state {
 };
 
 static void sdap_deref_search_done(struct tevent_req *subreq);
+static void sdap_deref_search_with_filter_done(struct tevent_req *subreq);
+
+struct tevent_req *
+sdap_deref_search_with_filter_send(TALLOC_CTX *memctx,
+                                   struct tevent_context *ev,
+                                   struct sdap_options *opts,
+                                   struct sdap_handle *sh,
+                                   const char *search_base,
+                                   const char *filter,
+                                   const char *deref_attr,
+                                   const char **attrs,
+                                   int num_maps,
+                                   struct sdap_attr_map_info *maps,
+                                   int timeout)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    struct sdap_deref_search_state *state;
+
+    req = tevent_req_create(memctx, &state, struct sdap_deref_search_state);
+    if (!req) return NULL;
+
+    state->sh = sh;
+    state->reply_count = 0;
+    state->reply = NULL;
+
+    if (sdap_is_control_supported(sh, LDAP_CONTROL_X_DEREF)) {
+        DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
+        state->deref_type = SDAP_DEREF_OPENLDAP;
+
+        subreq = sdap_x_deref_search_send(state, ev, opts, sh, search_base,
+                                          filter, deref_attr, attrs, maps,
+                                          num_maps, timeout);
+        if (!subreq) {
+            DEBUG(SSSDBG_OP_FAILURE, "Cannot start OpenLDAP deref search\n");
+            goto fail;
+        }
+    } else {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Server does not support any known deref method!\n");
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, sdap_deref_search_with_filter_done, req);
+    return req;
+
+fail:
+    talloc_zfree(req);
+    return NULL;
+}
+
+static void sdap_deref_search_with_filter_done(struct tevent_req *subreq)
+{
+    sdap_deref_search_done(subreq);
+}
+
+int sdap_deref_search_with_filter_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       size_t *reply_count,
+                                       struct sdap_deref_attrs ***reply)
+{
+    return sdap_deref_search_recv(req, mem_ctx, reply_count, reply);
+}
 
 struct tevent_req *
 sdap_deref_search_send(TALLOC_CTX *memctx,
@@ -2571,7 +2637,7 @@ sdap_deref_search_send(TALLOC_CTX *memctx,
         DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
         state->deref_type = SDAP_DEREF_OPENLDAP;
 
-        subreq = sdap_x_deref_search_send(state, ev, opts, sh, base_dn,
+        subreq = sdap_x_deref_search_send(state, ev, opts, sh, base_dn, NULL,
                                           deref_attr, attrs, maps, num_maps,
                                           timeout);
         if (!subreq) {
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 7bb69f2..1239f28 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -196,6 +196,23 @@ int sdap_get_generic_recv(struct tevent_req *req,
 bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts);
 
 struct tevent_req *
+sdap_deref_search_with_filter_send(TALLOC_CTX *memctx,
+                                   struct tevent_context *ev,
+                                   struct sdap_options *opts,
+                                   struct sdap_handle *sh,
+                                   const char *search_base,
+                                   const char *filter,
+                                   const char *deref_attr,
+                                   const char **attrs,
+                                   int num_maps,
+                                   struct sdap_attr_map_info *maps,
+                                   int timeout);
+int sdap_deref_search_with_filter_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       size_t *reply_count,
+                                       struct sdap_deref_attrs ***reply);
+
+struct tevent_req *
 sdap_deref_search_send(TALLOC_CTX *memctx,
                        struct tevent_context *ev,
                        struct sdap_options *opts,
-- 
1.8.3.1

-------------- next part --------------
From f907746b65ee0e45b486ed668714d03facd10241 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 19 Sep 2014 10:26:01 +0200
Subject: [PATCH 03/10] IPA: make IPA ID context available to extdom client
 code

---
 src/providers/ipa/ipa_id.c            | 2 +-
 src/providers/ipa/ipa_id.h            | 3 ++-
 src/providers/ipa/ipa_s2n_exop.c      | 9 ++++++++-
 src/providers/ipa/ipa_subdomains_id.c | 7 +++++--
 4 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
index dd87a2d..942feb1 100644
--- a/src/providers/ipa/ipa_id.c
+++ b/src/providers/ipa/ipa_id.c
@@ -90,7 +90,7 @@ void ipa_account_info_handler(struct be_req *breq)
         if (dp_opt_get_bool(ipa_ctx->ipa_options->basic, IPA_SERVER_MODE)) {
             req = ipa_get_ad_acct_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
         } else {
-            req = ipa_get_subdom_acct_send(breq, be_ctx->ev, ctx, ar);
+            req = ipa_get_subdom_acct_send(breq, be_ctx->ev, ipa_ctx, ar);
         }
     } else if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
         /* netgroups are handled by a separate request function */
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index 6c72f6d..9a255ff 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -52,6 +52,7 @@ void ipa_check_online(struct be_req *be_req);
 
 struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
                                               struct tevent_context *ev,
+                                              struct ipa_id_ctx *ipa_ctx,
                                               struct sdap_options *opts,
                                               struct sss_domain_info *dom,
                                               struct sdap_handle *sh,
@@ -61,7 +62,7 @@ int ipa_s2n_get_acct_info_recv(struct tevent_req *req);
 
 struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
                                             struct tevent_context *ev,
-                                            struct sdap_id_ctx *ctx,
+                                            struct ipa_id_ctx *ipa_ctx,
                                             struct be_acct_req *ar);
 int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out);
 
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 0d5c356..6f5fac3 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -874,6 +874,7 @@ done:
 
 struct ipa_s2n_get_groups_state {
     struct tevent_context *ev;
+    struct ipa_id_ctx *ipa_ctx;
     struct sss_domain_info *dom;
     struct sdap_handle *sh;
     struct req_input req_input;
@@ -887,6 +888,7 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq);
 
 static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
                                                   struct tevent_context *ev,
+                                                  struct ipa_id_ctx *ipa_ctx,
                                                   struct sss_domain_info *dom,
                                                   struct sdap_handle *sh,
                                                   int exop_timeout,
@@ -902,6 +904,7 @@ static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
     }
 
     state->ev = ev;
+    state->ipa_ctx = ipa_ctx;
     state->dom = dom;
     state->sh = sh;
     state->group_list = group_list;
@@ -1034,6 +1037,7 @@ static int ipa_s2n_get_groups_recv(struct tevent_req *req)
 
 struct ipa_s2n_get_user_state {
     struct tevent_context *ev;
+    struct ipa_id_ctx *ipa_ctx;
     struct sdap_options *opts;
     struct sss_domain_info *dom;
     struct sdap_handle *sh;
@@ -1049,6 +1053,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq);
 
 struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
                                               struct tevent_context *ev,
+                                              struct ipa_id_ctx *ipa_ctx,
                                               struct sdap_options *opts,
                                               struct sss_domain_info *dom,
                                               struct sdap_handle *sh,
@@ -1068,6 +1073,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
     }
 
     state->ev = ev;
+    state->ipa_ctx = ipa_ctx;
     state->opts = opts;
     state->dom = dom;
     state->sh = sh;
@@ -1322,7 +1328,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
             }
 
             if (missing_groups != NULL) {
-                subreq = ipa_s2n_get_groups_send(state, state->ev, state->dom,
+                subreq = ipa_s2n_get_groups_send(state, state->ev,
+                                                 state->ipa_ctx, state->dom,
                                                  state->sh, state->exop_timeout,
                                                  missing_groups);
                 if (subreq == NULL) {
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index 83f913c..d1bd08d 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -36,6 +36,7 @@
 
 struct ipa_get_subdom_acct {
     struct tevent_context *ev;
+    struct ipa_id_ctx *ipa_ctx;
     struct sdap_id_ctx *ctx;
     struct sdap_id_op *op;
     struct sysdb_ctx *sysdb;
@@ -53,7 +54,7 @@ static void ipa_get_subdom_acct_done(struct tevent_req *subreq);
 
 struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
                                             struct tevent_context *ev,
-                                            struct sdap_id_ctx *ctx,
+                                            struct ipa_id_ctx *ipa_ctx,
                                             struct be_acct_req *ar)
 {
     struct tevent_req *req;
@@ -65,7 +66,8 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
     if (!req) return NULL;
 
     state->ev = ev;
-    state->ctx = ctx;
+    state->ipa_ctx = ipa_ctx;
+    state->ctx = ipa_ctx->sdap_id_ctx;
     state->dp_error = DP_ERR_FATAL;
 
     state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
@@ -184,6 +186,7 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq)
 
     subreq = ipa_s2n_get_acct_info_send(state,
                                         state->ev,
+                                        state->ipa_ctx,
                                         state->ctx->opts,
                                         state->domain,
                                         sdap_id_op_handle(state->op),
-- 
1.8.3.1

-------------- next part --------------
From 017815203fc4d52b0559c79d53decc03a31500e4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 16 Sep 2014 15:26:24 +0200
Subject: [PATCH 04/10] IPA: add view support and get view name

Related to https://fedorahosted.org/sssd/ticket/2375
---
 src/db/sysdb.h                     |   4 +
 src/providers/ipa/ipa_common.c     |  44 +++++++++
 src/providers/ipa/ipa_common.h     |  29 ++++++
 src/providers/ipa/ipa_id.h         |   2 +
 src/providers/ipa/ipa_init.c       |  65 +++++++++----
 src/providers/ipa/ipa_opts.h       |  23 +++++
 src/providers/ipa/ipa_subdomains.c | 193 +++++++++++++++++++++++++++++++++++--
 7 files changed, 332 insertions(+), 28 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index b87b956..c2de008 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -150,6 +150,10 @@
 #define SYSDB_VIEW_CLASS "view"
 #define SYSDB_VIEW_NAME "viewName"
 #define SYSDB_DEFAULT_VIEW_NAME "default"
+#define SYSDB_OVERRIDE_CLASS "overrride"
+#define SYSDB_OVERRIDE_ANCHOR_UUID "overrideAnchorUUID"
+#define SYSDB_OVERRIDE_USER_CLASS "userOverride"
+#define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride"
 
 #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
 
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index f594de2..2940a42 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -149,6 +149,9 @@ static errno_t ipa_parse_search_base(TALLOC_CTX *mem_ctx,
     case IPA_RANGES_SEARCH_BASE:
         class_name = "IPA_RANGES";
         break;
+    case IPA_VIEWS_SEARCH_BASE:
+        class_name = "IPA_VIEWS";
+        break;
     default:
         DEBUG(SSSDBG_CONF_SETTINGS,
               "Unknown search base type: [%d]\n", class);
@@ -530,6 +533,29 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
                                 &ipa_opts->ranges_search_bases);
     if (ret != EOK) goto done;
 
+    if (NULL == dp_opt_get_string(ipa_opts->basic,
+                                  IPA_VIEWS_SEARCH_BASE)) {
+        value = talloc_asprintf(tmpctx, "cn=views,cn=accounts,%s", basedn);
+        if (value == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = dp_opt_set_string(ipa_opts->basic, IPA_VIEWS_SEARCH_BASE, value);
+        if (ret != EOK) {
+            goto done;
+        }
+
+        DEBUG(SSSDBG_CONF_SETTINGS, "Option %s set to %s\n",
+                  ipa_opts->basic[IPA_VIEWS_SEARCH_BASE].opt_name,
+                  dp_opt_get_string(ipa_opts->basic,
+                                    IPA_VIEWS_SEARCH_BASE));
+    }
+    ret = ipa_parse_search_base(ipa_opts, ipa_opts->basic,
+                                IPA_VIEWS_SEARCH_BASE,
+                                &ipa_opts->views_search_bases);
+    if (ret != EOK) goto done;
+
     ret = sdap_get_map(ipa_opts->id, cdb, conf_path,
                        ipa_attr_map,
                        SDAP_AT_GENERAL,
@@ -611,6 +637,24 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
         goto done;
     }
 
+    ret = sdap_get_map(ipa_opts->id,
+                       cdb, conf_path,
+                       ipa_view_map,
+                       IPA_OPTS_VIEW,
+                       &ipa_opts->view_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(ipa_opts->id,
+                       cdb, conf_path,
+                       ipa_override_map,
+                       IPA_OPTS_OVERRIDE,
+                       &ipa_opts->override_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 0b8a17c..0e9324f 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -53,6 +53,7 @@ enum ipa_basic_opt {
     IPA_RANGES_SEARCH_BASE,
     IPA_ENABLE_DNS_SITES,
     IPA_SERVER_MODE,
+    IPA_VIEWS_SEARCH_BASE,
 
     IPA_OPTS_BASIC /* opts counter */
 };
@@ -107,6 +108,30 @@ enum ipa_selinux_usermap_attrs {
     IPA_OPTS_SELINUX_USERMAP /* attrs counter */
 };
 
+enum ipa_view_attrs {
+    IPA_OC_VIEW = 0,
+    IPA_AT_VIEW_NAME,
+
+    IPA_OPTS_VIEW
+};
+
+enum ipa_override_attrs {
+    IPA_OC_OVERRIDE = 0,
+    IPA_AT_OVERRIDE_ANCHOR_UUID,
+    IPA_OC_OVERRIDE_USER,
+    IPA_OC_OVERRIDE_GROUP,
+    IPA_AT_OVERRIDE_USER_NAME,
+    IPA_AT_OVERRIDE_UID_NUMBER,
+    IPA_AT_OVERRIDE_USER_GID_NUMBER,
+    IPA_AT_OVERRIDE_GECOS,
+    IPA_AT_OVERRIDE_HOMEDIR,
+    IPA_AT_OVERRIDE_SHELL,
+    IPA_AT_OVERRIDE_GROUP_NAME,
+    IPA_AT_OVERRIDE_GROUP_GID_NUMBER,
+
+    IPA_OPTS_OVERRIDE
+};
+
 struct ipa_auth_ctx {
     struct krb5_ctx *krb5_auth_ctx;
     struct sdap_id_ctx *sdap_id_ctx;
@@ -120,6 +145,7 @@ struct ipa_id_ctx {
     struct sdap_id_ctx *sdap_id_ctx;
     struct ipa_options *ipa_options;
 
+    char *view_name;
     /* Only used with server mode */
     struct ipa_server_mode_ctx *server_mode;
 };
@@ -130,6 +156,8 @@ struct ipa_options {
     struct sdap_attr_map *host_map;
     struct sdap_attr_map *hostgroup_map;
     struct sdap_attr_map *selinuxuser_map;
+    struct sdap_attr_map *view_map;
+    struct sdap_attr_map *override_map;
 
     struct sdap_search_base **host_search_bases;
     struct sdap_search_base **hbac_search_bases;
@@ -137,6 +165,7 @@ struct ipa_options {
     struct sdap_search_base **subdomains_search_bases;
     struct sdap_search_base **master_domain_search_bases;
     struct sdap_search_base **ranges_search_bases;
+    struct sdap_search_base **views_search_bases;
     struct ipa_service *service;
 
     /* id provider */
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index 9a255ff..9f05d25 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -31,6 +31,8 @@
 #include "providers/ldap/sdap.h"
 #include "providers/ipa/ipa_subdomains.h"
 
+#define IPA_DEFAULT_VIEW_NAME "Default Trust View"
+
 void ipa_account_info_handler(struct be_req *breq);
 struct tevent_req *ipa_get_netgroups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index c1a9cc7..45abd0e 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -244,6 +244,20 @@ int sssm_ipa_id_init(struct be_ctx *bectx,
     server_mode = dp_opt_get_bool(ipa_options->basic, IPA_SERVER_MODE);
 
     if (server_mode == true) {
+        ipa_ctx->view_name = talloc_strdup(ipa_ctx, SYSDB_DEFAULT_VIEW_NAME);
+        if (ipa_ctx->view_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = sysdb_update_view_name(bectx->domain->sysdb, ipa_ctx->view_name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Cannot add/update view name to sysdb.\n");
+            goto done;
+        }
+
         ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER);
         if (srv_in_server_list(ipa_servers) == true
                 || dp_opt_get_bool(ipa_options->basic,
@@ -295,26 +309,41 @@ int sssm_ipa_id_init(struct be_ctx *bectx,
                       "will be ignored in ipa_server_mode\n");
             }
         }
-    } else if (dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES)) {
-        /* use IPA plugin */
-        ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN);
-        srv_ctx = ipa_srv_plugin_ctx_init(bectx, bectx->be_res->resolv,
-                                          hostname, ipa_domain);
-        if (srv_ctx == NULL) {
-            DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
-            ret = ENOMEM;
-            goto done;
-        }
-
-        be_fo_set_srv_lookup_plugin(bectx, ipa_srv_plugin_send,
-                                    ipa_srv_plugin_recv, srv_ctx, "IPA");
     } else {
-        /* fall back to standard plugin on clients. */
-        ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname);
+        ret = sysdb_get_view_name(ipa_ctx, bectx->domain->sysdb,
+                                  &ipa_ctx->view_name);
         if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
-                                        "[%d]: %s\n", ret, strerror(ret));
-            goto done;
+            if (ret == ENOENT) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Cannot find view name in the cache. " \
+                      "Will do online lookup later.\n");
+            } else {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
+                goto done;
+            }
+        }
+
+        if (dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES)) {
+            /* use IPA plugin */
+            ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN);
+            srv_ctx = ipa_srv_plugin_ctx_init(bectx, bectx->be_res->resolv,
+                                              hostname, ipa_domain);
+            if (srv_ctx == NULL) {
+                DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
+                ret = ENOMEM;
+                goto done;
+            }
+
+            be_fo_set_srv_lookup_plugin(bectx, ipa_srv_plugin_send,
+                                        ipa_srv_plugin_recv, srv_ctx, "IPA");
+        } else {
+            /* fall back to standard plugin on clients. */
+            ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
+                                            "[%d]: %s\n", ret, strerror(ret));
+                goto done;
+            }
         }
     }
 
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 30cb96b..4785e01 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -50,6 +50,7 @@ struct dp_option ipa_basic_opts[] = {
     { "ipa_ranges_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ipa_enable_dns_sites", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ipa_server_mode", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+    { "ipa_views_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     DP_OPTION_TERMINATOR
 };
 
@@ -263,6 +264,28 @@ struct sdap_attr_map ipa_selinux_user_map[] = {
     SDAP_ATTR_MAP_TERMINATOR
 };
 
+struct sdap_attr_map ipa_view_map[] = {
+    { "ipa_view_class", "nsContainer", SYSDB_VIEW_CLASS, NULL},
+    { "ipa_view_name", "cn", SYSDB_VIEW_NAME, NULL},
+    SDAP_ATTR_MAP_TERMINATOR
+};
+
+struct sdap_attr_map ipa_override_map[] = {
+    { "ipa_overide_object_class", "ipaOverrideAnchor", SYSDB_OVERRIDE_CLASS, NULL},
+    { "ipa_anchor_uuid", "ipaAnchorUUID", SYSDB_OVERRIDE_ANCHOR_UUID, NULL},
+    { "ipa_user_override_object_class", "ipaUserOverride", SYSDB_OVERRIDE_USER_CLASS, NULL},
+    { "ipa_group_override_object_class", "ipaGroupOverride", SYSDB_OVERRIDE_GROUP_CLASS, NULL},
+    { "ldap_user_name", "uid", SYSDB_NAME, NULL },
+    { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL },
+    { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+    { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL },
+    { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL },
+    { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL },
+    { "ldap_group_name", "cn", SYSDB_NAME, NULL },
+    { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+    SDAP_ATTR_MAP_TERMINATOR
+};
+
 struct dp_option ipa_def_krb5_opts[] = {
     { "krb5_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "krb5_backup_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 5245048..0ff61cf 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -26,6 +26,8 @@
 #include "providers/ldap/sdap_idmap.h"
 #include "providers/ipa/ipa_subdomains.h"
 #include "providers/ipa/ipa_common.h"
+#include "providers/ipa/ipa_id.h"
+
 #include <ctype.h>
 
 #define SUBDOMAINS_FILTER "objectclass=ipaNTTrustedDomain"
@@ -44,6 +46,8 @@
 #define IPA_SECONDARY_BASE_RID "ipaSecondaryBaseRID"
 #define OBJECTCLASS "objectClass"
 
+#define IPA_ASSIGNED_ID_VIEW "ipaAssignedIDView"
+
 /* do not refresh more often than every 5 seconds for now */
 #define IPA_SUBDOMAIN_REFRESH_LIMIT 5
 
@@ -70,6 +74,7 @@ struct ipa_subdomains_ctx {
     struct sdap_search_base **search_bases;
     struct sdap_search_base **master_search_bases;
     struct sdap_search_base **ranges_search_bases;
+    struct sdap_search_base **host_search_bases;
 
     time_t last_refreshed;
     struct tevent_timer *timer_event;
@@ -943,6 +948,134 @@ ipa_subdomains_handler_get(struct ipa_subdomains_req_ctx *ctx,
     return EAGAIN;
 }
 
+static void ipa_get_view_name_done(struct tevent_req *req);
+static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx);
+
+static errno_t ipa_get_view_name(struct ipa_subdomains_req_ctx *ctx)
+{
+    struct tevent_req *req;
+    struct sdap_search_base *base;
+    const char *attrs[] = {IPA_CN, OBJECTCLASS, NULL};
+    struct sdap_attr_map_info *maps;
+
+    maps = talloc_zero(ctx, struct sdap_attr_map_info);
+    if (maps == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+        return ENOMEM;
+    }
+    maps->map = ctx->sd_ctx->id_ctx->ipa_options->view_map;
+    maps->num_attrs = IPA_OPTS_VIEW;
+
+    base = ctx->search_bases[ctx->search_base_iter];
+    if (base == NULL) {
+        return EOK;
+    }
+
+    req = sdap_deref_search_with_filter_send(ctx, ctx->sd_ctx->be_ctx->ev,
+                        ctx->sd_ctx->sdap_id_ctx->opts,
+                        sdap_id_op_handle(ctx->sdap_op),
+                        base->basedn,
+                        ctx->current_filter, IPA_ASSIGNED_ID_VIEW, attrs,
+                        1, maps,
+                        dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
+                                       SDAP_SEARCH_TIMEOUT));
+
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, ipa_get_view_name_done, ctx);
+
+    return EAGAIN;
+}
+
+static void ipa_get_view_name_done(struct tevent_req *req)
+{
+    int ret;
+    struct ipa_subdomains_req_ctx *ctx;
+    size_t reply_count;
+    struct sdap_deref_attrs **reply = NULL;
+    const char *view_name;
+    int dp_error = DP_ERR_FATAL;
+
+    ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
+
+    ret = sdap_deref_search_with_filter_recv(req, ctx, &reply_count, &reply);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "get_view_name request failed.\n");
+        goto done;
+    }
+
+    if (reply_count == 0) {
+        ctx->search_base_iter++;
+        ret = ipa_get_view_name(ctx);
+        if (ret == EAGAIN) {
+            return;
+        } else if (ret == EOK) {
+            DEBUG(SSSDBG_TRACE_FUNC, "No view found, using default.\n");
+            view_name = SYSDB_DEFAULT_VIEW_NAME;
+        } else {
+            goto done;
+        }
+    } else if (reply_count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "get_view_name request returned more than one object.\n");
+        ret = EINVAL;
+        goto done;
+    } else {
+        ret = sysdb_attrs_get_string(reply[0]->attrs, SYSDB_VIEW_NAME,
+                                     &view_name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+            goto done;
+        }
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Found view name [%s].\n", view_name);
+    if (strcmp(view_name, IPA_DEFAULT_VIEW_NAME) == 0) {
+        DEBUG(SSSDBG_TRACE_ALL,
+              "Found IPA default view name, replacing with sysdb default.\n");
+        view_name = SYSDB_DEFAULT_VIEW_NAME;
+    }
+
+    if (ctx->sd_ctx->id_ctx->view_name != NULL
+            && strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "View name changed, this is currently not supported!\n");
+    } else {
+        ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
+                                     view_name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Cannot add/update view name to sysdb.\n");
+        } else {
+            if (ctx->sd_ctx->id_ctx->view_name == NULL) {
+                ctx->sd_ctx->id_ctx->view_name =
+                                              talloc_strdup(ctx->sd_ctx->id_ctx,
+                                                            view_name);
+                if (ctx->sd_ctx->id_ctx->view_name == NULL) {
+                    DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
+                }
+            }
+        }
+    }
+
+    ret = ipa_check_master(ctx);
+    if (ret == EAGAIN) {
+        return;
+    } else if (ret != EOK) {
+        goto done;
+    }
+
+done:
+    if (ret == EOK) {
+        dp_error = DP_ERR_OK;
+    }
+    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+}
+
 static void ipa_subdomains_handler_done(struct tevent_req *req)
 {
     int ret;
@@ -1005,9 +1138,54 @@ static void ipa_subdomains_handler_done(struct tevent_req *req)
         }
     }
 
+    ctx->search_base_iter = 0;
+    ctx->search_bases = ctx->sd_ctx->host_search_bases;
+    talloc_zfree(ctx->current_filter);
+    ctx->current_filter = talloc_asprintf(ctx, "(&(objectClass=%s)(%s=%s))",
+              ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_OC_HOST].name,
+              ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_AT_HOST_FQDN].name,
+              dp_opt_get_string(ctx->sd_ctx->id_ctx->ipa_options->basic,
+                                IPA_HOSTNAME));
+    if (ctx->current_filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    if (ctx->sd_ctx->id_ctx->server_mode == NULL) {
+        /* Only get view on clients, on servers it is always 'default' */
+        ret = ipa_get_view_name(ctx);
+        if (ret == EAGAIN) {
+            return;
+        } else if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    ret = ipa_check_master(ctx);
+    if (ret == EAGAIN) {
+        return;
+    } else if (ret != EOK) {
+        goto done;
+    }
+
+done:
+    if (ret == EOK) {
+        dp_error = DP_ERR_OK;
+    }
+    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+}
+
+static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx)
+{
+    int ret;
+    struct sss_domain_info *domain;
+
+    domain = ctx->sd_ctx->be_ctx->domain;
+
     ret = sysdb_master_domain_update(domain);
     if (ret != EOK) {
-        goto done;
+        return ret;
     }
 
     if (domain->flat_name == NULL ||
@@ -1018,19 +1196,13 @@ static void ipa_subdomains_handler_done(struct tevent_req *req)
         ctx->search_bases = ctx->sd_ctx->master_search_bases;
         ret = ipa_subdomains_handler_get(ctx, IPA_SUBDOMAINS_MASTER);
         if (ret == EAGAIN) {
-            return;
+            return EAGAIN;
         } else if (ret != EOK) {
-            goto done;
+            return ret;
         }
-    } else {
-        ret = EOK;
     }
 
-done:
-    if (ret == EOK) {
-        dp_error = DP_ERR_OK;
-    }
-    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+    return EOK;
 }
 
 
@@ -1328,6 +1500,7 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
     ctx->search_bases = id_ctx->ipa_options->subdomains_search_bases;
     ctx->master_search_bases = id_ctx->ipa_options->master_domain_search_bases;
     ctx->ranges_search_bases = id_ctx->ipa_options->ranges_search_bases;
+    ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
     ctx->configured_explicit = configured_explicit;
     ctx->disabled_until = 0;
     *ops = &ipa_subdomains_ops;
-- 
1.8.3.1

-------------- next part --------------
From 67af15b38eddae85127df4772c31980fa5f23e27 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 17 Sep 2014 15:25:04 +0200
Subject: [PATCH 05/10] views: add ipa_get_ad_override_send()

Related to https://fedorahosted.org/sssd/ticket/2375
---
 Makefile.am                   |   1 +
 src/providers/ipa/ipa_id.h    |  12 ++
 src/providers/ipa/ipa_views.c | 251 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 264 insertions(+)
 create mode 100644 src/providers/ipa/ipa_views.c

diff --git a/Makefile.am b/Makefile.am
index 2e0c190..5dc37bb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2337,6 +2337,7 @@ libsss_ipa_la_SOURCES = \
     src/providers/ipa/ipa_subdomains.c \
     src/providers/ipa/ipa_subdomains_id.c \
     src/providers/ipa/ipa_subdomains_ext_groups.c \
+    src/providers/ipa/ipa_views.c \
     src/providers/ipa/ipa_s2n_exop.c \
     src/providers/ipa/ipa_hbac_hosts.c \
     src/providers/ipa/ipa_hbac_private.h \
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index 9f05d25..b1d68de 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -76,4 +76,16 @@ struct tevent_req *ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
 
 errno_t ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out);
 
+struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct sdap_id_ctx *sdap_id_ctx,
+                                            struct ipa_options *ipa_options,
+                                            const char *ipa_realm,
+                                            const char *view_name,
+                                            const char *obj_sid);
+
+errno_t ipa_get_ad_override_recv(struct tevent_req *req, int *dp_error_out,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct sysdb_attrs **override_attrs);
+
 #endif
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
new file mode 100644
index 0000000..198e60b
--- /dev/null
+++ b/src/providers/ipa/ipa_views.c
@@ -0,0 +1,251 @@
+/*
+    SSSD
+
+    IPA Identity Backend Module for views and overrides
+
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2014 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 "util/util.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ipa/ipa_id.h"
+
+struct ipa_get_ad_override_state {
+    struct tevent_context *ev;
+    struct sdap_id_ctx *sdap_id_ctx;
+    struct ipa_options *ipa_options;
+    const char *ipa_realm;
+    const char *ipa_view_name;
+    const char *obj_sid;
+
+    struct sdap_id_op *sdap_op;
+    int dp_error;
+    struct sysdb_attrs *override_attrs;
+};
+
+static void ipa_get_ad_override_connect_done(struct tevent_req *subreq);
+static void ipa_get_ad_override_done(struct tevent_req *subreq);
+
+struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct sdap_id_ctx *sdap_id_ctx,
+                                            struct ipa_options *ipa_options,
+                                            const char *ipa_realm,
+                                            const char *view_name,
+                                            const char *obj_sid)
+{
+    int ret;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct ipa_get_ad_override_state *state;
+
+    req = tevent_req_create(mem_ctx, &state, struct ipa_get_ad_override_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->sdap_id_ctx = sdap_id_ctx;
+    state->ipa_options = ipa_options;
+    state->ipa_realm = ipa_realm;
+    if (strcmp(view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
+        state->ipa_view_name = IPA_DEFAULT_VIEW_NAME;
+    } else {
+        state->ipa_view_name = view_name;
+    }
+    state->obj_sid = obj_sid;
+    state->dp_error = -1;
+    state->override_attrs = NULL;
+
+    state->sdap_op = sdap_id_op_create(state,
+                                       state->sdap_id_ctx->conn->conn_cache);
+    if (state->sdap_op == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
+                                  ret, strerror(ret));
+        goto done;
+    }
+
+    tevent_req_set_callback(subreq, ipa_get_ad_override_connect_done, req);
+
+    return req;
+
+done:
+    if (ret != EOK) {
+        state->dp_error = DP_ERR_FATAL;
+        tevent_req_error(req, ret);
+    } else {
+        state->dp_error = DP_ERR_OK;
+        tevent_req_done(req);
+    }
+    tevent_req_post(req, state->ev);
+
+    return req;
+}
+
+static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct ipa_get_ad_override_state *state = tevent_req_data(req,
+                                              struct ipa_get_ad_override_state);
+    int ret;
+    char *basedn;
+    char *search_base;
+    char *filter;
+    struct ipa_options *ipa_opts = state->ipa_options;
+
+    ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        if (state->dp_error == DP_ERR_OFFLINE) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "No IPA server is available, going offline\n");
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Failed to connect to IPA server: [%d](%s)\n",
+                   ret, strerror(ret));
+        }
+
+        goto fail;
+    }
+
+    ret = domain_to_basedn(state, state->ipa_realm, &basedn);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
+        goto fail;
+    }
+
+    search_base = talloc_asprintf(state, "cn=%s,%s", state->ipa_view_name,
+                                       ipa_opts->views_search_bases[0]->basedn);
+    if (search_base == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=:SID:%s))",
+                       ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+                       ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
+                       state->obj_sid);
+    if (filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL,
+          "Searching for overrides in view [%s] for object with SID [%s].\n",
+          state->ipa_view_name, state->obj_sid);
+
+    subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
+                                 sdap_id_op_handle(state->sdap_op), search_base,
+                                 LDAP_SCOPE_SUBTREE,
+                                 filter, NULL, state->ipa_options->override_map,
+                                 IPA_OPTS_OVERRIDE,
+                                 dp_opt_get_int(state->sdap_id_ctx->opts->basic,
+                                                SDAP_ENUM_SEARCH_TIMEOUT),
+                                 false);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
+    return;
+
+fail:
+    state->dp_error = DP_ERR_FATAL;
+    tevent_req_error(req, ret);
+    return;
+}
+
+static void ipa_get_ad_override_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct ipa_get_ad_override_state *state = tevent_req_data(req,
+                                              struct ipa_get_ad_override_state);
+    int ret;
+    size_t reply_count;
+    struct sysdb_attrs **reply;
+
+    ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override request failed.\n");
+        goto fail;
+    }
+
+    if (reply_count == 0) {
+        DEBUG(SSSDBG_TRACE_ALL, "No override found for SID [%s].\n",
+                                state->obj_sid);
+        state->dp_error = DP_ERR_OK;
+        tevent_req_done(req);
+        return;
+    } else if (reply_count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found [%zu] overrides for SID [%s], expected only 1.\n",
+              reply_count, state->obj_sid);
+        ret = EINVAL;
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL, "Found override for object with SID [%s].\n",
+                            state->obj_sid);
+
+    state->override_attrs = reply[0];
+    state->dp_error = DP_ERR_OK;
+    tevent_req_done(req);
+    return;
+
+fail:
+    state->dp_error = DP_ERR_FATAL;
+    tevent_req_error(req, ret);
+    return;
+}
+
+errno_t ipa_get_ad_override_recv(struct tevent_req *req, int *dp_error_out,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct sysdb_attrs **override_attrs)
+{
+    struct ipa_get_ad_override_state *state = tevent_req_data(req,
+                                              struct ipa_get_ad_override_state);
+
+    if (dp_error_out != NULL) {
+        *dp_error_out = state->dp_error;
+    }
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    if (override_attrs != NULL) {
+        *override_attrs = talloc_steal(mem_ctx, state->override_attrs);
+    }
+
+    return EOK;
+}
+
-- 
1.8.3.1

-------------- next part --------------
From ff2cf53dc94f8d218ead61b0d9e1f838372337bb Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 22 Sep 2014 12:45:49 +0200
Subject: [PATCH 06/10] sysdb: add sysdb_store_override

---
 src/db/sysdb.h       |   8 ++
 src/db/sysdb_views.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 289 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c2de008..b039a67 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -154,6 +154,8 @@
 #define SYSDB_OVERRIDE_ANCHOR_UUID "overrideAnchorUUID"
 #define SYSDB_OVERRIDE_USER_CLASS "userOverride"
 #define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride"
+#define SYSDB_OVERRIDE_DN "overrideDN"
+#define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN"
 
 #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
 
@@ -224,6 +226,7 @@
 #define SYSDB_TMPL_CUSTOM_SUBTREE "cn=%s,"SYSDB_TMPL_CUSTOM_BASE
 #define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE
 #define SYSDB_TMPL_RANGE SYSDB_NAME"=%s,"SYSDB_TMPL_RANGE_BASE
+#define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,cn=%s,"SYSDB_TMPL_VIEW_BASE
 
 #define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD
 #define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE
@@ -732,6 +735,11 @@ errno_t sysdb_update_members_dn(struct sss_domain_info *member_domain,
                                 const char *const *add_groups,
                                 const char *const *del_groups);
 
+errno_t sysdb_store_override(struct sss_domain_info *domain,
+                             const char *view_name,
+                             enum sysdb_member_type type,
+                             struct sysdb_attrs *attrs, struct ldb_dn *obj_dn);
+
 /* Password caching function.
  * If you are in a transaction ignore sysdb and pass in the handle.
  * If you are not in a transaction pass NULL in handle and provide sysdb,
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 4708a22..dd614b8 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -180,3 +180,284 @@ done:
     return ret;
 }
 
+static errno_t add_aliases_for_name_override(struct sss_domain_info *domain,
+                                             struct sysdb_attrs *attrs,
+                                             const char *name_override)
+{
+    char *fq_name = NULL;
+    int ret;
+
+    if (strchr(name_override, '@') == NULL) {
+        fq_name = sss_tc_fqname(attrs, domain->names, domain, name_override);
+        if (fq_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "sss_tc_fqname failed.\n");
+            return ENOMEM;
+        }
+
+        if (!domain->case_sensitive) {
+            ret = sysdb_attrs_add_lc_name_alias(attrs, fq_name);
+        } else {
+            ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS,
+                                         fq_name);
+        }
+        talloc_free(fq_name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_attrs_add_lc_name_alias failed.\n");
+            return ret;
+        }
+    }
+
+    if (!domain->case_sensitive) {
+        ret = sysdb_attrs_add_lc_name_alias(attrs, name_override);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_attrs_add_lc_name_alias failed.\n");
+            return ret;
+        }
+    }
+
+    return EOK;
+}
+
+errno_t sysdb_store_override(struct sss_domain_info *domain,
+                             const char *view_name,
+                             enum sysdb_member_type type,
+                             struct sysdb_attrs *attrs, struct ldb_dn *obj_dn)
+{
+    TALLOC_CTX *tmp_ctx;
+    const char *anchor;
+    int ret;
+    struct ldb_dn *override_dn;
+    const char *override_dn_str;
+    const char *obj_dn_str;
+    const char *obj_attrs[] = { SYSDB_OBJECTCLASS,
+                                SYSDB_OVERRIDE_DN,
+                                NULL};
+    size_t count = 0;
+    struct ldb_message **msgs;
+    struct ldb_message *msg = NULL;
+    const char *obj_override_dn;
+    bool add_ref = true;
+    size_t c;
+    bool in_transaction = false;
+    bool has_override = true;
+    const char *name_override;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    if (attrs != NULL) {
+        has_override = true;
+        ret = sysdb_attrs_get_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID,
+                                     &anchor);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing anchor in override attributes.\n");
+            ret = EINVAL;
+            goto done;
+        }
+
+        override_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                                     SYSDB_TMPL_OVERRIDE, anchor, view_name);
+        if (override_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+    } else {
+        /* if there is no override for the given object, just store the DN of
+         * the object iself in the SYSDB_OVERRIDE_DN attribute to indicate
+         * that it was checked if an override exists and none was found. */
+        has_override = false;
+        override_dn = obj_dn;
+    }
+
+    override_dn_str = ldb_dn_get_linearized(override_dn);
+    obj_dn_str = ldb_dn_get_linearized(obj_dn);
+    if (override_dn_str == NULL || obj_dn_str == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, obj_dn, LDB_SCOPE_BASE,
+                             NULL, obj_attrs, &count, &msgs);
+    if (ret != EOK) {
+        if (ret == ENOENT) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Object to override does not exists.\n");
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n");
+        }
+        goto done;
+    }
+    if (count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Base searched returned more than one object.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    obj_override_dn = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OVERRIDE_DN,
+                                                  NULL);
+    if (obj_override_dn != NULL) {
+        if (strcmp(obj_override_dn, override_dn_str) != 0) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Existing [%s] and new [%s] override DN do not match.\n",
+                   obj_override_dn, override_dn_str);
+            ret = EINVAL;
+            goto done;
+        }
+
+        add_ref = false;
+    }
+
+    ret = ldb_transaction_start(domain->sysdb->ldb);
+    if (ret != EOK) {
+        return sysdb_error_to_errno(ret);
+    }
+    in_transaction = true;
+
+    if (has_override) {
+        ret = ldb_delete(domain->sysdb->ldb, override_dn);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "ldb_delete failed, maybe object did not exist. Ignoring.\n");
+        }
+
+        ret = sysdb_attrs_get_string(attrs, SYSDB_NAME, &name_override);
+        if (ret == EOK) {
+            ret = add_aliases_for_name_override(domain, attrs, name_override);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "add_aliases_for_name_override failed.\n");
+                goto done;
+            }
+        } else if (ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+            goto done;
+        }
+
+        msg = ldb_msg_new(tmp_ctx);
+        if (msg == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        msg->dn = override_dn;
+
+        msg->elements = talloc_array(msg, struct ldb_message_element,
+                                     attrs->num);
+        if (msg->elements == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        for (c = 0; c < attrs->num; c++) {
+            msg->elements[c] = attrs->a[c];
+            msg->elements[c].flags = LDB_FLAG_MOD_ADD;
+        }
+        msg->num_elements = attrs->num;
+
+        ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_ADD, NULL);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        switch(type) {
+        case SYSDB_MEMBER_USER:
+            ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS,
+                                     SYSDB_OVERRIDE_USER_CLASS);
+            break;
+        case SYSDB_MEMBER_GROUP:
+            ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS,
+                                     SYSDB_OVERRIDE_GROUP_CLASS);
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected object type.\n");
+            ret = EINVAL;
+            goto done;
+        }
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_OBJECT_DN, LDB_FLAG_MOD_ADD,
+                                NULL);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_msg_add_string(msg, SYSDB_OVERRIDE_OBJECT_DN, obj_dn_str);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_add(domain->sysdb->ldb, msg);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Failed to store override entry: %s(%d)[%s]\n",
+                  ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+    }
+
+    if (add_ref) {
+        talloc_free(msg);
+        msg = ldb_msg_new(tmp_ctx);
+        if (msg == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        msg->dn = obj_dn;
+
+        ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_ADD,
+                                NULL);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_msg_add_string(msg, SYSDB_OVERRIDE_DN, override_dn_str);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_modify(domain->sysdb->ldb, msg);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Failed to store override DN: %s(%d)[%s]\n",
+                  ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+    }
+
+    ret = EOK;
+
+done:
+    if (in_transaction) {
+        if (ret != EOK) {
+            DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
+            ldb_transaction_cancel(domain->sysdb->ldb);
+        } else {
+            ret = ldb_transaction_commit(domain->sysdb->ldb);
+            ret = sysdb_error_to_errno(ret);
+        }
+    }
+
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
-- 
1.8.3.1

-------------- next part --------------
From 2edbcae82ab18a45e67dd10375c423988fbaa651 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 22 Sep 2014 18:37:44 +0200
Subject: [PATCH 07/10] sysdb: sysdb_apply_default_override

The default view is special in the sense that it is the baseline for
every other view and that it always applies even if there is no view
defined. To avoid useless additional processing the default view
overrides are written directly to the corresponding cached object.
---
 src/db/sysdb.h       |   4 +
 src/db/sysdb_views.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 199 insertions(+), 13 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index b039a67..b576812 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -430,6 +430,10 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name);
 errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
                             char **view_name);
 
+errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                                     struct sysdb_attrs *override_attrs,
+                                     struct ldb_dn *obj_dn);
+
 /* Sysdb initialization.
  * call this function *only* once to initialize the database and get
  * the sysdb ctx */
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index dd614b8..97c04af 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -180,9 +180,11 @@ done:
     return ret;
 }
 
-static errno_t add_aliases_for_name_override(struct sss_domain_info *domain,
-                                             struct sysdb_attrs *attrs,
-                                             const char *name_override)
+static errno_t
+add_name_and_aliases_for_name_override(struct sss_domain_info *domain,
+                                       struct sysdb_attrs *attrs,
+                                       bool add_name,
+                                       const char *name_override)
 {
     char *fq_name = NULL;
     int ret;
@@ -200,24 +202,37 @@ static errno_t add_aliases_for_name_override(struct sss_domain_info *domain,
             ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS,
                                          fq_name);
         }
-        talloc_free(fq_name);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE,
                   "sysdb_attrs_add_lc_name_alias failed.\n");
-            return ret;
+            goto done;
         }
     }
 
-    if (!domain->case_sensitive) {
-        ret = sysdb_attrs_add_lc_name_alias(attrs, name_override);
+    if (add_name) {
+        ret = sysdb_attrs_add_string(attrs, SYSDB_DEFAULT_OVERRIDE_NAME,
+                                     fq_name == NULL ? name_override : fq_name);
         if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  "sysdb_attrs_add_lc_name_alias failed.\n");
-            return ret;
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n");
+            goto done;
         }
     }
 
-    return EOK;
+    if (!domain->case_sensitive) {
+        ret = sysdb_attrs_add_lc_name_alias(attrs, name_override);
+    } else {
+        ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, name_override);
+    }
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n");
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(fq_name);
+    return ret;
 }
 
 errno_t sysdb_store_override(struct sss_domain_info *domain,
@@ -329,10 +344,11 @@ errno_t sysdb_store_override(struct sss_domain_info *domain,
 
         ret = sysdb_attrs_get_string(attrs, SYSDB_NAME, &name_override);
         if (ret == EOK) {
-            ret = add_aliases_for_name_override(domain, attrs, name_override);
+            ret = add_name_and_aliases_for_name_override(domain, attrs, false,
+                                                         name_override);
             if (ret != EOK) {
                 DEBUG(SSSDBG_OP_FAILURE,
-                      "add_aliases_for_name_override failed.\n");
+                      "add_name_and_aliases_for_name_override failed.\n");
                 goto done;
             }
         } else if (ret != ENOENT) {
@@ -461,3 +477,169 @@ done:
     talloc_zfree(tmp_ctx);
     return ret;
 }
+
+static errno_t safe_original_attributes(struct sss_domain_info *domain,
+                                        struct sysdb_attrs *attrs,
+                                        struct ldb_dn *obj_dn,
+                                        const char **allowed_attrs)
+{
+    int ret;
+    size_t c;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *orig_obj;
+    char *orig_attr_name;
+    struct ldb_message_element *el = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &orig_obj, obj_dn,
+                     LDB_SCOPE_BASE, NULL, NULL);
+    if (ret != EOK || orig_obj->count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Original object not found.\n");
+        goto done;
+    }
+
+    /* Safe orginal values in attributes prefixed by OriginalAD. */
+    for (c = 0; allowed_attrs[c] != NULL; c++) {
+        el = ldb_msg_find_element(orig_obj->msgs[0], allowed_attrs[c]);
+        if (el != NULL) {
+            orig_attr_name = talloc_asprintf(tmp_ctx, "%s%s",
+                                             ORIGINALAD_PREFIX,
+                                             allowed_attrs[c]);
+            if (orig_attr_name == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+
+            ret = sysdb_attrs_add_val(attrs, orig_attr_name,
+                                      &el->values[0]);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sysdb_attrs_add_val failed.\n");
+                goto done;
+            }
+        } else {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "Original object does not have [%s] set.\n",
+                  allowed_attrs[c]);
+        }
+    }
+
+    /* Add existing aliases to new ones */
+    el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_NAME_ALIAS);
+    if (el != NULL) {
+        for (c = 0; c < el->num_values; c++) {
+            /* To avoid issue with ldb_modify if e.g. the orginal and the
+             * override name are the same, we use the *_safe version here. */
+            ret = sysdb_attrs_add_val_safe(attrs, SYSDB_NAME_ALIAS,
+                                           &el->values[c]);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
+                goto done;
+            }
+        }
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t sysdb_apply_default_override(struct sss_domain_info *domain,
+                                     struct sysdb_attrs *override_attrs,
+                                     struct ldb_dn *obj_dn)
+{
+    int ret;
+    TALLOC_CTX *tmp_ctx;
+    struct sysdb_attrs *attrs;
+    size_t c;
+    struct ldb_message_element *el = NULL;
+    const char *allowed_attrs[] = { SYSDB_UIDNUM,
+                                    SYSDB_GIDNUM,
+                                    SYSDB_GECOS,
+                                    SYSDB_HOMEDIR,
+                                    SYSDB_SHELL,
+                                    SYSDB_NAME,
+                                    NULL };
+    bool override_attrs_found = false;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+    attrs = sysdb_new_attrs(tmp_ctx);
+    if (attrs == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (c = 0; allowed_attrs[c] != NULL; c++) {
+        ret = sysdb_attrs_get_el_ext(override_attrs, allowed_attrs[c], false,
+                                     &el);
+        if (ret == EOK) {
+            override_attrs_found = true;
+
+            if (strcmp(allowed_attrs[c], SYSDB_NAME) == 0) {
+                if (el->values[0].data[el->values[0].length] != '\0') {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          "String attribute does not end with \\0.\n");
+                    ret = EINVAL;
+                    goto done;
+                }
+
+                ret = add_name_and_aliases_for_name_override(domain, attrs,
+                                                   true,
+                                                   (char *) el->values[0].data);
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_OP_FAILURE,
+                          "add_name_and_aliases_for_name_override failed.\n");
+                    goto done;
+                }
+            } else {
+                ret = sysdb_attrs_add_val(attrs,  allowed_attrs[c],
+                                          &el->values[0]);
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
+                    goto done;
+                }
+                DEBUG(SSSDBG_TRACE_ALL, "Override [%s] with [%.*s] for [%s].\n",
+                                        allowed_attrs[c],
+                                        (int) el->values[0].length,
+                                        el->values[0].data,
+                                        ldb_dn_get_linearized(obj_dn));
+            }
+        } else if (ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el_ext failed.\n");
+            goto done;
+        }
+    }
+
+    if (override_attrs_found) {
+        ret = safe_original_attributes(domain, attrs, obj_dn, allowed_attrs);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "safe_original_attributes failed.\n");
+            goto done;
+        }
+
+        ret = sysdb_set_entry_attr(domain->sysdb, obj_dn, attrs, SYSDB_MOD_REP);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n");
+            goto done;
+        }
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
-- 
1.8.3.1

-------------- next part --------------
From 920e264a6ca2968aa64a60c3e3586ca29b451b3d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 8 Oct 2014 16:12:52 +0200
Subject: [PATCH 08/10] sysdb: add sysdb_attrs_add_val_safe() and
 sysdb_attrs_add_string_safe()

sysdb_attrs_add_val_safe() works like sysdb_attrs_add_val() but checks
if the attribute value to add already exists. In this case the value
list is not changed. This is useful if values are added from different
sources at different times to avoid LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
errors from ldb_modify() later on.

sysdb_attrs_add_string_safe() does the same for string arguments
---
 src/db/sysdb.c          |  40 ++++++++++++++++++-
 src/db/sysdb.h          |   4 ++
 src/tests/sysdb-tests.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 88cff24..8d6f00b 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -508,18 +508,31 @@ int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
     return EOK;
 }
 
-int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
-                        const char *name, const struct ldb_val *val)
+
+static int sysdb_attrs_add_val_int(struct sysdb_attrs *attrs,
+                                   const char *name, bool check_values,
+                                   const struct ldb_val *val)
 {
     struct ldb_message_element *el = NULL;
     struct ldb_val *vals;
     int ret;
+    size_t c;
 
     ret = sysdb_attrs_get_el(attrs, name, &el);
     if (ret != EOK) {
         return ret;
     }
 
+    if (check_values) {
+        for (c = 0; c < el->num_values; c++) {
+            if (val->length == el->values[c].length
+                    && memcmp(val->data, el->values[c].data,
+                              val->length) == 0) {
+                return EOK;
+            }
+        }
+    }
+
     vals = talloc_realloc(attrs->a, el->values,
                           struct ldb_val, el->num_values+1);
     if (!vals) return ENOMEM;
@@ -535,6 +548,29 @@ int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
 
     return EOK;
 }
+int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
+                        const char *name, const struct ldb_val *val)
+{
+    return sysdb_attrs_add_val_int(attrs, name, false, val);
+}
+
+/* Check if the same value already exists. */
+int sysdb_attrs_add_val_safe(struct sysdb_attrs *attrs,
+                             const char *name, const struct ldb_val *val)
+{
+    return sysdb_attrs_add_val_int(attrs, name, true, val);
+}
+
+int sysdb_attrs_add_string_safe(struct sysdb_attrs *attrs,
+                                const char *name, const char *str)
+{
+    struct ldb_val v;
+
+    v.data = (uint8_t *)discard_const(str);
+    v.length = strlen(str);
+
+    return sysdb_attrs_add_val_safe(attrs, name, &v);
+}
 
 int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
                            const char *name, const char *str)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index b576812..6bb25de 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -287,6 +287,10 @@ struct range_info {
 /* values are copied in the structure, allocated on "attrs" */
 int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
                         const char *name, const struct ldb_val *val);
+int sysdb_attrs_add_val_safe(struct sysdb_attrs *attrs,
+                             const char *name, const struct ldb_val *val);
+int sysdb_attrs_add_string_safe(struct sysdb_attrs *attrs,
+                                const char *name, const char *str);
 int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
                            const char *name, const char *str);
 int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs,
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index c251156..e01ddf4 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4630,6 +4630,106 @@ START_TEST(test_sysdb_attrs_get_string_array)
 }
 END_TEST
 
+START_TEST(test_sysdb_attrs_add_val)
+{
+    int ret;
+    struct sysdb_attrs *attrs;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_val val = {discard_const(TEST_ATTR_VALUE),
+                          sizeof(TEST_ATTR_VALUE) - 1};
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed");
+
+    attrs = sysdb_new_attrs(NULL);
+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+    ret = sysdb_attrs_add_val(attrs, TEST_ATTR_NAME, &val);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    ret = sysdb_attrs_add_val(attrs, TEST_ATTR_NAME, &val);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    fail_unless(attrs->num == 1, "Unexpected number of attributes.");
+    fail_unless(strcmp(attrs->a[0].name, TEST_ATTR_NAME) == 0,
+                "Unexpected attribute name.");
+    fail_unless(attrs->a[0].num_values == 2,
+                "Unexpected number of attribute values.");
+    fail_unless(ldb_val_string_cmp(&attrs->a[0].values[0],
+                                   TEST_ATTR_VALUE) == 0,
+                "Unexpected attribute value.");
+    fail_unless(ldb_val_string_cmp(&attrs->a[0].values[1],
+                                   TEST_ATTR_VALUE) == 0,
+                "Unexpected attribute value.");
+
+    talloc_free(tmp_ctx);
+}
+END_TEST
+
+START_TEST(test_sysdb_attrs_add_val_safe)
+{
+    int ret;
+    struct sysdb_attrs *attrs;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_val val = {discard_const(TEST_ATTR_VALUE),
+                          sizeof(TEST_ATTR_VALUE) - 1};
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed");
+
+    attrs = sysdb_new_attrs(NULL);
+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+    ret = sysdb_attrs_add_val(attrs, TEST_ATTR_NAME, &val);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    ret = sysdb_attrs_add_val_safe(attrs, TEST_ATTR_NAME, &val);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    fail_unless(attrs->num == 1, "Unexpected number of attributes.");
+    fail_unless(strcmp(attrs->a[0].name, TEST_ATTR_NAME) == 0,
+                "Unexpected attribute name.");
+    fail_unless(attrs->a[0].num_values == 1,
+                "Unexpected number of attribute values.");
+    fail_unless(ldb_val_string_cmp(&attrs->a[0].values[0],
+                                   TEST_ATTR_VALUE) == 0,
+                "Unexpected attribute value.");
+
+    talloc_free(tmp_ctx);
+}
+END_TEST
+
+START_TEST(test_sysdb_attrs_add_string_safe)
+{
+    int ret;
+    struct sysdb_attrs *attrs;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed");
+
+    attrs = sysdb_new_attrs(NULL);
+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+    ret = sysdb_attrs_add_string(attrs, TEST_ATTR_NAME, TEST_ATTR_VALUE);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    ret = sysdb_attrs_add_string_safe(attrs, TEST_ATTR_NAME, TEST_ATTR_VALUE);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed.");
+
+    fail_unless(attrs->num == 1, "Unexpected number of attributes.");
+    fail_unless(strcmp(attrs->a[0].name, TEST_ATTR_NAME) == 0,
+                "Unexpected attribute name.");
+    fail_unless(attrs->a[0].num_values == 1,
+                "Unexpected number of attribute values.");
+    fail_unless(ldb_val_string_cmp(&attrs->a[0].values[0],
+                                   TEST_ATTR_VALUE) == 0,
+                "Unexpected attribute value.");
+
+    talloc_free(tmp_ctx);
+}
+END_TEST
+
 START_TEST (test_sysdb_search_return_ENOENT)
 {
     struct sysdb_test_ctx *test_ctx;
@@ -6033,6 +6133,9 @@ Suite *create_sysdb_suite(void)
 
 /* ===== UTIL TESTS ===== */
     tcase_add_test(tc_sysdb, test_sysdb_attrs_get_string_array);
+    tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val);
+    tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val_safe);
+    tcase_add_test(tc_sysdb, test_sysdb_attrs_add_string_safe);
 
 /* ===== Test search return empty result ===== */
     tcase_add_test(tc_sysdb, test_sysdb_search_return_ENOENT);
-- 
1.8.3.1

-------------- next part --------------
From 03e7080994e8a4698f0febf27c41aa27dda86f9b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 23 Sep 2014 13:13:37 +0200
Subject: [PATCH 09/10] views: get overrides during user and group lookups

With this patch the IPA provider will check if overrides exists for the
given view during the lookup of users and groups from trusted domains.
In ipa-server-mode the default view is automatically applied and written
to the cache. On IPA clients which use the extdom plugin for user and
group lookups the override data is saved separately and the original
object and the override data are linked with DN attributes for faster
reference.

Related to https://fedorahosted.org/sssd/ticket/2375
---
 src/providers/ipa/ipa_s2n_exop.c      | 354 ++++++++++++++++++++++++++++------
 src/providers/ipa/ipa_subdomains_id.c | 258 ++++++++++++++++++++-----
 2 files changed, 512 insertions(+), 100 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 6f5fac3..b7ba262 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -674,7 +674,9 @@ done:
 static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
                                     struct req_input *req_input,
                                     struct resp_attrs *attrs,
-                                    struct resp_attrs *simple_attrs);
+                                    struct resp_attrs *simple_attrs,
+                                    const char *view_name,
+                                    struct sysdb_attrs *override_attrs);
 
 static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
                                      char *retoid,
@@ -881,9 +883,11 @@ struct ipa_s2n_get_groups_state {
     char **group_list;
     size_t group_idx;
     int exop_timeout;
+    struct resp_attrs *attrs;
 };
 
 static errno_t ipa_s2n_get_groups_step(struct tevent_req *req);
+static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq);
 static void ipa_s2n_get_groups_next(struct tevent_req *subreq);
 
 static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
@@ -912,6 +916,7 @@ static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
     state->req_input.type = REQ_INP_NAME;
     state->req_input.inp.name = NULL;
     state->exop_timeout = exop_timeout;
+    state->attrs = NULL;
 
     ret = ipa_s2n_get_groups_step(req);
     if (ret != EOK) {
@@ -988,7 +993,7 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
                                                struct ipa_s2n_get_groups_state);
     char *retoid = NULL;
     struct berval *retdata = NULL;
-    struct resp_attrs *attrs;
+    const char *sid_str;
 
     ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
     talloc_zfree(subreq);
@@ -997,13 +1002,59 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
         goto fail;
     }
 
-    ret = s2n_response_to_attrs(state, retoid, retdata, &attrs);
+    talloc_zfree(state->attrs);
+    ret = s2n_response_to_attrs(state, retoid, retdata, &state->attrs);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
         goto fail;
     }
 
-    ret = ipa_s2n_save_objects(state->dom, &state->req_input, attrs, NULL);
+    ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
+                                 &sid_str);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+        goto fail;
+    }
+
+    subreq = ipa_get_ad_override_send(state, state->ev,
+                           state->ipa_ctx->sdap_id_ctx,
+                           state->ipa_ctx->ipa_options,
+                           dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
+                                             IPA_KRB5_REALM),
+                           state->ipa_ctx->view_name,
+                           sid_str);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ipa_s2n_get_groups_get_override_done, req);
+
+    return;
+
+fail:
+    tevent_req_error(req,ret);
+    return;
+}
+
+static void ipa_s2n_get_groups_get_override_done(struct tevent_req *subreq)
+{
+    int ret;
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+                                               struct ipa_s2n_get_groups_state);
+    struct sysdb_attrs *override_attrs = NULL;
+
+    ret = ipa_get_ad_override_recv(subreq, NULL, state, &override_attrs);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
+        goto fail;
+    }
+
+    ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs,
+                               NULL, state->ipa_ctx->view_name, override_attrs);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
         goto fail;
@@ -1046,6 +1097,7 @@ struct ipa_s2n_get_user_state {
     enum request_types request_type;
     struct resp_attrs *attrs;
     struct resp_attrs *simple_attrs;
+    struct resp_attrs *override_attrs;
     int exop_timeout;
 };
 
@@ -1273,6 +1325,7 @@ done:
 }
 
 static void ipa_s2n_get_groups_done(struct tevent_req  *subreq);
+static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq);
 static void ipa_s2n_get_user_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -1286,6 +1339,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
     struct berval *bv_req = NULL;
     char **missing_groups = NULL;
     struct ldb_dn **group_dn_list = NULL;
+    const char *sid_str;
 
     ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
     talloc_zfree(subreq);
@@ -1392,10 +1446,44 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
         goto done;
     }
 
-    ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
-                               state->simple_attrs);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+    if (state->simple_attrs != NULL
+            && state->simple_attrs->response_type == RESP_SID) {
+        sid_str = state->simple_attrs->a.sid_str;
+        ret = EOK;
+    } else if (state->attrs->sysdb_attrs != NULL) {
+        ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
+                                     &sid_str);
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, "No SID available.\n");
+        ret = ENOENT;
+    }
+
+    if (ret == ENOENT) {
+        ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+                                   state->simple_attrs, NULL, NULL);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+            goto done;
+        }
+    } else if (ret == EOK) {
+        subreq = ipa_get_ad_override_send(state, state->ev,
+                           state->ipa_ctx->sdap_id_ctx,
+                           state->ipa_ctx->ipa_options,
+                           dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
+                                             IPA_KRB5_REALM),
+                           state->ipa_ctx->view_name,
+                           sid_str);
+        if (subreq == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+        tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done,
+                                req);
+
+        return;
+    } else {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
         goto done;
     }
 
@@ -1411,17 +1499,23 @@ done:
 static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
                                     struct req_input *req_input,
                                     struct resp_attrs *attrs,
-                                    struct resp_attrs *simple_attrs)
+                                    struct resp_attrs *simple_attrs,
+                                    const char *view_name,
+                                    struct sysdb_attrs *override_attrs)
 {
     int ret;
     time_t now;
     uint64_t timeout = 10*60*60; /* FIXME: find a better timeout ! */
     struct sss_nss_homedir_ctx homedir_ctx;
-    char *name;
+    char *name = NULL;
     char *realm;
-    char *upn;
+    char *upn = NULL;
     gid_t gid;
     TALLOC_CTX *tmp_ctx;
+    const char *sid_str;
+    const char *tmp_str;
+    struct ldb_result *res;
+    enum sysdb_member_type type;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -1440,9 +1534,59 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
         }
     }
 
+    if (attrs->sysdb_attrs != NULL) {
+        ret = sysdb_attrs_get_string(attrs->sysdb_attrs,
+                                     ORIGINALAD_PREFIX SYSDB_NAME, &tmp_str);
+        if (ret == EOK) {
+            name = talloc_strdup(tmp_ctx, tmp_str);
+            if (name == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+            DEBUG(SSSDBG_TRACE_ALL, "Found original AD name [%s].\n", name);
+        } else if (ret == ENOENT) {
+            name = NULL;
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+            goto done;
+        }
+
+        ret = sysdb_attrs_get_string(attrs->sysdb_attrs,
+                                     SYSDB_DEFAULT_OVERRIDE_NAME, &tmp_str);
+        if (ret == EOK) {
+            ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, tmp_str);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sysdb_attrs_add_lc_name_alias failed.\n");
+                goto done;
+            }
+        } else if (ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+            goto done;
+        }
+
+        ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_UPN, &tmp_str);
+        if (ret == EOK) {
+            upn = talloc_strdup(tmp_ctx, tmp_str);
+            if (upn == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+            DEBUG(SSSDBG_TRACE_ALL, "Found original AD upn [%s].\n", upn);
+        } else if (ret == ENOENT) {
+            upn = NULL;
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+            goto done;
+        }
+    }
+
     switch (attrs->response_type) {
         case RESP_USER:
         case RESP_USER_GROUPLIST:
+            type = SYSDB_MEMBER_USER;
             if (dom->subdomain_homedir
                     && attrs->a.user.pw_dir == NULL) {
                 ZERO_STRUCT(homedir_ctx);
@@ -1461,13 +1605,15 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
                 }
             }
 
-            /* we always use the fully qualified name for subdomain users */
-            name = sss_tc_fqname(tmp_ctx, dom->names, dom,
-                                 attrs->a.user.pw_name);
-            if (!name) {
-                DEBUG(SSSDBG_OP_FAILURE, "failed to format user name.\n");
-                ret = ENOMEM;
-                goto done;
+            if (name == NULL) {
+                /* we always use the fully qualified name for subdomain users */
+                name = sss_tc_fqname(tmp_ctx, dom->names, dom,
+                                     attrs->a.user.pw_name);
+                if (!name) {
+                    DEBUG(SSSDBG_OP_FAILURE, "failed to format user name.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
             }
 
             ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
@@ -1477,35 +1623,43 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
                 goto done;
             }
 
-            /* We also have to store a fake UPN here, because otherwise the
-             * krb5 child later won't be able to properly construct one as
-             * the username is fully qualified but the child doesn't have
-             * access to the regex to deconstruct it */
-            /* FIXME: The real UPN is available from the PAC, we should get
-             * it from there. */
-            realm = get_uppercase_realm(tmp_ctx, dom->name);
-            if (!realm) {
-                DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n");
-                ret = ENOMEM;
-                goto done;
-            }
-            upn = talloc_asprintf(tmp_ctx, "%s@%s",
-                                  attrs->a.user.pw_name, realm);
-            if (!upn) {
-                DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
-                ret = ENOMEM;
-                goto done;
-            }
+            if (upn == NULL) {
+                /* We also have to store a fake UPN here, because otherwise the
+                 * krb5 child later won't be able to properly construct one as
+                 * the username is fully qualified but the child doesn't have
+                 * access to the regex to deconstruct it */
+                /* FIXME: The real UPN is available from the PAC, we should get
+                 * it from there. */
+                realm = get_uppercase_realm(tmp_ctx, dom->name);
+                if (!realm) {
+                    DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
+                upn = talloc_asprintf(tmp_ctx, "%s@%s",
+                                      attrs->a.user.pw_name, realm);
+                if (!upn) {
+                    DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
 
-            ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_UPN, upn);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
-                goto done;
+                /* We might already have the SID or the UPN from other sources
+                 * hence sysdb_attrs_add_string_safe is used to avoid double
+                 * entries. */
+                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs, SYSDB_UPN,
+                                                  upn);
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_OP_FAILURE,
+                          "sysdb_attrs_add_string failed.\n");
+                    goto done;
+                }
             }
 
             if (req_input->type == REQ_INP_SECID) {
-                ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
-                                             req_input->inp.secid);
+                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
+                                                  SYSDB_SID_STR,
+                                                  req_input->inp.secid);
                 if (ret != EOK) {
                     DEBUG(SSSDBG_OP_FAILURE,
                           "sysdb_attrs_add_string failed.\n");
@@ -1515,8 +1669,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
 
             if (simple_attrs != NULL
                     && simple_attrs->response_type == RESP_SID) {
-                ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
-                                             simple_attrs->a.sid_str);
+                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
+                                                  SYSDB_SID_STR,
+                                                  simple_attrs->a.sid_str);
                 if (ret != EOK) {
                     DEBUG(SSSDBG_OP_FAILURE,
                           "sysdb_attrs_add_string failed.\n");
@@ -1538,13 +1693,17 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
             break;
         case RESP_GROUP:
         case RESP_GROUP_MEMBERS:
-            /* we always use the fully qualified name for subdomain users */
-            name = sss_tc_fqname(tmp_ctx, dom->names, dom,
-                                 attrs->a.group.gr_name);
-            if (!name) {
-                DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
-                ret = ENOMEM;
-                goto done;
+            type = SYSDB_MEMBER_GROUP;
+
+            if (name == NULL) {
+                /* we always use the fully qualified name for subdomain users */
+                name = sss_tc_fqname(tmp_ctx, dom->names, dom,
+                                     attrs->a.group.gr_name);
+                if (!name) {
+                    DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
             }
 
             ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
@@ -1554,9 +1713,12 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
                 goto done;
             }
 
+            /* We might already have the SID from other sources hence
+             * sysdb_attrs_add_string_safe is used to avoid double entries. */
             if (req_input->type == REQ_INP_SECID) {
-                ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
-                                             req_input->inp.secid);
+                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
+                                                  SYSDB_SID_STR,
+                                                  req_input->inp.secid);
                 if (ret != EOK) {
                     DEBUG(SSSDBG_OP_FAILURE,
                           "sysdb_attrs_add_string failed.\n");
@@ -1566,8 +1728,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
 
             if (simple_attrs != NULL
                 && simple_attrs->response_type == RESP_SID) {
-                ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
-                                             simple_attrs->a.sid_str);
+                ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
+                                                  SYSDB_SID_STR,
+                                                  simple_attrs->a.sid_str);
                 if (ret != EOK) {
                     DEBUG(SSSDBG_OP_FAILURE,
                           "sysdb_attrs_add_string failed.\n");
@@ -1592,6 +1755,27 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
             goto done;
     }
 
+    ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_SID_STR, &sid_str);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Cannot find SID of object with override.\n");
+        goto done;
+    }
+
+    ret = sysdb_search_object_by_sid(tmp_ctx, dom, sid_str, NULL, &res);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Cannot find object with override with SID [%s].\n", sid_str);
+        goto done;
+    }
+
+    ret = sysdb_store_override(dom, view_name, type, override_attrs,
+                               res->msgs[0]->dn);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_override failed.\n");
+        goto done;
+    }
+
 done:
     talloc_free(tmp_ctx);
 
@@ -1605,6 +1789,7 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
                                                       struct tevent_req);
     struct ipa_s2n_get_user_state *state = tevent_req_data(req,
                                                 struct ipa_s2n_get_user_state);
+    const char *sid_str;
 
     ret = ipa_s2n_get_groups_recv(subreq);
     talloc_zfree(subreq);
@@ -1614,8 +1799,63 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
         return;
     }
 
+    ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
+                                 &sid_str);
+    if (ret == ENOENT) {
+        ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+                                   state->simple_attrs, NULL, NULL);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+            goto fail;
+        }
+        tevent_req_done(req);
+        return;
+    } else if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+        goto fail;
+    }
+
+    subreq = ipa_get_ad_override_send(state, state->ev,
+                           state->ipa_ctx->sdap_id_ctx,
+                           state->ipa_ctx->ipa_options,
+                           dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
+                                             IPA_KRB5_REALM),
+                           state->ipa_ctx->view_name,
+                           sid_str);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done, req);
+
+    return;
+
+fail:
+    tevent_req_error(req, ret);
+    return;
+}
+
+static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq)
+{
+    int ret;
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct ipa_s2n_get_user_state *state = tevent_req_data(req,
+                                                struct ipa_s2n_get_user_state);
+    struct sysdb_attrs *override_attrs = NULL;
+
+    ret = ipa_get_ad_override_recv(subreq, NULL, state, &override_attrs);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
+        tevent_req_error(req, ret);
+        return;
+    }
+
     ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
-                               state->simple_attrs);
+                               state->simple_attrs, state->ipa_ctx->view_name,
+                               override_attrs);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
         tevent_req_error(req, ret);
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index d1bd08d..f6cc92e 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -259,9 +259,12 @@ struct ipa_get_ad_acct_state {
     struct be_req *be_req;
     struct be_acct_req *ar;
     struct sss_domain_info *user_dom;
+    char *object_sid;
+    struct ldb_message *obj_msg;
 };
 
 static void ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq);
+static void ipa_get_ad_override_done(struct tevent_req *subreq);
 static void ipa_get_ad_acct_done(struct tevent_req *subreq);
 static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
                                            struct sss_domain_info *dom);
@@ -290,6 +293,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
     state->ipa_ctx = ipa_ctx;
     state->be_req = be_req;
     state->ar = ar;
+    state->obj_msg = NULL;
 
     /* This can only be a subdomain request, verify subdomain */
     state->user_dom = find_domain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
@@ -491,67 +495,50 @@ done:
 
 static errno_t
 apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-                        int filter_type, const char *filter_value)
+                        struct ldb_message *msg)
 {
     errno_t ret;
     uint32_t uid;
     const char *fqname;
     const char *homedir = NULL;
-    struct ldb_result *res = NULL;
-    struct ldb_message *msg = NULL;
-    const char *attrs[] = { SYSDB_NAME,
-                            SYSDB_UIDNUM,
-                            NULL };
+    struct ldb_message_element *msg_el = NULL;
+    size_t c;
 
-    if (filter_type == BE_FILTER_NAME) {
-        ret = sysdb_getpwnam(mem_ctx, dom, filter_value, &res);
-        if (res && res->count == 0) {
-            ret = ENOENT;
-        }
-    } else if (filter_type == BE_FILTER_IDNUM) {
-        errno = 0;
-        uid = strtouint32(filter_value, NULL, 10);
-        if (errno != 0) {
-            ret = errno;
-            goto done;
-        }
-        ret = sysdb_getpwuid(mem_ctx, dom, uid, &res);
-        if (res && res->count == 0) {
-            ret = ENOENT;
-        }
-    } else if (filter_type == BE_FILTER_SECID) {
-        ret = sysdb_search_user_by_sid_str(mem_ctx, dom, filter_value,
-                                           attrs, &msg);
-    } else {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "Unsupported filter type: [%d].\n", filter_type);
-        ret = EINVAL;
+    msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS);
+    if (msg_el == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_find_element failed.\n");
+        ret = ENOENT;
         goto done;
     }
 
-    if (ret != EOK && ret != ENOENT) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "Failed to make request to our cache: [%d]: [%s]\n",
-               ret, sss_strerror(ret));
-        goto done;
-    } else if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_FUNC, "Cannot find [%s] with search type [%d]\n",
-              filter_value, filter_type);
+    for (c = 0; c < msg_el->num_values; c++) {
+        if (strncmp(SYSDB_USER_CLASS, (const char *)msg_el->values[c].data,
+                    msg_el->values[c].length) == 0) {
+            break;
+        }
+    }
+    if (c == msg_el->num_values) {
+        DEBUG(SSSDBG_TRACE_ALL,
+              "User objectclass not found, object is not a user.\n");
+        ret = ENOENT;
         goto done;
     }
 
-    if (res != NULL) {
-        msg = res->msgs[0];
-    }
     /*
      * Homedir is always overriden by subdomain_homedir even if it was
      * explicitly set by user.
      */
     fqname = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+    if (fqname == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
     uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
     if (uid == 0) {
         DEBUG(SSSDBG_OP_FAILURE, "UID for user [%s] is not known.\n",
-                                  filter_value);
+                                  fqname);
         ret = ENOENT;
         goto done;
     }
@@ -576,6 +563,115 @@ done:
     return ret;
 }
 
+static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
+                                     struct sss_domain_info *dom,
+                                     struct be_acct_req *ar,
+                                     struct ldb_message **_msg)
+{
+    errno_t ret;
+    uint32_t id;
+    struct ldb_message *msg = NULL;
+    struct ldb_result *res = NULL;
+    const char *attrs[] = { SYSDB_NAME,
+                            SYSDB_UIDNUM,
+                            SYSDB_SID_STR,
+                            SYSDB_OBJECTCLASS,
+                            NULL };
+    char *name;
+
+    if (ar->filter_type == BE_FILTER_SECID) {
+        ret = sysdb_search_object_by_sid(mem_ctx, dom, ar->filter_value, attrs,
+                                         &res);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Failed to make request to our cache: [%d]: [%s]\n",
+                   ret, sss_strerror(ret));
+            goto done;
+        }
+
+        *_msg = res->msgs[0];
+
+        ret = EOK;
+        goto done;
+    }
+
+    if (ar->filter_type == BE_FILTER_IDNUM) {
+        errno = 0;
+        id = strtouint32(ar->filter_value, NULL, 10);
+        if (errno != 0) {
+            ret = errno;
+            DEBUG(SSSDBG_OP_FAILURE, "strtouint32 failed.\n");
+            goto done;
+        }
+
+        switch (ar->entry_type & BE_REQ_TYPE_MASK) {
+        case BE_REQ_GROUP:
+            ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
+            break;
+        case BE_REQ_INITGROUPS:
+        case BE_REQ_USER:
+        case BE_REQ_USER_AND_GROUP:
+            ret = sysdb_search_user_by_uid(mem_ctx, dom, id, attrs, &msg);
+            if (ret == ENOENT && (ar->entry_type & BE_REQ_TYPE_MASK)
+                                                     == BE_REQ_USER_AND_GROUP) {
+                ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
+            }
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d].\n",
+                                        (ar->entry_type & BE_REQ_TYPE_MASK));
+            ret = EINVAL;
+            goto done;
+        }
+    } else if (ar->filter_type == BE_FILTER_NAME) {
+        name = sss_get_domain_name(mem_ctx, ar->filter_value, dom);
+        if (name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_name failed\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        switch (ar->entry_type & BE_REQ_TYPE_MASK) {
+        case BE_REQ_GROUP:
+            ret = sysdb_search_group_by_name(mem_ctx, dom, name, attrs, &msg);
+            break;
+        case BE_REQ_INITGROUPS:
+        case BE_REQ_USER:
+        case BE_REQ_USER_AND_GROUP:
+            ret = sysdb_search_user_by_name(mem_ctx, dom, name, attrs, &msg);
+            if (ret == ENOENT && (ar->entry_type & BE_REQ_TYPE_MASK)
+                                                     == BE_REQ_USER_AND_GROUP) {
+                ret = sysdb_search_group_by_name(mem_ctx, dom, name,
+                                                 attrs, &msg);
+            }
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d].\n",
+                                        (ar->entry_type & BE_REQ_TYPE_MASK));
+            ret = EINVAL;
+            goto done;
+        }
+    } else {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected filter type.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Failed to make request to our cache: [%d]: [%s]\n",
+               ret, sss_strerror(ret));
+        goto done;
+    }
+
+    *_msg = msg;
+
+    ret = EOK;
+
+done:
+    return ret;
+}
+
 static void
 ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
 {
@@ -584,6 +680,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
     struct ipa_get_ad_acct_state *state = tevent_req_data(req,
                                                 struct ipa_get_ad_acct_state);
     errno_t ret;
+    const char *sid;
 
     ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
     talloc_zfree(subreq);
@@ -593,9 +690,15 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
         return;
     }
 
+    ret = get_object_from_cache(state, state->user_dom, state->ar,
+                                &state->obj_msg);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
+        goto fail;
+    }
+
     ret = apply_subdomain_homedir(state, state->user_dom,
-                                  state->ar->filter_type,
-                                  state->ar->filter_value);
+                                  state->obj_msg);
     if (ret != EOK && ret != ENOENT) {
         DEBUG(SSSDBG_OP_FAILURE,
               "apply_subdomain_homedir failed: [%d]: [%s].\n",
@@ -603,6 +706,74 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
         goto fail;
     }
 
+    sid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_SID_STR, NULL);
+    if (sid == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find a SID.\n");
+        ret = EINVAL;
+        goto fail;
+    }
+
+    state->object_sid = talloc_strdup(state, sid);
+    if (state->object_sid == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    subreq = ipa_get_ad_override_send(state, state->ev,
+                                      state->ipa_ctx->sdap_id_ctx,
+                                      state->ipa_ctx->ipa_options,
+                                      state->ipa_ctx->server_mode->realm,
+                                      state->ipa_ctx->view_name,
+                                      state->object_sid);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
+
+    return;
+
+fail:
+    state->dp_error = DP_ERR_FATAL;
+    tevent_req_error(req, ret);
+    return;
+}
+
+
+static void
+ipa_get_ad_override_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                struct tevent_req);
+    struct ipa_get_ad_acct_state *state = tevent_req_data(req,
+                                                struct ipa_get_ad_acct_state);
+    errno_t ret;
+    struct sysdb_attrs *override_attrs = NULL;
+
+    ret = ipa_get_ad_override_recv(subreq, &state->dp_error, state,
+                                   &override_attrs);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
+        tevent_req_error(req, ret);
+        return;
+
+    }
+
+    if (override_attrs != NULL) {
+        /* We are in ipa-server-mode, so the view is the default view by
+         * definition. */
+        ret = sysdb_apply_default_override(state->user_dom,
+                                           override_attrs,
+                                           state->obj_msg->dn);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_apply_default_override failed.\n");
+            goto fail;
+        }
+    }
+
     if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) {
         tevent_req_done(req);
         return;
@@ -645,6 +816,7 @@ ipa_get_ad_acct_done(struct tevent_req *subreq)
                                   ret);
         tevent_req_error(req, ret);
         return;
+
     }
 
     tevent_req_done(req);
-- 
1.8.3.1

-------------- next part --------------
From fc86653f7304853bcc819397e2509f8bf11b4c0e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 1 Oct 2014 17:04:44 +0200
Subject: [PATCH 10/10] views: search overrides for user and group requests

If the name or the POSIX ID of a user or a group is overridden the
search request for those objects have to check the overide objects first
before looking up the original objects.

This patch adds a new request for the IPA sub-domain users which checks
the overrides first if
- SSSD is running in ipa-server-mode and a name or a POSIX ID is
  searched, since we do not override the SIDs we can skip the search in
  the override tree here
- if the responder indicates it has not found the corresponding object
  in the cache and the input might be an override name or ID and not the
  original one of an object.

If an override object was found the SID is extracted from the anchor
attribute and the original object is search by its SID. If no override
object was found the original object is search with the original input
and finally it is checked if an override object exits for the found
object.

Relates to https://fedorahosted.org/sssd/ticket/2375
---
 src/providers/data_provider.h         |   1 +
 src/providers/ipa/ipa_id.c            |  18 +-
 src/providers/ipa/ipa_id.h            |  31 ++-
 src/providers/ipa/ipa_s2n_exop.c      |  83 ++++++--
 src/providers/ipa/ipa_subdomains_id.c | 385 ++++++++++++++++++++++++++++++----
 src/providers/ipa/ipa_views.c         | 181 ++++++++++++++--
 6 files changed, 598 insertions(+), 101 deletions(-)

diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index ec5b79d..e1cb4be 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -148,6 +148,7 @@
 #define DP_SEC_ID_LEN (sizeof(DP_SEC_ID) - 1)
 
 #define EXTRA_NAME_IS_UPN "U"
+#define EXTRA_INPUT_MAYBE_WITH_VIEW "V"
 
 /* AUTH related common data and functions */
 
diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
index 942feb1..cd65f5b 100644
--- a/src/providers/ipa/ipa_id.c
+++ b/src/providers/ipa/ipa_id.c
@@ -87,11 +87,8 @@ void ipa_account_info_handler(struct be_req *breq)
          * subdomain lookups are handled differently on the server
          * and the client
          */
-        if (dp_opt_get_bool(ipa_ctx->ipa_options->basic, IPA_SERVER_MODE)) {
-            req = ipa_get_ad_acct_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
-        } else {
-            req = ipa_get_subdom_acct_send(breq, be_ctx->ev, ipa_ctx, ar);
-        }
+        req = ipa_subdomain_account_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
+
     } else if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
         /* netgroups are handled by a separate request function */
         if (ar->filter_type != BE_FILTER_NAME) {
@@ -116,24 +113,15 @@ void ipa_account_info_handler(struct be_req *breq)
 static void ipa_account_info_done(struct tevent_req *req)
 {
     struct be_req *breq = tevent_req_callback_data(req, struct be_req);
-    struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
-    struct ipa_id_ctx *ipa_ctx;
     struct be_acct_req *ar = talloc_get_type(be_req_get_data(breq),
                                              struct be_acct_req);
     const char *error_text;
     int ret, dp_error;
 
-    ipa_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
-                              struct ipa_id_ctx);
-
     if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
         ret = ipa_id_get_netgroup_recv(req, &dp_error);
     } else {
-        if (dp_opt_get_bool(ipa_ctx->ipa_options->basic, IPA_SERVER_MODE)) {
-            ret = ipa_get_ad_acct_recv(req, &dp_error);
-        } else {
-            ret = ipa_get_subdom_acct_recv(req, &dp_error);
-        }
+        ret = ipa_subdomain_account_recv(req, &dp_error);
     }
     talloc_zfree(req);
 
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index b1d68de..e13aded 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -53,18 +53,20 @@ int ipa_get_netgroups_recv(struct tevent_req *req,
 void ipa_check_online(struct be_req *be_req);
 
 struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
-                                              struct tevent_context *ev,
-                                              struct ipa_id_ctx *ipa_ctx,
-                                              struct sdap_options *opts,
-                                              struct sss_domain_info *dom,
-                                              struct sdap_handle *sh,
-                                              int entry_type,
-                                              struct req_input *req_input);
+                                             struct tevent_context *ev,
+                                             struct ipa_id_ctx *ipa_ctx,
+                                             struct sdap_options *opts,
+                                             struct sss_domain_info *dom,
+                                             struct sysdb_attrs *override_attrs,
+                                             struct sdap_handle *sh,
+                                             int entry_type,
+                                             struct req_input *req_input);
 int ipa_s2n_get_acct_info_recv(struct tevent_req *req);
 
 struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
                                             struct tevent_context *ev,
                                             struct ipa_id_ctx *ipa_ctx,
+                                            struct sysdb_attrs *override_attrs,
                                             struct be_acct_req *ar);
 int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out);
 
@@ -72,20 +74,33 @@ struct tevent_req *ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
                                         struct tevent_context *ev,
                                         struct ipa_id_ctx *ipa_ctx,
                                         struct be_req *be_req,
+                                        struct sysdb_attrs *override_attrs,
                                         struct be_acct_req *ar);
 
 errno_t ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out);
 
+errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+                                const char *domain_name,
+                                struct be_acct_req **_ar);
+
 struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
                                             struct tevent_context *ev,
                                             struct sdap_id_ctx *sdap_id_ctx,
                                             struct ipa_options *ipa_options,
                                             const char *ipa_realm,
                                             const char *view_name,
-                                            const char *obj_sid);
+                                            struct be_acct_req *ar);
 
 errno_t ipa_get_ad_override_recv(struct tevent_req *req, int *dp_error_out,
                                  TALLOC_CTX *mem_ctx,
                                  struct sysdb_attrs **override_attrs);
 
+struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
+                                              struct tevent_context *ev,
+                                              struct ipa_id_ctx *ipa_ctx,
+                                              struct be_req *be_req,
+                                              struct be_acct_req *ar);
+
+errno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out);
+
 #endif
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index b7ba262..64c3b3e 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -884,6 +884,7 @@ struct ipa_s2n_get_groups_state {
     size_t group_idx;
     int exop_timeout;
     struct resp_attrs *attrs;
+    struct sss_domain_info *obj_domain;
 };
 
 static errno_t ipa_s2n_get_groups_step(struct tevent_req *req);
@@ -940,7 +941,6 @@ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
                                                struct ipa_s2n_get_groups_state);
     struct berval *bv_req;
     struct tevent_req *subreq;
-    struct sss_domain_info *obj_domain;
     struct sss_domain_info *parent_domain;
     char *group_name = NULL;
     char *domain_name = NULL;
@@ -957,15 +957,15 @@ static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
         return ret;
     }
 
-    obj_domain = find_domain_by_name(parent_domain, domain_name, true);
-    if (obj_domain == NULL) {
+    state->obj_domain = find_domain_by_name(parent_domain, domain_name, true);
+    if (state->obj_domain == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
         return ENOMEM;
     }
 
     state->req_input.inp.name = group_name;
 
-    ret = s2n_encode_request(state, obj_domain->name, BE_REQ_GROUP,
+    ret = s2n_encode_request(state, state->obj_domain->name, BE_REQ_GROUP,
                              REQ_FULL_WITH_MEMBERS,
                              &state->req_input, &bv_req);
     if (ret != EOK) {
@@ -994,6 +994,7 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
     char *retoid = NULL;
     struct berval *retdata = NULL;
     const char *sid_str;
+    struct be_acct_req *ar;
 
     ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
     talloc_zfree(subreq);
@@ -1016,13 +1017,19 @@ static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
         goto fail;
     }
 
+    ret = get_be_acct_req_for_sid(state, sid_str, state->obj_domain->name, &ar);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+        goto fail;
+    }
+
     subreq = ipa_get_ad_override_send(state, state->ev,
                            state->ipa_ctx->sdap_id_ctx,
                            state->ipa_ctx->ipa_options,
                            dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
                                              IPA_KRB5_REALM),
                            state->ipa_ctx->view_name,
-                           sid_str);
+                           ar);
     if (subreq == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
         ret = ENOMEM;
@@ -1097,20 +1104,21 @@ struct ipa_s2n_get_user_state {
     enum request_types request_type;
     struct resp_attrs *attrs;
     struct resp_attrs *simple_attrs;
-    struct resp_attrs *override_attrs;
+    struct sysdb_attrs *override_attrs;
     int exop_timeout;
 };
 
 static void ipa_s2n_get_user_done(struct tevent_req *subreq);
 
 struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
-                                              struct tevent_context *ev,
-                                              struct ipa_id_ctx *ipa_ctx,
-                                              struct sdap_options *opts,
-                                              struct sss_domain_info *dom,
-                                              struct sdap_handle *sh,
-                                              int entry_type,
-                                              struct req_input *req_input)
+                                             struct tevent_context *ev,
+                                             struct ipa_id_ctx *ipa_ctx,
+                                             struct sdap_options *opts,
+                                             struct sss_domain_info *dom,
+                                             struct sysdb_attrs *override_attrs,
+                                             struct sdap_handle *sh,
+                                             int entry_type,
+                                             struct req_input *req_input)
 {
     struct ipa_s2n_get_user_state *state;
     struct tevent_req *req;
@@ -1134,6 +1142,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
     state->attrs = NULL;
     state->simple_attrs = NULL;
     state->exop_timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
+    state->override_attrs = override_attrs;
 
     if (sdap_is_extension_supported(sh, EXOP_SID2NAME_V1_OID)) {
         state->request_type = REQ_FULL_WITH_MEMBERS;
@@ -1340,6 +1349,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
     char **missing_groups = NULL;
     struct ldb_dn **group_dn_list = NULL;
     const char *sid_str;
+    struct be_acct_req *ar;
 
     ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
     talloc_zfree(subreq);
@@ -1453,6 +1463,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
     } else if (state->attrs->sysdb_attrs != NULL) {
         ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
                                      &sid_str);
+    } else if (state->req_input->type == REQ_INP_SECID) {
+        sid_str = state->req_input->inp.secid;
+        ret = EOK;
     } else {
         DEBUG(SSSDBG_TRACE_FUNC, "No SID available.\n");
         ret = ENOENT;
@@ -1466,13 +1479,19 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
             goto done;
         }
     } else if (ret == EOK) {
+        ret = get_be_acct_req_for_sid(state, sid_str, state->dom->name, &ar);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+            goto done;
+        }
+
         subreq = ipa_get_ad_override_send(state, state->ev,
                            state->ipa_ctx->sdap_id_ctx,
                            state->ipa_ctx->ipa_options,
                            dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
                                              IPA_KRB5_REALM),
                            state->ipa_ctx->view_name,
-                           sid_str);
+                           ar);
         if (subreq == NULL) {
             DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
             ret = ENOMEM;
@@ -1790,6 +1809,7 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
     struct ipa_s2n_get_user_state *state = tevent_req_data(req,
                                                 struct ipa_s2n_get_user_state);
     const char *sid_str;
+    struct be_acct_req *ar;
 
     ret = ipa_s2n_get_groups_recv(subreq);
     talloc_zfree(subreq);
@@ -1815,19 +1835,40 @@ static void ipa_s2n_get_groups_done(struct tevent_req  *subreq)
         goto fail;
     }
 
-    subreq = ipa_get_ad_override_send(state, state->ev,
+    ret = get_be_acct_req_for_sid(state, sid_str, state->dom->name, &ar);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+        goto fail;
+    }
+
+    if (state->override_attrs == NULL) {
+        subreq = ipa_get_ad_override_send(state, state->ev,
                            state->ipa_ctx->sdap_id_ctx,
                            state->ipa_ctx->ipa_options,
                            dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
                                              IPA_KRB5_REALM),
                            state->ipa_ctx->view_name,
-                           sid_str);
-    if (subreq == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
-        ret = ENOMEM;
-        goto fail;
+                           ar);
+        if (subreq == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+            ret = ENOMEM;
+            goto fail;
+        }
+        tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done,
+                                req);
+    } else {
+        ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+                                   state->simple_attrs,
+                                   state->ipa_ctx->view_name,
+                                   state->override_attrs);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+            tevent_req_error(req, ret);
+            return;
+        }
+
+        tevent_req_done(req);
     }
-    tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done, req);
 
     return;
 
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index f6cc92e..9e190ff 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -34,6 +34,277 @@
 #include "providers/ad/ad_id.h"
 #include "providers/ipa/ipa_subdomains.h"
 
+struct ipa_subdomain_account_state {
+    struct tevent_context *ev;
+    struct ipa_id_ctx *ipa_ctx;
+    struct sdap_id_ctx *ctx;
+    struct sdap_id_op *op;
+    struct sysdb_ctx *sysdb;
+    struct sss_domain_info *domain;
+    struct be_req *be_req;
+    struct be_acct_req *ar;
+
+    bool ipa_server_mode;
+    int entry_type;
+    const char *filter;
+    int filter_type;
+    struct sysdb_attrs *override_attrs;
+
+    int dp_error;
+};
+
+static void ipa_subdomain_account_connected(struct tevent_req *subreq);
+static void ipa_subdomain_account_got_override(struct tevent_req *subreq);
+static void ipa_subdomain_account_done(struct tevent_req *subreq);
+static errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
+                                                       struct be_acct_req *ar);
+
+struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
+                                              struct tevent_context *ev,
+                                              struct ipa_id_ctx *ipa_ctx,
+                                              struct be_req *be_req,
+                                              struct be_acct_req *ar)
+{
+    struct tevent_req *req;
+    struct ipa_subdomain_account_state *state;
+    struct tevent_req *subreq;
+    int ret;
+
+    req = tevent_req_create(memctx, &state, struct ipa_subdomain_account_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
+         return NULL;
+    }
+
+    state->ev = ev;
+    state->ipa_ctx = ipa_ctx;
+    state->ctx = ipa_ctx->sdap_id_ctx;
+    state->dp_error = DP_ERR_FATAL;
+
+    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
+    if (!state->op) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    state->domain = find_domain_by_name(state->ctx->be->domain,
+                                        ar->domain, true);
+    if (state->domain == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+    state->sysdb = state->domain->sysdb;
+    state->be_req = be_req;
+    state->ar = ar;
+    state->ipa_server_mode = dp_opt_get_bool(state->ipa_ctx->ipa_options->basic,
+                                             IPA_SERVER_MODE);
+    state->override_attrs = NULL;
+
+    /* With views we cannot got directly to the look up the AD objects but
+     * have to check first if the request matches an override in the given
+     * view. But there are cases where this can be skipped and the AD object
+     * can be searched directly:
+     * - searches by SID: because we do not override the SID
+     * - if the responder does not send the EXTRA_INPUT_MAYBE_WITH_VIEW flags,
+     *   because in this case the entry was found in the cache and the
+     *   original value is used for the search (e.g. during cache updates) */
+    if (state->ar->filter_type == BE_FILTER_SECID
+            || (!state->ipa_server_mode
+                && state->ar->extra_value != NULL
+                && strcmp(state->ar->extra_value,
+                          EXTRA_INPUT_MAYBE_WITH_VIEW) != 0 ))  {
+        ret = ipa_subdomain_account_get_original_step(req, state->ar);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "ipa_subdomain_account_get_original_step failed.\n");
+            goto fail;
+        }
+
+        return req;
+    }
+
+    subreq = sdap_id_op_connect_send(state->op, state, &ret);
+    if (!subreq) {
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ipa_subdomain_account_connected, req);
+
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void ipa_subdomain_account_connected(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                struct tevent_req);
+    struct ipa_subdomain_account_state *state = tevent_req_data(req,
+                                            struct ipa_subdomain_account_state);
+    int dp_error = DP_ERR_FATAL;
+    int ret;
+
+    ret = sdap_id_op_connect_recv(subreq, &dp_error);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect request failed.\n");
+        goto fail;
+    }
+
+    subreq = ipa_get_ad_override_send(state, state->ev, state->ctx,
+                          state->ipa_ctx->ipa_options,
+                          dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
+                                            IPA_KRB5_REALM),
+                          state->ipa_ctx->view_name, state->ar);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, ipa_subdomain_account_got_override, req);
+
+    return;
+
+fail:
+    state->dp_error = dp_error;
+    tevent_req_error(req, ret);
+    return;
+}
+
+#define OVERRIDE_ANCHOR_SID_PREFIX ":SID:"
+#define OVERRIDE_ANCHOR_SID_PREFIX_LEN (sizeof(OVERRIDE_ANCHOR_SID_PREFIX) -1 )
+
+static void ipa_subdomain_account_got_override(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                struct tevent_req);
+    struct ipa_subdomain_account_state *state = tevent_req_data(req,
+                                            struct ipa_subdomain_account_state);
+    int dp_error = DP_ERR_FATAL;
+    int ret;
+    const char *anchor;
+    struct be_acct_req *ar;
+
+    ret = ipa_get_ad_override_recv(subreq, &dp_error, state,
+                                   &state->override_attrs);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
+        goto fail;
+    }
+
+    if (state->override_attrs != NULL) {
+        ret = sysdb_attrs_get_string(state->override_attrs,
+                                     SYSDB_OVERRIDE_ANCHOR_UUID,
+                                     &anchor);
+        if (strncmp(OVERRIDE_ANCHOR_SID_PREFIX, anchor,
+                    OVERRIDE_ANCHOR_SID_PREFIX_LEN) == 0) {
+
+            ret = get_be_acct_req_for_sid(state,
+                                        anchor + OVERRIDE_ANCHOR_SID_PREFIX_LEN,
+                                        state->ar->domain,
+                                        &ar);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+                goto fail;
+            }
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Unsupported override anchor type [%s].\n", anchor);
+            ret = EINVAL;
+            goto fail;
+        }
+    } else {
+        ar = state->ar;
+    }
+
+    ret = ipa_subdomain_account_get_original_step(req, ar);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "ipa_subdomain_account_get_original_step failed.\n");
+        goto fail;
+    }
+
+    return;
+
+fail:
+    state->dp_error = dp_error;
+    tevent_req_error(req, ret);
+    return;
+}
+
+static errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
+                                                       struct be_acct_req *ar)
+{
+    struct ipa_subdomain_account_state *state = tevent_req_data(req,
+                                            struct ipa_subdomain_account_state);
+    struct tevent_req *subreq;
+
+    if (state->ipa_server_mode) {
+        subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
+                                      state->be_req, state->override_attrs, ar);
+    } else {
+        subreq = ipa_get_subdom_acct_send(state, state->ev, state->ipa_ctx,
+                                          state->override_attrs, ar);
+    }
+
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct_send failed.\n");
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(subreq, ipa_subdomain_account_done, req);
+
+    return EOK;
+}
+
+
+static void ipa_subdomain_account_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                struct tevent_req);
+    struct ipa_subdomain_account_state *state = tevent_req_data(req,
+                                            struct ipa_subdomain_account_state);
+    int dp_error = DP_ERR_FATAL;
+    int ret;
+
+    if (state->ipa_server_mode) {
+        ret = ipa_get_ad_acct_recv(subreq, &dp_error);
+    } else {
+        ret = ipa_get_subdom_acct_recv(subreq, &dp_error);
+    }
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct request failed: %d\n", ret);
+        state->dp_error = dp_error;
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    state->dp_error = DP_ERR_OK;
+    tevent_req_done(req);
+    return;
+}
+
+errno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out)
+{
+    struct ipa_subdomain_account_state *state = tevent_req_data(req,
+                                            struct ipa_subdomain_account_state);
+
+    if (dp_error_out) {
+        *dp_error_out = state->dp_error;
+    }
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
 struct ipa_get_subdom_acct {
     struct tevent_context *ev;
     struct ipa_id_ctx *ipa_ctx;
@@ -41,6 +312,7 @@ struct ipa_get_subdom_acct {
     struct sdap_id_op *op;
     struct sysdb_ctx *sysdb;
     struct sss_domain_info *domain;
+    struct sysdb_attrs *override_attrs;
 
     int entry_type;
     const char *filter;
@@ -55,6 +327,7 @@ static void ipa_get_subdom_acct_done(struct tevent_req *subreq);
 struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
                                             struct tevent_context *ev,
                                             struct ipa_id_ctx *ipa_ctx,
+                                            struct sysdb_attrs *override_attrs,
                                             struct be_acct_req *ar)
 {
     struct tevent_req *req;
@@ -69,6 +342,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
     state->ipa_ctx = ipa_ctx;
     state->ctx = ipa_ctx->sdap_id_ctx;
     state->dp_error = DP_ERR_FATAL;
+    state->override_attrs = override_attrs;
 
     state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
     if (!state->op) {
@@ -189,6 +463,7 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq)
                                         state->ipa_ctx,
                                         state->ctx->opts,
                                         state->domain,
+                                        state->override_attrs,
                                         sdap_id_op_handle(state->op),
                                         state->entry_type,
                                         req_input);
@@ -260,11 +535,13 @@ struct ipa_get_ad_acct_state {
     struct be_acct_req *ar;
     struct sss_domain_info *user_dom;
     char *object_sid;
+    struct sysdb_attrs *override_attrs;
     struct ldb_message *obj_msg;
 };
 
 static void ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq);
 static void ipa_get_ad_override_done(struct tevent_req *subreq);
+static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req);
 static void ipa_get_ad_acct_done(struct tevent_req *subreq);
 static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
                                            struct sss_domain_info *dom);
@@ -274,6 +551,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
                      struct tevent_context *ev,
                      struct ipa_id_ctx *ipa_ctx,
                      struct be_req *be_req,
+                     struct sysdb_attrs *override_attrs,
                      struct be_acct_req *ar)
 {
     errno_t ret;
@@ -294,6 +572,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
     state->be_req = be_req;
     state->ar = ar;
     state->obj_msg = NULL;
+    state->override_attrs = override_attrs;
 
     /* This can only be a subdomain request, verify subdomain */
     state->user_dom = find_domain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
@@ -681,6 +960,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
                                                 struct ipa_get_ad_acct_state);
     errno_t ret;
     const char *sid;
+    struct be_acct_req *ar;
 
     ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
     talloc_zfree(subreq);
@@ -706,32 +986,48 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
         goto fail;
     }
 
-    sid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_SID_STR, NULL);
-    if (sid == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find a SID.\n");
-        ret = EINVAL;
-        goto fail;
-    }
+    if (state->override_attrs == NULL) {
+        sid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_SID_STR, NULL);
+        if (sid == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find a SID.\n");
+            ret = EINVAL;
+            goto fail;
+        }
 
-    state->object_sid = talloc_strdup(state, sid);
-    if (state->object_sid == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-        ret = ENOMEM;
-        goto fail;
-    }
+        state->object_sid = talloc_strdup(state, sid);
+        if (state->object_sid == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+            ret = ENOMEM;
+            goto fail;
+        }
 
-    subreq = ipa_get_ad_override_send(state, state->ev,
-                                      state->ipa_ctx->sdap_id_ctx,
-                                      state->ipa_ctx->ipa_options,
-                                      state->ipa_ctx->server_mode->realm,
-                                      state->ipa_ctx->view_name,
-                                      state->object_sid);
-    if (subreq == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
-        ret = ENOMEM;
-        goto fail;
+        ret = get_be_acct_req_for_sid(state, state->object_sid,
+                                      state->user_dom->name, &ar);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
+            goto fail;
+        }
+
+        subreq = ipa_get_ad_override_send(state, state->ev,
+                                          state->ipa_ctx->sdap_id_ctx,
+                                          state->ipa_ctx->ipa_options,
+                                          state->ipa_ctx->server_mode->realm,
+                                          state->ipa_ctx->view_name,
+                                          ar);
+        if (subreq == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
+            ret = ENOMEM;
+            goto fail;
+        }
+        tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
+    } else {
+        ret = ipa_get_ad_apply_override_step(req);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "ipa_get_ad_apply_override_step failed.\n");
+            goto fail;
+        }
     }
-    tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
 
     return;
 
@@ -750,10 +1046,9 @@ ipa_get_ad_override_done(struct tevent_req *subreq)
     struct ipa_get_ad_acct_state *state = tevent_req_data(req,
                                                 struct ipa_get_ad_acct_state);
     errno_t ret;
-    struct sysdb_attrs *override_attrs = NULL;
 
     ret = ipa_get_ad_override_recv(subreq, &state->dp_error, state,
-                                   &override_attrs);
+                                   &state->override_attrs);
     talloc_zfree(subreq);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
@@ -762,21 +1057,42 @@ ipa_get_ad_override_done(struct tevent_req *subreq)
 
     }
 
-    if (override_attrs != NULL) {
+    ret = ipa_get_ad_apply_override_step(req);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_apply_override_step failed.\n");
+        goto fail;
+    }
+
+    return;
+
+fail:
+    state->dp_error = DP_ERR_FATAL;
+    tevent_req_error(req, ret);
+    return;
+}
+
+static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
+{
+    struct ipa_get_ad_acct_state *state = tevent_req_data(req,
+                                                struct ipa_get_ad_acct_state);
+    errno_t ret;
+    struct tevent_req *subreq;
+
+    if (state->override_attrs != NULL) {
         /* We are in ipa-server-mode, so the view is the default view by
          * definition. */
         ret = sysdb_apply_default_override(state->user_dom,
-                                           override_attrs,
+                                           state->override_attrs,
                                            state->obj_msg->dn);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE, "sysdb_apply_default_override failed.\n");
-            goto fail;
+            return ret;
         }
     }
 
     if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) {
         tevent_req_done(req);
-        return;
+        return EOK;
     }
 
     /* For initgroups request we have to check IPA group memberships of AD
@@ -787,17 +1103,12 @@ ipa_get_ad_override_done(struct tevent_req *subreq)
                                          state->ipa_ctx->sdap_id_ctx,
                                          state->ipa_ctx->server_mode->realm);
     if (subreq == NULL) {
-        ret = ENOMEM;
-        goto fail;
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_memberships_send failed.\n");
+        return ENOMEM;
     }
     tevent_req_set_callback(subreq, ipa_get_ad_acct_done, req);
 
-    return;
-
-fail:
-    state->dp_error = DP_ERR_FATAL;
-    tevent_req_error(req, ret);
-    return;
+    return EOK;
 }
 
 static void
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
index 198e60b..9053f54 100644
--- a/src/providers/ipa/ipa_views.c
+++ b/src/providers/ipa/ipa_views.c
@@ -23,20 +23,163 @@
 */
 
 #include "util/util.h"
+#include "util/strtonum.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ipa/ipa_id.h"
 
+static errno_t be_acct_req_to_override_filter(TALLOC_CTX *mem_ctx,
+                                              struct ipa_options *ipa_opts,
+                                              struct be_acct_req *ar,
+                                              char **override_filter)
+{
+    char *filter;
+    uint32_t id;
+    char *endptr;
+
+    switch (ar->filter_type) {
+    case BE_FILTER_NAME:
+        switch ((ar->entry_type & BE_REQ_TYPE_MASK)) {
+        case BE_REQ_USER:
+        case BE_REQ_INITGROUPS:
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
+                         ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+                         ipa_opts->override_map[IPA_AT_OVERRIDE_USER_NAME].name,
+                         ar->filter_value);
+            break;
+
+         case BE_REQ_GROUP:
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))",
+                        ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+                        ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_NAME].name,
+                        ar->filter_value);
+            break;
+
+         case BE_REQ_USER_AND_GROUP:
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
+                        ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+                        ipa_opts->override_map[IPA_AT_OVERRIDE_USER_NAME].name,
+                        ar->filter_value,
+                        ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_NAME].name,
+                        ar->filter_value);
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d] for name filter.\n",
+                                       ar->entry_type);
+            return EINVAL;
+        }
+        break;
+
+    case BE_FILTER_IDNUM:
+        errno = 0;
+        id = strtouint32(ar->filter_value, &endptr, 10);
+        if (errno != 0|| *endptr != '\0' || (ar->filter_value == endptr)) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Invalid id value [%s].\n",
+                                       ar->filter_value);
+            return EINVAL;
+        }
+        switch ((ar->entry_type & BE_REQ_TYPE_MASK)) {
+        case BE_REQ_USER:
+        case BE_REQ_INITGROUPS:
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%"PRIu32"))",
+                        ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+                        ipa_opts->override_map[IPA_AT_OVERRIDE_UID_NUMBER].name,
+                        id);
+            break;
+
+         case BE_REQ_GROUP:
+            filter = talloc_asprintf(mem_ctx,
+                  "(&(objectClass=%s)(%s=%"PRIu32"))",
+                  ipa_opts->override_map[IPA_OC_OVERRIDE_GROUP].name,
+                  ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_GID_NUMBER].name,
+                  id);
+            break;
+
+         case BE_REQ_USER_AND_GROUP:
+            filter = talloc_asprintf(mem_ctx,
+                  "(&(objectClass=%s)(|(%s=%"PRIu32")(%s=%"PRIu32")))",
+                  ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+                  ipa_opts->override_map[IPA_AT_OVERRIDE_UID_NUMBER].name,
+                  id,
+                  ipa_opts->override_map[IPA_AT_OVERRIDE_GROUP_GID_NUMBER].name,
+                  id);
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Unexpected entry type [%d] for id filter.\n",
+                  ar->entry_type);
+            return EINVAL;
+        }
+        break;
+
+    case BE_FILTER_SECID:
+        if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_SECID) {
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=:SID:%s))",
+                       ipa_opts->override_map[IPA_OC_OVERRIDE].name,
+                       ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
+                       ar->filter_value);
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Unexpected entry type [%d] for SID filter.\n",
+                  ar->entry_type);
+            return EINVAL;
+        }
+        break;
+
+    default:
+        DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
+        return EINVAL;
+    }
+
+    if (filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        return ENOMEM;
+    }
+
+    *override_filter = filter;
+
+    return EOK;
+}
+
+errno_t get_be_acct_req_for_sid(TALLOC_CTX *mem_ctx, const char *sid,
+                                const char *domain_name,
+                                struct be_acct_req **_ar)
+{
+    struct be_acct_req *ar;
+
+    ar = talloc_zero(mem_ctx, struct be_acct_req);
+    if (ar == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+        return ENOMEM;
+    }
+
+    ar->entry_type = BE_REQ_BY_SECID;
+    ar->filter_type = BE_FILTER_SECID;
+    ar->filter_value = talloc_strdup(ar, sid);
+    ar->domain = talloc_strdup(ar, domain_name);
+    if (ar->filter_value == NULL || ar->domain == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+        talloc_free(ar);
+        return ENOMEM;
+    }
+
+
+    *_ar = ar;
+
+    return EOK;
+}
+
 struct ipa_get_ad_override_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *sdap_id_ctx;
     struct ipa_options *ipa_options;
     const char *ipa_realm;
     const char *ipa_view_name;
-    const char *obj_sid;
+    struct be_acct_req *ar;
 
     struct sdap_id_op *sdap_op;
     int dp_error;
     struct sysdb_attrs *override_attrs;
+    char *filter;
 };
 
 static void ipa_get_ad_override_connect_done(struct tevent_req *subreq);
@@ -48,7 +191,7 @@ struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
                                             struct ipa_options *ipa_options,
                                             const char *ipa_realm,
                                             const char *view_name,
-                                            const char *obj_sid)
+                                            struct be_acct_req *ar)
 {
     int ret;
     struct tevent_req *req;
@@ -70,9 +213,10 @@ struct tevent_req *ipa_get_ad_override_send(TALLOC_CTX *mem_ctx,
     } else {
         state->ipa_view_name = view_name;
     }
-    state->obj_sid = obj_sid;
+    state->ar = ar;
     state->dp_error = -1;
     state->override_attrs = NULL;
+    state->filter = NULL;
 
     state->sdap_op = sdap_id_op_create(state,
                                        state->sdap_id_ctx->conn->conn_cache);
@@ -115,7 +259,6 @@ static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
     int ret;
     char *basedn;
     char *search_base;
-    char *filter;
     struct ipa_options *ipa_opts = state->ipa_options;
 
     ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
@@ -147,24 +290,22 @@ static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
         goto fail;
     }
 
-    filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=:SID:%s))",
-                       ipa_opts->override_map[IPA_OC_OVERRIDE].name,
-                       ipa_opts->override_map[IPA_AT_OVERRIDE_ANCHOR_UUID].name,
-                       state->obj_sid);
-    if (filter == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
-        ret = ENOMEM;
+    ret = be_acct_req_to_override_filter(state, state->ipa_options, state->ar,
+                                         &state->filter);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "be_acct_req_to_override_filter failed.\n");
         goto fail;
     }
 
     DEBUG(SSSDBG_TRACE_ALL,
-          "Searching for overrides in view [%s] for object with SID [%s].\n",
-          state->ipa_view_name, state->obj_sid);
+          "Searching for overrides in view [%s] with filter [%s].\n",
+          state->ipa_view_name, state->filter);
 
     subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
                                  sdap_id_op_handle(state->sdap_op), search_base,
                                  LDAP_SCOPE_SUBTREE,
-                                 filter, NULL, state->ipa_options->override_map,
+                                 state->filter, NULL,
+                                 state->ipa_options->override_map,
                                  IPA_OPTS_OVERRIDE,
                                  dp_opt_get_int(state->sdap_id_ctx->opts->basic,
                                                 SDAP_ENUM_SEARCH_TIMEOUT),
@@ -202,21 +343,21 @@ static void ipa_get_ad_override_done(struct tevent_req *subreq)
     }
 
     if (reply_count == 0) {
-        DEBUG(SSSDBG_TRACE_ALL, "No override found for SID [%s].\n",
-                                state->obj_sid);
+        DEBUG(SSSDBG_TRACE_ALL, "No override found with filter [%s].\n",
+                                state->filter);
         state->dp_error = DP_ERR_OK;
         tevent_req_done(req);
         return;
     } else if (reply_count > 1) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "Found [%zu] overrides for SID [%s], expected only 1.\n",
-              reply_count, state->obj_sid);
+              "Found [%zu] overrides with filter [%s], expected only 1.\n",
+              reply_count, state->filter);
         ret = EINVAL;
         goto fail;
     }
 
-    DEBUG(SSSDBG_TRACE_ALL, "Found override for object with SID [%s].\n",
-                            state->obj_sid);
+    DEBUG(SSSDBG_TRACE_ALL, "Found override for object with filter [%s].\n",
+                            state->filter);
 
     state->override_attrs = reply[0];
     state->dp_error = DP_ERR_OK;
-- 
1.8.3.1



More information about the sssd-devel mailing list