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

Sumit Bose sbose at redhat.com
Wed Oct 1 18:14:21 UTC 2014


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.

bye,
Sumit
> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From 658cfb90ea991a81f766b4e952446874243a0806 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 1/9] 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 86a0572..bc93d34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -664,6 +664,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 901b612..41fd3c5 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"
@@ -138,6 +140,10 @@
 #define SYSDB_DOMAIN_ID "domainID"
 #define SYSDB_ID_RANGE_TYPE "idRangeType"
 
+#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
@@ -403,6 +409,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 8dec44076bbf90b69aa80e8c885ed59cfe95a0c9 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 2/9] 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 fde573eea7e80ec1ea45a6391b17e4982d8148c6 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 3/9] 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 76494a0..bfe1f50 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -866,6 +866,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;
@@ -879,6 +880,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,
@@ -894,6 +896,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;
@@ -1026,6 +1029,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;
@@ -1041,6 +1045,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,
@@ -1060,6 +1065,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;
@@ -1314,7 +1320,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 750533ac7d6b6697c063b5347d4f5b0901c86c34 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 4/9] 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 41fd3c5..ede96bc 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -143,6 +143,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 f3c9c6c8d56782def944b80e2a9f542bba81ddb7 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 5/9] 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 bc93d34..61b8169 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2330,6 +2330,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 32e0fed2e50fab8fd19b94e264855b49e2ecec38 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 6/9] 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 ede96bc..b77e822 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -147,6 +147,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"=*)"
 
@@ -215,6 +217,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
@@ -723,6 +726,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 38ad60f67820076b45ce0e33c96a651f3dd5ca70 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 7/9] 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 | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index b77e822..b30d268 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -421,6 +421,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..3f22f3b 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -461,3 +461,87 @@ done:
     talloc_zfree(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;
+            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));
+
+            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_aliases_for_name_override(domain, attrs,
+                                                   (char *) el->values[0].data);
+                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_el_ext failed.\n");
+            goto done;
+        }
+    }
+
+    if (override_attrs_found) {
+        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 66e85fb0c42f258a3353920e09f76b00b075e53f 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 8/9] 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      | 192 +++++++++++++++++++++++--
 src/providers/ipa/ipa_subdomains_id.c | 258 ++++++++++++++++++++++++++++------
 2 files changed, 397 insertions(+), 53 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index bfe1f50..545bcd7 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -666,7 +666,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,
@@ -873,9 +875,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,
@@ -904,6 +908,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) {
@@ -980,7 +985,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);
@@ -989,13 +994,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;
@@ -1038,6 +1089,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;
 };
 
@@ -1265,6 +1317,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,
@@ -1278,6 +1331,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);
@@ -1384,10 +1438,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;
     }
 
@@ -1403,7 +1491,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)
 {
     int ret;
     time_t now;
@@ -1414,6 +1504,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
     char *upn;
     gid_t gid;
     TALLOC_CTX *tmp_ctx;
+    const char *sid_str;
+    struct ldb_result *res;
+    enum sysdb_member_type type;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -1435,6 +1528,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
     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);
@@ -1530,6 +1624,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
             break;
         case RESP_GROUP:
         case RESP_GROUP_MEMBERS:
+            type = SYSDB_MEMBER_GROUP;
             /* we always use the fully qualified name for subdomain users */
             name = sss_tc_fqname(tmp_ctx, dom->names, dom,
                                  attrs->a.group.gr_name);
@@ -1584,6 +1679,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);
 
@@ -1597,6 +1713,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);
@@ -1606,8 +1723,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 a0e4d94033f68b3d61ae75de2c125ceaaa931d1c 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 9/9] 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      |  80 +++++--
 src/providers/ipa/ipa_subdomains_id.c | 394 ++++++++++++++++++++++++++++++----
 src/providers/ipa/ipa_views.c         | 177 +++++++++++++--
 6 files changed, 607 insertions(+), 94 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 545bcd7..d6c52ad 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -876,6 +876,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);
@@ -932,7 +933,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;
@@ -949,15 +949,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) {
@@ -986,6 +986,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);
@@ -1008,13 +1009,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;
@@ -1089,20 +1096,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;
@@ -1126,6 +1134,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;
@@ -1332,6 +1341,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);
@@ -1458,13 +1468,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;
@@ -1714,6 +1730,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);
@@ -1739,19 +1756,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..1371fd1 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -34,6 +34,286 @@
 #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;
+
+    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;
+    }
+
+#if 0
+    if (state->ipa_server_mode) {
+        subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
+                                      state->be_req, ar);
+    } else {
+        subreq = ipa_get_subdom_acct_send(state, state->ev, state->ipa_ctx, ar);
+    }
+
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct_send failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, ipa_subdomain_account_done, req);
+#endif
+
+    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 +321,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 +336,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 +351,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 +472,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 +544,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 +560,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 +581,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 +969,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 +995,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 +1055,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 +1066,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 +1112,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..fe8a7e6 100644
--- a/src/providers/ipa/ipa_views.c
+++ b/src/providers/ipa/ipa_views.c
@@ -23,20 +23,161 @@
 */
 
 #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:
+            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:
+            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 +189,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 +211,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 +257,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,6 +288,14 @@ static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
         goto fail;
     }
 
+    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;
+    }
+
+#if 0
     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,
@@ -156,15 +305,17 @@ static void ipa_get_ad_override_connect_done(struct tevent_req *subreq)
         ret = ENOMEM;
         goto fail;
     }
+#endif
 
     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 +353,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