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

Sumit Bose sbose at redhat.com
Mon Sep 29 11:01:32 UTC 2014


On Mon, Sep 29, 2014 at 11:52:52AM +0200, Pavel Březina wrote:
> On 09/26/2014 04:36 PM, Sumit Bose wrote:
> >On Fri, Sep 26, 2014 at 01:41:39PM +0200, Pavel Březina wrote:
> >>On 09/26/2014 01:38 PM, Pavel Březina wrote:
> >>>On Wed, Sep 24, 2014 at 10:25:22AM +0200, Sumit Bose wrote:
> >>>>Hi,
> >>>>
> >>>>this patches contain the IPA provider part of
> >>>>https://fedorahosted.org/sssd/ticket/2375  as described in the FreeIPA
> >>>>design page
> >>>>http://www.freeipa.org/page/V4/Migrating_existing_environments_to_Trust
> >>>>
> >>>>Patches 0001, 0006 and 0007 contain new sysdb interfaces for views and
> >>>>overrides. 0002 and 0003 refactor some already existing calls.
> >>>>
> >>>>0004 adds the initial support for views and overrides and reads the view
> >>>>name for the client from the FreeIPA server or sets it to 'default' when
> >>>>running in ipa-server-mode. It adds some new options which currently
> >>>>misses man page entries and are not added to the python config API. I
> >>>>did this on purpose for the time being because I wanted to see first if
> >>>>the list is complete or if some options ca be dropped.
> >>>>
> >>>>0005 adds the request to get a specific override from the FreeIPA server
> >>>>and finally in 0008 the overrides are read during a request and saves or
> >>>>applied.
> >>>>
> >>>>This patches must be applied on to of the extdom patch I send yesterday.
> >>>>To add and manage views and override on the server side please have a
> >>>>look at Tomas's patch set on the freeipa-devel list
> >>>>(https://www.redhat.com/archives/freeipa-devel/2014-September/msg00336.html).
> >>>>
> >>>>
> >>>>bye,
> >>>>Sumit
> >
> >Pavel, Jakub, thank you for the review.
> >
> >>>
> >>>>From dedbb5ae2faa13d396e84ce9911ab1e9c0246836 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/8] sysdb: add sysdb_update_view_name()
> >>>
> >>>ACK
> >>>
> >>>A unit test for the functions would be nice in order to avoid decreasing
> >>>the code coverage of the sysdb module, but I realize we have a deadline.
> >>>We should file a ticket, though.
> >
> >yes, I feel quite bad about the missing test, but my plan is to add them
> >after the dealine
> >
> >>>
> >>>It would also be nice to add a comment that it's not possible to have a
> >>>view w/o a name but we are trying to be on the safe side b/c name is not
> >>>MUST as we discussed on IRC with Sumit.
> >
> >done
> 
> Ack.
> 
> >>>
> >>>>From c09a8553d7371e46b84e980f38d017c7f84c2f87 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/8] Add sdap_deref_search_with_filter_send()
> >>>
> >>>I would prefer to also add a matching _done and _recv functions, even if
> >>>they were wrappers around existing functions. But tevent coding style is
> >>>important to follow, we already had bugs about reusing a single tevent
> >>>callbacks for multiple requests.
> 
> >+    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;
> >+    }
> 
> 
> Would it be possible to use sdap_has_deref_support() instead of manually
> testing the support for OpenLDAP deref or you can't use ASQ for some reason?

no, afaik ASQ can only do base searches and follow the references in the
given DN, so adding a filter won't work.

> 
> >
> >done
> >
> >>>
> >>>We can do it post-rebase, though. Just please file a ticket.
> >>>
> >>>
> >>>>From 3097c76ba9498b90df69935d24dc9ce55f602937 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/8] IPA: make IPA ID context available to extdom
> >>>>client code
> >>>
> >>>ACK
> 
> Still Ack.
> 
> >>>
> >>>...aaand I stopped here.
> >>>
> >>>That was Jakub's part of the review.
> >>>
> >>>Patch 4: IPA: add view support and get 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 llokup later\n");
> >>>                                          ^ typo
> >
> >fixed
> >
> >>>>+            } else {
> >>>>+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name
> >>>>failed.\n");
> >>>>+                goto done;
> >>>>+            }
> >>>>+        }
> >>>
> >>>>     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;
> >>>
> >>>This change seems to be unrelated to this patch. Shouldn't it be a
> >>>separate commit?
> >
> >no, the view name is an attribute of the host object so we must be able
> >to search it.
> 
> Ok. Typo is still there, I'm sending a trivial patch. Feel free to squash
> it.

