>From b6767736b642cbab1569ed2889e9d43bdbd1beb2 Mon Sep 17 00:00:00 2001
From: Michal Zidek <mzidek@redhat.com>
Date: Wed, 10 Sep 2014 12:56:54 +0200
Subject: [PATCH 2/2] Use the alternative objectclass in group maps.

Use the alternative group objectclass in queries.

Fixes:
https://fedorahosted.org/sssd/ticket/2436
---
 src/providers/ldap/ldap_id.c                  | 18 ++++++----
 src/providers/ldap/sdap.c                     | 40 ++++++++++++++++++---
 src/providers/ldap/sdap.h                     |  2 ++
 src/providers/ldap/sdap_async_enum.c          | 12 +++++--
 src/providers/ldap/sdap_async_initgroups.c    | 50 +++++++++++++++++++++------
 src/providers/ldap/sdap_async_initgroups_ad.c | 13 +++++--
 src/providers/ldap/sdap_async_nested_groups.c | 11 ++++--
 7 files changed, 117 insertions(+), 29 deletions(-)

diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index eb349f3..e8b3a0e 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -540,6 +540,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
     enum idmap_error_code err;
     char *sid;
     const char *member_filter[2];
+    char *oc_list;
 
     req = tevent_req_create(memctx, &state, struct groups_get_state);
     if (!req) return NULL;
@@ -645,21 +646,26 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
         goto done;
     }
 
