r11242: use LDAP bitwise machting rule when searching for groups in ADS.
authorGünther Deschner <gd@samba.org>
Fri, 21 Oct 2005 12:50:39 +0000 (12:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:05:09 +0000 (11:05 -0500)
This avoids that each time a full-group-dump is requested from ADS; the
bitwise match allows to only query those groups we are interested in.

The ADS LDAP server changed to RFC compliant behaviour when decoding the ldap
filter with extensible match in the latest SPs (fixes). From the patch:

/* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
  * rollup-fixes:
  *
  * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
  * default value, it MUST be absent. In case of extensible matching the
  * "dnattr" boolean defaults to FALSE and so it must be only be present
  * when set to TRUE.
  *
  * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
  * filter using bitwise matching rule then a buggy AD fails to decode
  * the extensible match. As a workaround set it to TRUE and thereby add
  * the dnAttributes "dn" field to cope with those older AD versions.
  * It should not harm and won't put any additional load on the AD since
  * none of the dn components have a bitmask-attribute.
  *
  * Thanks to Ralf Haferkamp for input and testing */

Guenther

source/include/ads.h
source/nsswitch/winbindd_ads.c

index d2eeaab4d8488ad94ca88d6362585e50efc57568..decb823ea99a56f4c3f9911a2aa01dfcda742330 100644 (file)
@@ -98,6 +98,10 @@ typedef void **ADS_MODLIST;
 #define ADS_ATTR_SFU_HOMEDIR_OID       "1.2.840.113556.1.6.18.1.344"
 #define ADS_ATTR_SFU_SHELL_OID                 "1.2.840.113556.1.6.18.1.312"
 
+/* ldap bitwise searches */
+#define ADS_LDAP_MATCHING_RULE_BIT_AND "1.2.840.113556.1.4.803"
+#define ADS_LDAP_MATCHING_RULE_BIT_OR  "1.2.840.113556.1.4.804"
+
 /* UserFlags for userAccountControl */
 #define UF_SCRIPT                              0x00000001
 #define UF_ACCOUNTDISABLE                      0x00000002
@@ -186,9 +190,27 @@ typedef void **ADS_MODLIST;
 #define ATYPE_LOCAL_GROUP      ATYPE_SECURITY_LOCAL_GROUP      /* 0x20000000 536870912 */
 
 /* groupType */
-#define GTYPE_SECURITY_BUILTIN_LOCAL_GROUP     0x80000005      /* -2147483643 */
-#define GTYPE_SECURITY_DOMAIN_LOCAL_GROUP      0x80000004      /* -2147483644 */
-#define GTYPE_SECURITY_GLOBAL_GROUP            0x80000002      /* -2147483646 */
+#define GROUP_TYPE_BUILTIN_LOCAL_GROUP         0x00000001
+#define GROUP_TYPE_ACCOUNT_GROUP               0x00000002
+#define GROUP_TYPE_RESOURCE_GROUP              0x00000004
+#define GROUP_TYPE_UNIVERSAL_GROUP             0x00000008
+#define GROUP_TYPE_APP_BASIC_GROUP             0x00000010
+#define GROUP_TYPE_APP_QUERY_GROUP             0x00000020
+#define GROUP_TYPE_SECURITY_ENABLED            0x80000000
+
+#define GTYPE_SECURITY_BUILTIN_LOCAL_GROUP (   /* 0x80000005 -2147483643 */ \
+               GROUP_TYPE_BUILTIN_LOCAL_GROUP| \
+               GROUP_TYPE_RESOURCE_GROUP| \
+               GROUP_TYPE_SECURITY_ENABLED \
+               )
+#define GTYPE_SECURITY_DOMAIN_LOCAL_GROUP (    /* 0x80000004 -2147483644 */ \
+               GROUP_TYPE_RESOURCE_GROUP| \
+               GROUP_TYPE_SECURITY_ENABLED \
+               )
+#define GTYPE_SECURITY_GLOBAL_GROUP (          /* 0x80000002 -2147483646 */ \
+               GROUP_TYPE_ACCOUNT_GROUP| \
+               GROUP_TYPE_SECURITY_ENABLED \
+               )
 #define GTYPE_DISTRIBUTION_GLOBAL_GROUP                0x00000002      /* 2 */
 #define GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP  0x00000004      /* 4 */
 #define GTYPE_DISTRIBUTION_UNIVERSAL_GROUP     0x00000008      /* 8 */
index f11f1514281fad3c765afa2f1e67fdf66d8cb5ae..6b170c33305ecb898a11863081957733e63da6ae 100644 (file)
@@ -220,19 +220,51 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
 {
        ADS_STRUCT *ads = NULL;
        const char *attrs[] = {"userPrincipalName", "sAMAccountName",
-                              "name", "objectSid", 
-                              "sAMAccountType", NULL};
+                              "name", "objectSid", NULL};
        int i, count;
        ADS_STATUS rc;
        void *res = NULL;
        void *msg = NULL;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       uint32 group_flags;
+       const char *filter;
+       BOOL enum_dom_local_groups = False;
 
        *num_entries = 0;
 
        DEBUG(3,("ads: enum_dom_groups\n"));
 
+       /* only grab domain local groups for our domain */
+       if ( domain->native_mode && strequal(lp_realm(), domain->alt_name)  ) {
+               enum_dom_local_groups = True;
+       }
+
+       /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
+        * rollup-fixes:
+        *
+        * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
+        * default value, it MUST be absent. In case of extensible matching the
+        * "dnattr" boolean defaults to FALSE and so it must be only be present
+        * when set to TRUE. 
+        *
+        * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
+        * filter using bitwise matching rule then the buggy AD fails to decode
+        * the extensible match. As a workaround set it to TRUE and thereby add
+        * the dnAttributes "dn" field to cope with those older AD versions.
+        * It should not harm and won't put any additional load on the AD since
+        * none of the dn components have a bitmask-attribute.
+        *
+        * Thanks to Ralf Haferkamp for input and testing - Guenther */
+
+       filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
+                                ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
+                                ADS_LDAP_MATCHING_RULE_BIT_AND, 
+                                enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
+
+       if (filter == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
        ads = ads_cached_connection(domain);
 
        if (!ads) {
@@ -240,7 +272,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                goto done;
        }
 
-       rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs);
+       rc = ads_search_retry(ads, &res, filter, attrs);
        if (!ADS_ERR_OK(rc) || !res) {
                DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
                goto done;
@@ -260,21 +292,11 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
 
        i = 0;
        
-       group_flags = ATYPE_GLOBAL_GROUP;
-
-       /* only grab domain local groups for our domain */
-       if ( domain->native_mode && strequal(lp_realm(), domain->alt_name)  )
-               group_flags |= ATYPE_LOCAL_GROUP;
-
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
                char *name, *gecos;
                DOM_SID sid;
                uint32 rid;
-               uint32 account_type;
 
-               if (!ads_pull_uint32(ads, msg, "sAMAccountType", &account_type) || !(account_type & group_flags) ) 
-                       continue; 
-                       
                name = ads_pull_username(ads, mem_ctx, msg);
                gecos = ads_pull_string(ads, mem_ctx, msg, "name");
                if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
@@ -282,9 +304,6 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                        continue;
                }
 
-               if (sid_check_is_in_builtin(&sid))
-                       continue;
-
                if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
                        DEBUG(1,("No rid for %s !?\n", name));
                        continue;