squashed in.

> 
> Ack.
> 
> >
> >>>
> >>>Patch 5: views: add ipa_get_ad_override_send()
> >>>
> >>>Looks good, but can you add some more tracing debug messages there? For
> >>>example what view are we searching for and that an override was found.
> >
> >done
> 
> Ack.
> 
> >
> >>>
> >>>Patch 6:
> >>>
> >>>>+    const char *obj_attrs[] = { SYSDB_OBJECTCLASS,
> >>>>+                              SYSDB_OVERRIDE_DN,
> >>>>+                                   NULL};
> >>>
> >>>Indentation.
> >
> >fixed
> >
> >>>
> >>>>+        if (ret != EOK) {
> >>>>+            DEBUG(SSSDBG_CRIT_FAILURE,
> >>>>+                  "Missing anchor in overide attributes.\n");
> >>>                                            ^ typo
> >
> >fixed
> >
> >>>>+            ret = EINVAL;
> >>>>+            goto done;
> >>>>+        }
> >>>
> >>>>+    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;
> >>>>+    }
> >>>
> >>>Can you use if (ret == ENOENT) else if (ret != EOK) here? I think it is
> >>>simpler.
> >
> >I prefer it the other way, becasue I think it makes it more clear that
> >it is an error in all cases and only adds a special messages for the
> >ENOENT case.
> 
> Ok.
> 
> >
> >>>
> >>>>+    if (obj_override_dn != NULL) {
> >>>>+        if (strcmp(obj_override_dn, override_dn_str) != 0) {
> >>>>+            DEBUG(SSSDBG_CRIT_FAILURE,
> >>>>+                  "Existing [%s] and new [%s] overid DN do not
> >>>>match.\n",
> >>>                                                  ^ typo
> >
> >fixed
> >
> >>>>+                   obj_override_dn, override_dn_str);
> >>>>+            ret = EINVAL;
> >>>>+            goto done;
> >>>>+        }
> >>>>+
> >>>>+        add_ref = false;
> >>>
> >+    }
> 
> >+        case SYSDB_MEMBER_GROUP:
> >+            ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS,
> >+                                     SYSDB_OVERRIDE_USER_CLASS);
> >+            break;
> 
> Shouldn't it say SYSDB_OVERRIDE_GROUP_CLASS?

D'oh, fixed.

> 
> >>>
> >>>Patch 7: sysdb: sysdb_apply_default_override
> >>>
> >>>Ack.
> 
> Ack stays, but can you clarify what is the intended use case of this
> function in the commit message please?

Comment added.

> 
> >>>
> >>>Patch 8: views: get overrides during user and group lookups
> >>>
> >>>Ack.
> 
> >    if (override_attrs != NULL) {
> >        ret = sysdb_apply_default_override(state->user_dom->sysdb,
> >                                           override_attrs,
> >                                           state->obj_msg->dn);
> >        if (ret != EOK) {
> >            DEBUG(SSSDBG_OP_FAILURE, "sysdb_apply_default_override failed.\n");
> >            goto fail;
> >        }
> >    }
> 
> I thought the sysdb_apply_default_override is used to override original
> object in sysdb with information from the default view. This looks like it
> is overwritten with data from whatever view we are using.

This code path is in ipa-server-mode where the default view is
hardcoded/fixed by definition. I added a comment to make this clear.

> 
> >>
> >>BTW I checked out your repo. The patches couldn't be applied to master even
> >>with the extdom patch here on the list.
> >
> >I send a new version of the extdom patch as well all rebase on master, I
> >hope it will work now.
> >
> >New version attached.
> >
> >bye,
> >Sumit
> 
> I get this warning:
> /home/pbrezina/workspace/sssd/src/providers/ipa/ipa_views.c: In function
> 'ipa_get_ad_override_done':
> /home/pbrezina/workspace/sssd/src/providers/ipa/ipa_views.c:207:9: error:
> format '%d' expects argument of type 'int', but argument 6 has type 'size_t'
> [-Werror=format]

Your fix is squashed in.

Thank you for the review. New version attached.

bye,
Sumit