+    oc_list = sdap_make_oc_list(state, ctx->opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
     if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
         /* When mapping IDs or looking for SIDs, we don't want to limit
          * ourselves to groups with a GID value
          */
 
         state->filter = talloc_asprintf(state,
-                                        "(&(%s=%s)(objectclass=%s)(%s=*))",
-                                        attr_name, clean_name,
-                                        ctx->opts->group_map[SDAP_OC_GROUP].name,
+                                        "(&(%s=%s)(%s)(%s=*))",
+                                        attr_name, clean_name, oc_list,
                                         ctx->opts->group_map[SDAP_AT_GROUP_NAME].name);
     } else {
         state->filter = talloc_asprintf(state,
-                                        "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
-                                        attr_name, clean_name,
-                                        ctx->opts->group_map[SDAP_OC_GROUP].name,
+                                        "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))",
+                                        attr_name, clean_name, oc_list,
                                         ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
                                         ctx->opts->group_map[SDAP_AT_GROUP_GID].name,
                                         ctx->opts->group_map[SDAP_AT_GROUP_GID].name);
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index ff50f8b..7034b11 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -290,6 +290,8 @@ int sdap_get_map(TALLOC_CTX *memctx,
 
 /* =Parse-msg============================================================= */
 
+static bool objectclass_matched(struct sdap_attr_map *map,
+                                const char *objcl, int len);
 int sdap_parse_entry(TALLOC_CTX *memctx,
                      struct sdap_handle *sh, struct sdap_msg *sm,
                      struct sdap_attr_map *map, int attrs_num,
@@ -348,9 +350,7 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
         }
 
         for (i = 0; vals[i]; i++) {
-            /* the objectclass is always the first name in the map */
-            if (strncasecmp(map[0].name,
-                            vals[i]->bv_val, vals[i]->bv_len) == 0) {
+            if (objectclass_matched(map, vals[i]->bv_val, vals[i]->bv_len)) {
                 /* ok it's an entry of the right type */
                 break;
             }
@@ -530,6 +530,25 @@ done:
     return ret;
 }
 
+static bool objectclass_matched(struct sdap_attr_map *map,
+                                const char *objcl, int len)
+{
+    if (len == 0) {
+        len = strlen(objcl) + 1;
+    }
+
+    if (strncasecmp(map[SDAP_OC_GROUP].name, objcl, len) == 0) {
+        return true;
+    }
+
+    if (map[SDAP_OC_GROUP_ALT].name != NULL
+        && strncasecmp(map[SDAP_OC_GROUP_ALT].name, objcl, len) == 0) {
+        return true;
+    }
+
+    return false;
+}
+
 /* Parses an LDAPDerefRes into sdap_deref_attrs structure */
 errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
                          struct sdap_attr_map_info *minfo,
@@ -630,7 +649,7 @@ errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
 
         for (i=0; ocs[i]; i++) {
             /* the objectclass is always the first name in the map */
-            if (strcasecmp(minfo[mi].map[0].name, ocs[i]) == 0) {
+            if (objectclass_matched(minfo[mi].map, ocs[i], 0)) {
                 DEBUG(SSSDBG_TRACE_ALL,
                       "Found map for objectclass '%s'\n", ocs[i]);
                 map = minfo[mi].map;
@@ -1449,3 +1468,16 @@ errno_t sdap_get_netgroup_primary_name(TALLOC_CTX *memctx,
                                  opts->netgroup_map[SDAP_AT_NETGROUP_NAME].name,
                                  attrs, dom, _netgroup_name);
 }
+
+char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map)
+{
+    if (map[SDAP_OC_GROUP_ALT].name == NULL) {
+        return talloc_asprintf(mem_ctx, "objectClass=%s",
+                               map[SDAP_OC_GROUP].name);
+    } else {
+        return talloc_asprintf(mem_ctx,
+                               "|(objectClass=%s)(objectClass=%s)",
+                               map[SDAP_OC_GROUP].name,
+                               map[SDAP_OC_GROUP_ALT].name);
+    }
+}
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 937869d..7eb7cff 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -560,4 +560,6 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
                                       struct sdap_server_opts **srv_opts);
 void sdap_steal_server_opts(struct sdap_id_ctx *id_ctx,
                             struct sdap_server_opts **srv_opts);
+
+char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map);
 #endif /* _SDAP_H_ */
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 1c69c07..242b317 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -717,6 +717,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
     struct enum_groups_state *state;
     int ret;
     bool use_mapping;
+    char *oc_list;
 
     req = tevent_req_create(memctx, &state, struct enum_groups_state);
     if (!req) return NULL;
@@ -732,9 +733,14 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                                         sdom->dom->domain_id);
 
     /* We always want to filter on objectclass and an available name */
-    state->filter = talloc_asprintf(state,
-                               "(&(objectclass=%s)(%s=*)",
-                               ctx->opts->group_map[SDAP_OC_GROUP].name,
+    oc_list = sdap_make_oc_list(state, ctx->opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    state->filter = talloc_asprintf(state, "(&(%s)(%s=*)", oc_list,
                                ctx->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->filter) {
         DEBUG(SSSDBG_MINOR_FAILURE,
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 9f45fde..d3e0800 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -368,6 +368,7 @@ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
     const char **attr_filter;
     char *clean_name;
     errno_t ret;
+    char *oc_list;
 
     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
     if (!req) return NULL;
@@ -419,11 +420,17 @@ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
         return NULL;
     }
 
+    oc_list = sdap_make_oc_list(state, opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
     state->base_filter = talloc_asprintf(state,
-                             "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
+                             "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))",
                              opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-                             clean_name,
-                             opts->group_map[SDAP_OC_GROUP].name,
+                             clean_name, oc_list,
                              opts->group_map[SDAP_AT_GROUP_NAME].name,
                              opts->group_map[SDAP_AT_GROUP_GID].name,
                              opts->group_map[SDAP_AT_GROUP_GID].name);
@@ -805,6 +812,7 @@ static errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req)
     int i;
     struct tevent_req *subreq;
     struct sdap_initgr_nested_state *state;
+    char *oc_list;
 
     state = tevent_req_data(req, struct sdap_initgr_nested_state);
 
@@ -823,8 +831,13 @@ static errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req)
     state->group_dns[i] = NULL; /* terminate */
     state->cur = 0;
 
-    state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
-                            state->opts->group_map[SDAP_OC_GROUP].name,
+    oc_list = sdap_make_oc_list(state, state->opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        return ENOMEM;
+    }
+
+    state->filter = talloc_asprintf(state, "(&(%s)(%s=*))", oc_list,
                             state->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->filter) {
         return ENOMEM;
@@ -1513,6 +1526,7 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
     const char **attr_filter;
     char *clean_orig_dn;
     bool use_id_mapping;
+    char *oc_list;
 
     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_state);
     if (!req) return NULL;
@@ -1565,11 +1579,18 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
                                                         sdom->dom->name,
                                                         sdom->dom->domain_id);
 
+    oc_list = sdap_make_oc_list(state, opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
     state->base_filter =
-            talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*)",
+            talloc_asprintf(state,
+                            "(&(%s=%s)(%s)(%s=*)",
                             opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-                            clean_orig_dn,
-                            opts->group_map[SDAP_OC_GROUP].name,
+                            clean_orig_dn, oc_list,
                             opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->base_filter) {
         ret = ENOMEM;
@@ -2263,6 +2284,7 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
     hash_value_t value;
     struct sdap_rfc2307bis_nested_ctx *state =
             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+    char *oc_list;
 
     tmp_ctx = talloc_new(state);
     if (!tmp_ctx) {
@@ -2339,11 +2361,17 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
         goto done;
     }
 
+    oc_list = sdap_make_oc_list(state, state->opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
     state->base_filter = talloc_asprintf(
-            state, "(&(%s=%s)(objectclass=%s)(%s=*))",
+            state, "(&(%s=%s)(%s)(%s=*))",
             state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-            clean_orig_dn,
-            state->opts->group_map[SDAP_OC_GROUP].name,
+            clean_orig_dn, oc_list,
             state->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->base_filter) {
         ret = ENOMEM;
diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
index 82d8c8a..9923958 100644
--- a/src/providers/ldap/sdap_async_initgroups_ad.c
+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
@@ -70,6 +70,7 @@ sdap_get_ad_match_rule_initgroups_send(TALLOC_CTX *mem_ctx,
     struct sdap_ad_match_rule_initgr_state *state;
     const char **filter_members;
     char *sanitized_user_dn;
+    char *oc_list;
 
     req = tevent_req_create(mem_ctx, &state,
                             struct sdap_ad_match_rule_initgr_state);
@@ -122,13 +123,19 @@ sdap_get_ad_match_rule_initgroups_send(TALLOC_CTX *mem_ctx,
     /* Craft a special filter according to
      * http://msdn.microsoft.com/en-us/library/windows/desktop/aa746475%28v=vs.85%29.aspx
      */
+    oc_list = sdap_make_oc_list(state, state->opts->group_map);
+    if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto immediate;
+    }
+
     state->base_filter =
             talloc_asprintf(state,
-                            "(&(%s:%s:=%s)(objectClass=%s))",
+                            "(&(%s:%s:=%s)(%s))",
                             state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
                             SDAP_MATCHING_RULE_IN_CHAIN,
-                            sanitized_user_dn,
-                            state->opts->group_map[SDAP_OC_GROUP].name);
+                            sanitized_user_dn, oc_list);
     talloc_zfree(sanitized_user_dn);
     if (!state->base_filter) {
         ret = ENOMEM;
diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c
index b07616a..ad5667e 100644
--- a/src/providers/ldap/sdap_async_nested_groups.c
+++ b/src/providers/ldap/sdap_async_nested_groups.c
@@ -1712,6 +1712,7 @@ sdap_nested_group_lookup_group_send(TALLOC_CTX *mem_ctx,
      const char **attrs = NULL;
      const char *base_filter = NULL;
      const char *filter = NULL;
+     char *oc_list;
      errno_t ret;
 
      req = tevent_req_create(mem_ctx, &state,
@@ -1728,8 +1729,14 @@ sdap_nested_group_lookup_group_send(TALLOC_CTX *mem_ctx,
      }
 
      /* create filter */
-     base_filter = talloc_asprintf(attrs, "(&(objectclass=%s)(%s=*))",
-                                   map[SDAP_OC_GROUP].name,
+     oc_list = sdap_make_oc_list(state, map);
+     if (oc_list == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
+        ret = ENOMEM;
+        goto immediately;
+     }
+
+     base_filter = talloc_asprintf(attrs, "(&(%s)(%s=*))", oc_list,
                                    map[SDAP_AT_GROUP_NAME].name);
      if (base_filter == NULL) {
          ret = ENOMEM;
-- 
1.9.3

