LCOV - code coverage report
Current view: top level - source4/dsdb/schema - schema_query.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 202 271 74.5 %
Date: 2024-04-21 15:09:00 Functions: 21 26 80.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS Implementation.
       3             :    DSDB schema header
       4             :    
       5             :    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             :    
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "dsdb/samdb/samdb.h"
      25             : #include <ldb_module.h>
      26             : #include "lib/util/binsearch.h"
      27             : #include "lib/util/tsort.h"
      28             : #include "util/dlinklist.h"
      29             : 
      30             : #undef strcasecmp
      31             : #undef strncasecmp
      32             : 
      33             : static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, 
      34             :                                                       const struct dsdb_schema *schema, 
      35             :                                                       const char **class_list,
      36             :                                                       enum dsdb_attr_list_query query);
      37             : 
      38   456377688 : static int uint32_cmp(uint32_t c1, uint32_t c2) 
      39             : {
      40   456377688 :         if (c1 == c2) return 0;
      41   408232017 :         return c1 > c2 ? 1 : -1;
      42             : }
      43             : 
      44   123967190 : static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str)
      45             : {
      46   123967190 :         int ret = strncasecmp((const char *)target->data, str, target->length);
      47   123967190 :         if (ret == 0) {
      48    18467403 :                 size_t len = strlen(str);
      49    18467403 :                 if (target->length > len) {
      50           0 :                         if (target->data[len] == 0) {
      51           0 :                                 return 0;
      52             :                         }
      53           0 :                         return 1;
      54             :                 }
      55    18467403 :                 return (target->length - len);
      56             :         }
      57    95906953 :         return ret;
      58             : }
      59             : 
      60    42746222 : const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
      61             :                                                               uint32_t id)
      62             : {
      63     1460915 :         struct dsdb_attribute *c;
      64             : 
      65             :         /*
      66             :          * 0xFFFFFFFF is used as value when no mapping table is available,
      67             :          * so don't try to match with it
      68             :          */
      69    42746222 :         if (id == 0xFFFFFFFF) return NULL;
      70             : 
      71             :         /* check for msDS-IntId type attribute */
      72    42746222 :         if (dsdb_pfm_get_attid_type(id) == DSDB_ATTID_TYPE_INTID) {
      73        3315 :                 BINARY_ARRAY_SEARCH_P(schema->attributes_by_msDS_IntId,
      74             :                                       schema->num_int_id_attr, msDS_IntId, id, uint32_cmp, c);
      75        1199 :                 return c;
      76             :         }
      77             : 
      78   419033022 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_id,
      79             :                               schema->num_attributes, attributeID_id, id, uint32_cmp, c);
      80    41284108 :         return c;
      81             : }
      82             : 
      83         653 : const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
      84             :                                                                const char *oid)
      85             : {
      86           0 :         struct dsdb_attribute *c;
      87             : 
      88         653 :         if (!oid) return NULL;
      89             : 
      90        6763 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_oid,
      91             :                               schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
      92         653 :         return c;
      93             : }
      94             : 
      95  1799949455 : const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
      96             :                                                                const char *name)
      97             : {
      98    57857288 :         struct dsdb_attribute *c;
      99             : 
     100  1799949455 :         if (!name) return NULL;
     101             : 
     102 17512753428 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
     103             :                               schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
     104  1742092167 :         return c;
     105             : }
     106             : 
     107           0 : const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
     108             :                                                                        const struct ldb_val *name)
     109             : {
     110           0 :         struct dsdb_attribute *a;
     111             : 
     112           0 :         if (!name) return NULL;
     113             : 
     114           0 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
     115             :                               schema->num_attributes, lDAPDisplayName, name, strcasecmp_with_ldb_val, a);
     116           0 :         return a;
     117             : }
     118             : 
     119     2162920 : const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
     120             :                                                       int linkID)
     121             : {
     122       28328 :         struct dsdb_attribute *c;
     123             : 
     124    21968027 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_linkID,
     125             :                               schema->num_attributes, linkID, linkID, uint32_cmp, c);
     126     2162920 :         return c;
     127             : }
     128             : 
     129        5083 : const struct dsdb_attribute *dsdb_attribute_by_cn_ldb_val(const struct dsdb_schema *schema,
     130             :                                                           const struct ldb_val *cn)
     131             : {
     132           0 :         struct dsdb_attribute *c;
     133             : 
     134       45099 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_cn,
     135             :                               schema->num_attributes, cn, cn, strcasecmp_with_ldb_val, c);
     136        5083 :         return c;
     137             : }
     138             : 
     139     3883525 : const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
     140             :                                                     uint32_t id)
     141             : {
     142      357159 :         struct dsdb_class *c;
     143             : 
     144             :         /*
     145             :          * 0xFFFFFFFF is used as value when no mapping table is available,
     146             :          * so don't try to match with it
     147             :          */
     148     3883525 :         if (id == 0xFFFFFFFF) return NULL;
     149             : 
     150    30859198 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_id,
     151             :                               schema->num_classes, governsID_id, id, uint32_cmp, c);
     152     3526366 :         return c;
     153             : }
     154             : 
     155          22 : const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
     156             :                                                      const char *oid)
     157             : {
     158           0 :         struct dsdb_class *c;
     159          22 :         if (!oid) return NULL;
     160         152 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_oid,
     161             :                               schema->num_classes, governsID_oid, oid, strcasecmp, c);
     162          22 :         return c;
     163             : }
     164             : 
     165   112719398 : const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
     166             :                                                        const char *name)
     167             : {
     168     1823842 :         struct dsdb_class *c;
     169   112719398 :         if (!name) return NULL;
     170   786208457 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
     171             :                               schema->num_classes, lDAPDisplayName, name, strcasecmp, c);
     172   110895556 :         return c;
     173             : }
     174             : 
     175    17068740 : const struct dsdb_class *dsdb_class_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
     176             :                                                                const struct ldb_val *name)
     177             : {
     178     1653469 :         struct dsdb_class *c;
     179    17068740 :         if (!name) return NULL;
     180   122750568 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
     181             :                               schema->num_classes, lDAPDisplayName, name, strcasecmp_with_ldb_val, c);
     182    15415271 :         return c;
     183             : }
     184             : 
     185      161988 : const struct dsdb_class *dsdb_class_by_cn_ldb_val(const struct dsdb_schema *schema,
     186             :                                                   const struct ldb_val *cn)
     187             : {
     188        8667 :         struct dsdb_class *c;
     189      161988 :         if (!cn) return NULL;
     190     1171526 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_cn,
     191             :                               schema->num_classes, cn, cn, strcasecmp_with_ldb_val, c);
     192      153321 :         return c;
     193             : }
     194             : 
     195           0 : const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
     196             :                                        uint32_t id)
     197             : {
     198           0 :         const struct dsdb_attribute *a;
     199           0 :         const struct dsdb_class *c;
     200             : 
     201           0 :         a = dsdb_attribute_by_attributeID_id(schema, id);
     202           0 :         if (a) {
     203           0 :                 return a->lDAPDisplayName;
     204             :         }
     205             : 
     206           0 :         c = dsdb_class_by_governsID_id(schema, id);
     207           0 :         if (c) {
     208           0 :                 return c->lDAPDisplayName;
     209             :         }
     210             : 
     211           0 :         return NULL;
     212             : }
     213             : 
     214             : /** 
     215             :     Return a list of linked attributes, in lDAPDisplayName format.
     216             : 
     217             :     This may be used to determine if a modification would require
     218             :     backlinks to be updated, for example
     219             : */
     220             : 
     221           0 : WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
     222             : {
     223           0 :         const char **attr_list = NULL;
     224           0 :         struct dsdb_attribute *cur;
     225           0 :         unsigned int i = 0;
     226           0 :         for (cur = schema->attributes; cur; cur = cur->next) {
     227           0 :                 if (cur->linkID == 0) continue;
     228             :                 
     229           0 :                 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
     230           0 :                 if (!attr_list) {
     231           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     232             :                 }
     233           0 :                 attr_list[i] = cur->lDAPDisplayName;
     234           0 :                 i++;
     235             :         }
     236           0 :         if (attr_list != NULL && attr_list[i] != NULL) {
     237           0 :                 attr_list[i] = NULL;
     238             :         }
     239           0 :         *attr_list_ret = attr_list;
     240           0 :         return WERR_OK;
     241             : }
     242             : 
     243    28266207 : const char **merge_attr_list(TALLOC_CTX *mem_ctx, 
     244             :                        const char **attrs, const char * const*new_attrs) 
     245             : {
     246     2350144 :         const char **ret_attrs;
     247     2350144 :         unsigned int i;
     248    28266207 :         size_t new_len, new_attr_len, orig_len = str_list_length(attrs);
     249    28266207 :         if (new_attrs == NULL || new_attrs[0] == NULL) {
     250    15396399 :                 return attrs;
     251             :         }
     252    11480962 :         new_attr_len = str_list_length(new_attrs);
     253             : 
     254    11480962 :         ret_attrs = talloc_realloc(mem_ctx,
     255             :                                    attrs, const char *, orig_len + new_attr_len + 1);
     256    11480962 :         if (ret_attrs) {
     257   361693562 :                 for (i = 0; i < new_attr_len; i++) {
     258   350212600 :                         ret_attrs[orig_len + i] = new_attrs[i];
     259             :                 }
     260    11480962 :                 new_len = orig_len + new_attr_len;
     261             : 
     262    11480962 :                 ret_attrs[new_len] = NULL;
     263             :         }
     264             : 
     265    10519664 :         return ret_attrs;
     266             : }
     267             : 
     268             : /*
     269             :   Return a merged list of the attributes of exactly one class (not
     270             :   considering subclasses, auxiliary classes etc)
     271             : */
     272             : 
     273     5660055 : const char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *sclass, enum dsdb_attr_list_query query)
     274             : {
     275     5660055 :         const char **attr_list = NULL;
     276     5660055 :         switch (query) {
     277     2813009 :         case DSDB_SCHEMA_ALL_MAY:
     278     2813009 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     279     2813009 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     280     2813009 :                 break;
     281             :                 
     282     2814656 :         case DSDB_SCHEMA_ALL_MUST:
     283     2814656 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     284     2814656 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     285     2814656 :                 break;
     286             :                 
     287           0 :         case DSDB_SCHEMA_SYS_MAY:
     288           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     289           0 :                 break;
     290             :                 
     291           0 :         case DSDB_SCHEMA_SYS_MUST:
     292           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     293           0 :                 break;
     294             :                 
     295           0 :         case DSDB_SCHEMA_MAY:
     296           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     297           0 :                 break;
     298             :                 
     299           0 :         case DSDB_SCHEMA_MUST:
     300           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     301           0 :                 break;
     302             :                 
     303       32390 :         case DSDB_SCHEMA_ALL:
     304       32390 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     305       32390 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     306       32390 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     307       32390 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     308       32390 :                 break;
     309             :         }
     310     5660055 :         return attr_list;
     311             : }
     312             : 
     313     5626955 : static const char **attribute_list_from_class(TALLOC_CTX *mem_ctx,
     314             :                                               const struct dsdb_schema *schema, 
     315             :                                               const struct dsdb_class *sclass,
     316             :                                               enum dsdb_attr_list_query query) 
     317             : {
     318      469756 :         const char **this_class_list;
     319      469756 :         const char **system_recursive_list;
     320      469756 :         const char **recursive_list;
     321      469756 :         const char **attr_list;
     322             : 
     323     5626955 :         this_class_list = dsdb_attribute_list(mem_ctx, sclass, query);
     324             :         
     325     6096711 :         recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
     326     5626955 :                                                            sclass->systemAuxiliaryClass,
     327             :                                                            query);
     328             :         
     329     6096711 :         system_recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
     330     5626955 :                                                                   sclass->auxiliaryClass,
     331             :                                                                   query);
     332             :         
     333     5626955 :         attr_list = this_class_list;
     334     5626955 :         attr_list = merge_attr_list(mem_ctx, attr_list, recursive_list);
     335     5626955 :         attr_list = merge_attr_list(mem_ctx, attr_list, system_recursive_list);
     336     5626955 :         return attr_list;
     337             : }
     338             : 
     339             : /* Return a full attribute list for a given class list
     340             : 
     341             :    Via attribute_list_from_class() this calls itself when recursing on auxiliary classes
     342             :  */
     343    11253910 : static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, 
     344             :                                                       const struct dsdb_schema *schema, 
     345             :                                                       const char **class_list,
     346             :                                                       enum dsdb_attr_list_query query)
     347             : {
     348      939512 :         unsigned int i;
     349    11253910 :         const char **attr_list = NULL;
     350             : 
     351    12569345 :         for (i=0; class_list && class_list[i]; i++) {
     352       28814 :                 const char **sclass_list
     353     1315435 :                         = attribute_list_from_class(mem_ctx, schema,
     354     1286621 :                                                     dsdb_class_by_lDAPDisplayName(schema, class_list[i]),
     355             :                                                     query);
     356             : 
     357     1315435 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
     358             :         }
     359    11253910 :         return attr_list;
     360             : }
     361             : 
     362             : /* Return a full attribute list for a given class list (as a ldb_message_element)
     363             : 
     364             :    Using the ldb_message_element ensures we do length-limited
     365             :    comparisons, rather than casting the possibly-unterminated string
     366             : 
     367             :    Via attribute_list_from_class() this calls 
     368             :    dsdb_full_attribute_list_internal() when recursing on auxiliary classes
     369             :  */
     370     1860115 : static const char **dsdb_full_attribute_list_internal_el(TALLOC_CTX *mem_ctx, 
     371             :                                                          const struct dsdb_schema *schema, 
     372             :                                                          const struct ldb_message_element *el,
     373             :                                                          enum dsdb_attr_list_query query)
     374             : {
     375      213616 :         unsigned int i;
     376     1860115 :         const char **attr_list = NULL;
     377             : 
     378     6171635 :         for (i=0; i < el->num_values; i++) {
     379      440942 :                 const char **sclass_list
     380     4311520 :                         = attribute_list_from_class(mem_ctx, schema,
     381     4311520 :                                                     dsdb_class_by_lDAPDisplayName_ldb_val(schema, &el->values[i]),
     382             :                                                     query);
     383             :                 
     384     4311520 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
     385             :         }
     386     1860115 :         return attr_list;
     387             : }
     388             : 
     389   890220747 : static int qsort_string(const char **s1, const char **s2)
     390             : {
     391   890220747 :         return strcasecmp(*s1, *s2);
     392             : }
     393             : 
     394             : /* Helper function to remove duplicates from the attribute list to be returned */
     395     1860115 : static const char **dedup_attr_list(const char **attr_list) 
     396             : {
     397     1860115 :         size_t new_len = str_list_length(attr_list);
     398             :         /* Remove duplicates */
     399     1860115 :         if (new_len > 1) {
     400      213616 :                 size_t i;
     401     1860115 :                 TYPESAFE_QSORT(attr_list, new_len, qsort_string);
     402             :                 
     403   163919078 :                 for (i=1; i < new_len; i++) {
     404   161845347 :                         const char **val1 = &attr_list[i-1];
     405   161845347 :                         const char **val2 = &attr_list[i];
     406   161845347 :                         if (ldb_attr_cmp(*val1, *val2) == 0) {
     407     3522544 :                                 memmove(val1, val2, (new_len - i) * sizeof( *attr_list)); 
     408     3522544 :                                 attr_list[new_len-1] = NULL;
     409     3522544 :                                 new_len--;
     410     3522544 :                                 i--;
     411             :                         }
     412             :                 }
     413             :         }
     414     1860115 :         return attr_list;
     415             : }
     416             : 
     417             : /* Return a full attribute list for a given class list (as a ldb_message_element)
     418             : 
     419             :    Using the ldb_message_element ensures we do length-limited
     420             :    comparisons, rather than casting the possibly-unterminated string
     421             : 
     422             :    The result contains only unique values
     423             :  */
     424     1860115 : const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx, 
     425             :                                       const struct dsdb_schema *schema, 
     426             :                                       const struct ldb_message_element *class_list,
     427             :                                       enum dsdb_attr_list_query query)
     428             : {
     429     1860115 :         const char **attr_list = dsdb_full_attribute_list_internal_el(mem_ctx, schema, class_list, query);
     430     1860115 :         return dedup_attr_list(attr_list);
     431             : }
     432             : 
     433             : /* Return the schemaIDGUID of a class */
     434             : 
     435           0 : const struct GUID *class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
     436             :                                                           const char *name)
     437             : {
     438           0 :         const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
     439           0 :         if (!object_class)
     440           0 :                 return NULL;
     441             : 
     442           0 :         return &object_class->schemaIDGUID;
     443             : }
     444             : 
     445           0 : const struct GUID *attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
     446             :                                                               const char *name)
     447             : {
     448           0 :         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, name);
     449           0 :         if (!attr)
     450           0 :                 return NULL;
     451             : 
     452           0 :         return &attr->schemaIDGUID;
     453             : }
     454             : 
     455             : /*
     456             :  * Sort a "objectClass" attribute (LDB message element "objectclass_element")
     457             :  * into correct order and validate that all object classes specified actually
     458             :  * exist in the schema.
     459             :  * The output is written in an existing LDB message element
     460             :  * "out_objectclass_element" where the values will be allocated on "mem_ctx".
     461             :  */
     462     1590520 : int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
     463             :                                const struct dsdb_schema *schema,
     464             :                                const struct ldb_message_element *objectclass_element,
     465             :                                TALLOC_CTX *mem_ctx,
     466             :                                struct ldb_message_element *out_objectclass_element)
     467             : {
     468      246206 :         unsigned int i, lowest;
     469      246206 :         struct class_list {
     470             :                 struct class_list *prev, *next;
     471             :                 const struct dsdb_class *objectclass;
     472     1590520 :         } *unsorted = NULL, *sorted = NULL, *current = NULL,
     473     1590520 :           *poss_parent = NULL, *new_parent = NULL,
     474     1590520 :           *current_lowest = NULL, *current_lowest_struct = NULL;
     475      246206 :         struct ldb_message_element *el;
     476      246206 :         TALLOC_CTX *tmp_mem_ctx;
     477             : 
     478     1590520 :         tmp_mem_ctx = talloc_new(mem_ctx);
     479     1590520 :         if (tmp_mem_ctx == NULL) {
     480           0 :                 return ldb_oom(ldb);
     481             :         }
     482             : 
     483             :         /*
     484             :          * DESIGN:
     485             :          *
     486             :          * We work on 4 different 'bins' (implemented here as linked lists):
     487             :          *
     488             :          * * sorted:       the eventual list, in the order we wish to push
     489             :          *                 into the database.  This is the only ordered list.
     490             :          *
     491             :          * * parent_class: The current parent class 'bin' we are
     492             :          *                 trying to find subclasses for
     493             :          *
     494             :          * * subclass:     The subclasses we have found so far
     495             :          *
     496             :          * * unsorted:     The remaining objectClasses
     497             :          *
     498             :          * The process is a matter of filtering objectClasses up from
     499             :          * unsorted into sorted.  Order is irrelevant in the later 3 'bins'.
     500             :          *
     501             :          * We start with 'top' (found and promoted to parent_class
     502             :          * initially).  Then we find (in unsorted) all the direct
     503             :          * subclasses of 'top'.  parent_classes is concatenated onto
     504             :          * the end of 'sorted', and subclass becomes the list in
     505             :          * parent_class.
     506             :          *
     507             :          * We then repeat, until we find no more subclasses.  Any left
     508             :          * over classes are added to the end.
     509             :          *
     510             :          */
     511             : 
     512             :         /*
     513             :          * Firstly, dump all the "objectClass" values into the unsorted bin,
     514             :          * except for 'top', which is special
     515             :          */
     516     4842854 :         for (i=0; i < objectclass_element->num_values; i++) {
     517     3252336 :                 current = talloc(tmp_mem_ctx, struct class_list);
     518     3252336 :                 if (!current) {
     519           0 :                         talloc_free(tmp_mem_ctx);
     520           0 :                         return ldb_oom(ldb);
     521             :                 }
     522     3252336 :                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
     523     3252336 :                 if (!current->objectclass) {
     524           2 :                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
     525           2 :                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
     526             :                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
     527           2 :                         talloc_free(tmp_mem_ctx);
     528           2 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     529     3252334 :                 } else if (current->objectclass->isDefunct) {
     530           0 :                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
     531           0 :                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
     532             :                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
     533           0 :                         talloc_free(tmp_mem_ctx);
     534           0 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     535             :                 }
     536             : 
     537             :                 /* Don't add top to list, we will do that later */
     538     3252334 :                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
     539     1992531 :                         DLIST_ADD_END(unsorted, current);
     540             :                 }
     541             :         }
     542             : 
     543             : 
     544             :         /* Add top here, to prevent duplicates */
     545     1590518 :         current = talloc(tmp_mem_ctx, struct class_list);
     546     1590518 :         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
     547     1590518 :         DLIST_ADD_END(sorted, current);
     548             : 
     549             :         /* For each object: find parent chain */
     550     3408755 :         for (current = unsorted; current != NULL; current = current->next) {
     551     3830988 :                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
     552     2171496 :                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
     553      155064 :                                 break;
     554             :                         }
     555             :                 }
     556             :                 /* If we didn't get to the end of the list, we need to add this parent */
     557     1818237 :                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
     558     1749489 :                         continue;
     559             :                 }
     560             : 
     561       68748 :                 new_parent = talloc(tmp_mem_ctx, struct class_list);
     562       68748 :                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
     563      318641 :                 DLIST_ADD_END(unsorted, new_parent);
     564             :         }
     565             : 
     566             :         /* For each object: order by hierarchy */
     567     3703579 :         while (unsorted != NULL) {
     568     1567488 :                 lowest = UINT_MAX;
     569     1567488 :                 current_lowest = current_lowest_struct = NULL;
     570     3989482 :                 for (current = unsorted; current != NULL; current = current->next) {
     571     2171245 :                         if (current->objectclass->subClass_order <= lowest) {
     572             :                                 /*
     573             :                                  * According to MS-ADTS 3.1.1.1.4 structural
     574             :                                  * and 88 object classes are always listed after
     575             :                                  * the other class types in a subclass hierarchy
     576             :                                  */
     577     1927146 :                                 if (current->objectclass->objectClassCategory > 1) {
     578       15178 :                                         current_lowest = current;
     579             :                                 } else {
     580     1909169 :                                         current_lowest_struct = current;
     581             :                                 }
     582     1675218 :                                 lowest = current->objectclass->subClass_order;
     583             :                         }
     584             :                 }
     585     1818237 :                 if (current_lowest == NULL) {
     586     1800263 :                         current_lowest = current_lowest_struct;
     587             :                 }
     588             : 
     589     1818237 :                 if (current_lowest != NULL) {
     590     1818237 :                         DLIST_REMOVE(unsorted,current_lowest);
     591     2315192 :                         DLIST_ADD_END(sorted,current_lowest);
     592             :                 }
     593             :         }
     594             : 
     595             :         /* Now rebuild the sorted "objectClass" message element */
     596     1590518 :         el = out_objectclass_element;
     597             : 
     598     1590518 :         el->flags = objectclass_element->flags;
     599     1590518 :         el->name = talloc_strdup(mem_ctx, objectclass_element->name);
     600     1590518 :         if (el->name == NULL) {
     601           0 :                 talloc_free(tmp_mem_ctx);
     602           0 :                 return ldb_oom(ldb);
     603             :         }
     604     1590518 :         el->num_values = 0;
     605     1590518 :         el->values = NULL;
     606     4999273 :         for (current = sorted; current != NULL; current = current->next) {
     607     3408755 :                 el->values = talloc_realloc(mem_ctx, el->values,
     608             :                                             struct ldb_val, el->num_values + 1);
     609     3408755 :                 if (el->values == NULL) {
     610           0 :                         talloc_free(tmp_mem_ctx);
     611           0 :                         return ldb_oom(ldb);
     612             :                 }
     613     3408755 :                 el->values[el->num_values] = data_blob_string_const(current->objectclass->lDAPDisplayName);
     614             : 
     615     3408755 :                 ++(el->num_values);
     616             :         }
     617             : 
     618     1590518 :         talloc_free(tmp_mem_ctx);
     619     1590518 :         return LDB_SUCCESS;
     620             : }

Generated by: LCOV version 1.14