> 
> 
> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From 76a1612288d2217157dd5ea7cb9745b0a0fa691a 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/8] 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 b5554c1c984c6cd82eaaeda8755d06b7898f3020 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/8] 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 a8ea531..ab7ac45 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);
@@ -2527,6 +2530,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,
@@ -2566,7 +2632,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 13a96d67040575e9e32bfe0fedad358e101a0fa0 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/8] 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 80cc3c8..5793a60 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -845,6 +845,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;
@@ -858,6 +859,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,
@@ -873,6 +875,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;
@@ -1005,6 +1008,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;
@@ -1020,6 +1024,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,
@@ -1039,6 +1044,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;
@@ -1293,7 +1299,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 78963d9b62aad5eb8f722e4b8889d1c43ec88356 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/8] 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     |  27 ++++++
 src/providers/ipa/ipa_init.c       |  65 +++++++++----
 src/providers/ipa/ipa_opts.h       |  23 +++++
 src/providers/ipa/ipa_subdomains.c | 186 +++++++++++++++++++++++++++++++++++--
 6 files changed, 321 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..2207604 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,28 @@ 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_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,
+    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 +143,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 +154,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 +163,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_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..50f4921 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -44,6 +44,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 +72,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 +946,129 @@ 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_ALL, "No view found, using default");
+            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_ALL, "Found view name [%s].\n", 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 +1131,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 +1189,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 +1493,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 839bb877e4f7aab60847a5141c1eaea6400b187b 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/8] 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 | 247 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 260 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 9a255ff..bbce549 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -74,4 +74,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..8cca402
--- /dev/null
+++ b/src/providers/ipa/ipa_views.c
@@ -0,0 +1,247 @@
+/*
+    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 *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;
+    state->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->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->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 e733f191e77bb0c52b09dff79f2903aa593f8239 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/8] sysdb: add sysdb_store_override

---
 src/db/sysdb.h       |   7 ++
 src/db/sysdb_views.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 233 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index ede96bc..6381475 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,10 @@ 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 sysdb_ctx *sysdb, 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..6a9b36b 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -180,3 +180,229 @@ done:
     return ret;
 }
 
+errno_t sysdb_store_override(struct sysdb_ctx *sysdb, 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;
+
+    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, 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, 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(sysdb->ldb);
+    if (ret != EOK) {
+        return sysdb_error_to_errno(ret);
+    }
+    in_transaction = true;
+
+    if (has_override) {
+        ret = ldb_delete(sysdb->ldb, override_dn);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "ldb_delete failed, maybe object did not exist. Ignoring.\n");
+        }
+
+        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(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(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(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(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(sysdb->ldb);
+        } else {
+            ret = ldb_transaction_commit(sysdb->ldb);
+            ret = sysdb_error_to_errno(ret);
+        }
+    }
+
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
-- 
1.8.3.1

-------------- next part --------------
From f1576dc717c2a997f8f191238b6414298a41ce65 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/8] 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 | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 6381475..8af5454 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 sysdb_ctx *sysdb,
+                                     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 6a9b36b..d4c97cd 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -406,3 +406,70 @@ done:
     talloc_zfree(tmp_ctx);
     return ret;
 }
+
+errno_t sysdb_apply_default_override(struct sysdb_ctx *sysdb,
+                                     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));
+        } 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(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 333974b793196f811bcaa1e399e267dc489c4f1a 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/8] 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      | 182 ++++++++++++++++++++++--
 src/providers/ipa/ipa_subdomains_id.c | 258 ++++++++++++++++++++++++++++------
 2 files changed, 387 insertions(+), 53 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 5793a60..aae222e 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -645,7 +645,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,
@@ -852,9 +854,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,
@@ -883,6 +887,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) {
@@ -959,7 +964,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);
@@ -968,13 +973,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;
@@ -1017,6 +1068,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;
 };
 
@@ -1244,6 +1296,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,
@@ -1257,6 +1310,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);
@@ -1363,10 +1417,34 @@ 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");
+    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 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;
     }
 
@@ -1382,7 +1460,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;
@@ -1393,6 +1473,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) {
@@ -1414,6 +1497,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);
@@ -1509,6 +1593,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);
@@ -1563,6 +1648,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->sysdb, 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);
 
@@ -1576,6 +1682,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);
@@ -1585,8 +1692,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..5238045 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->sysdb,
+                                           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



More information about the sssd-devel mailing list