LCOV - code coverage report
Current view: top level - source4/dsdb/schema - schema_query.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 203 272 74.6 %
Date: 2024-05-31 13:13:24 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   458703029 : static int uint32_cmp(uint32_t c1, uint32_t c2) 
      39             : {
      40   458703029 :         if (c1 == c2) return 0;
      41   410323772 :         return c1 > c2 ? 1 : -1;
      42             : }
      43             : 
      44   124099116 : static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str)
      45             : {
      46   124099116 :         int ret = strncasecmp((const char *)target->data, str, target->length);
      47   124099116 :         if (ret == 0) {
      48    18488058 :                 size_t len = strlen(str);
      49    18488058 :                 if (target->length > len) {
      50           0 :                         if (target->data[len] == 0) {
      51           0 :                                 return 0;
      52             :                         }
      53           0 :                         return 1;
      54             :                 }
      55    18488058 :                 if (target->length < len) {
      56     1233402 :                         return -1;
      57             :                 }
      58             :         }
      59   111609458 :         return ret;
      60             : }
      61             : 
      62    42956673 : const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
      63             :                                                               uint32_t id)
      64             : {
      65     1460915 :         struct dsdb_attribute *c;
      66             : 
      67             :         /*
      68             :          * 0xFFFFFFFF is used as value when no mapping table is available,
      69             :          * so don't try to match with it
      70             :          */
      71    42956673 :         if (id == 0xFFFFFFFF) return NULL;
      72             : 
      73             :         /* check for msDS-IntId type attribute */
      74    42956673 :         if (dsdb_pfm_get_attid_type(id) == DSDB_ATTID_TYPE_INTID) {
      75        3522 :                 BINARY_ARRAY_SEARCH_P(schema->attributes_by_msDS_IntId,
      76             :                                       schema->num_int_id_attr, msDS_IntId, id, uint32_cmp, c);
      77        1267 :                 return c;
      78             :         }
      79             : 
      80   421098173 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_id,
      81             :                               schema->num_attributes, attributeID_id, id, uint32_cmp, c);
      82    41494491 :         return c;
      83             : }
      84             : 
      85         653 : const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
      86             :                                                                const char *oid)
      87             : {
      88           0 :         struct dsdb_attribute *c;
      89             : 
      90         653 :         if (!oid) return NULL;
      91             : 
      92        6763 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_oid,
      93             :                               schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
      94         653 :         return c;
      95             : }
      96             : 
      97  1805030673 : const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
      98             :                                                                const char *name)
      99             : {
     100    57944244 :         struct dsdb_attribute *c;
     101             : 
     102  1805030673 :         if (!name) return NULL;
     103             : 
     104 17561475488 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
     105             :                               schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
     106  1747086429 :         return c;
     107             : }
     108             : 
     109           0 : const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
     110             :                                                                        const struct ldb_val *name)
     111             : {
     112           0 :         struct dsdb_attribute *a;
     113             : 
     114           0 :         if (!name) return NULL;
     115             : 
     116           0 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
     117             :                               schema->num_attributes, lDAPDisplayName, name, strcasecmp_with_ldb_val, a);
     118           0 :         return a;
     119             : }
     120             : 
     121     2185155 : const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
     122             :                                                       int linkID)
     123             : {
     124       28328 :         struct dsdb_attribute *c;
     125             : 
     126    22192246 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_linkID,
     127             :                               schema->num_attributes, linkID, linkID, uint32_cmp, c);
     128     2185155 :         return c;
     129             : }
     130             : 
     131        5083 : const struct dsdb_attribute *dsdb_attribute_by_cn_ldb_val(const struct dsdb_schema *schema,
     132             :                                                           const struct ldb_val *cn)
     133             : {
     134           0 :         struct dsdb_attribute *c;
     135             : 
     136       45099 :         BINARY_ARRAY_SEARCH_P(schema->attributes_by_cn,
     137             :                               schema->num_attributes, cn, cn, strcasecmp_with_ldb_val, c);
     138        5083 :         return c;
     139             : }
     140             : 
     141     3889134 : const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
     142             :                                                     uint32_t id)
     143             : {
     144      357159 :         struct dsdb_class *c;
     145             : 
     146             :         /*
     147             :          * 0xFFFFFFFF is used as value when no mapping table is available,
     148             :          * so don't try to match with it
     149             :          */
     150     3889134 :         if (id == 0xFFFFFFFF) return NULL;
     151             : 
     152    30899671 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_id,
     153             :                               schema->num_classes, governsID_id, id, uint32_cmp, c);
     154     3531975 :         return c;
     155             : }
     156             : 
     157          22 : const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
     158             :                                                      const char *oid)
     159             : {
     160           0 :         struct dsdb_class *c;
     161          22 :         if (!oid) return NULL;
     162         152 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_oid,
     163             :                               schema->num_classes, governsID_oid, oid, strcasecmp, c);
     164          22 :         return c;
     165             : }
     166             : 
     167   113864236 : const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
     168             :                                                        const char *name)
     169             : {
     170     1823982 :         struct dsdb_class *c;
     171   113864236 :         if (!name) return NULL;
     172   794635454 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
     173             :                               schema->num_classes, lDAPDisplayName, name, strcasecmp, c);
     174   112040254 :         return c;
     175             : }
     176             : 
     177    17095744 : const struct dsdb_class *dsdb_class_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
     178             :                                                                const struct ldb_val *name)
     179             : {
     180     1653595 :         struct dsdb_class *c;
     181    17095744 :         if (!name) return NULL;
     182   122946470 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
     183             :                               schema->num_classes, lDAPDisplayName, name, strcasecmp_with_ldb_val, c);
     184    15442149 :         return c;
     185             : }
     186             : 
     187      153832 : const struct dsdb_class *dsdb_class_by_cn_ldb_val(const struct dsdb_schema *schema,
     188             :                                                   const struct ldb_val *cn)
     189             : {
     190        8859 :         struct dsdb_class *c;
     191      153832 :         if (!cn) return NULL;
     192     1107550 :         BINARY_ARRAY_SEARCH_P(schema->classes_by_cn,
     193             :                               schema->num_classes, cn, cn, strcasecmp_with_ldb_val, c);
     194      144973 :         return c;
     195             : }
     196             : 
     197           0 : const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
     198             :                                        uint32_t id)
     199             : {
     200           0 :         const struct dsdb_attribute *a;
     201           0 :         const struct dsdb_class *c;
     202             : 
     203           0 :         a = dsdb_attribute_by_attributeID_id(schema, id);
     204           0 :         if (a) {
     205           0 :                 return a->lDAPDisplayName;
     206             :         }
     207             : 
     208           0 :         c = dsdb_class_by_governsID_id(schema, id);
     209           0 :         if (c) {
     210           0 :                 return c->lDAPDisplayName;
     211             :         }
     212             : 
     213           0 :         return NULL;
     214             : }
     215             : 
     216             : /** 
     217             :     Return a list of linked attributes, in lDAPDisplayName format.
     218             : 
     219             :     This may be used to determine if a modification would require
     220             :     backlinks to be updated, for example
     221             : */
     222             : 
     223           0 : WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
     224             : {
     225           0 :         const char **attr_list = NULL;
     226           0 :         struct dsdb_attribute *cur;
     227           0 :         unsigned int i = 0;
     228           0 :         for (cur = schema->attributes; cur; cur = cur->next) {
     229           0 :                 if (cur->linkID == 0) continue;
     230             :                 
     231           0 :                 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
     232           0 :                 if (!attr_list) {
     233           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     234             :                 }
     235           0 :                 attr_list[i] = cur->lDAPDisplayName;
     236           0 :                 i++;
     237             :         }
     238           0 :         if (attr_list != NULL && attr_list[i] != NULL) {
     239           0 :                 attr_list[i] = NULL;
     240             :         }
     241           0 :         *attr_list_ret = attr_list;
     242           0 :         return WERR_OK;
     243             : }
     244             : 
     245    28265995 : const char **merge_attr_list(TALLOC_CTX *mem_ctx, 
     246             :                        const char **attrs, const char * const*new_attrs) 
     247             : {
     248     2351404 :         const char **ret_attrs;
     249     2351404 :         unsigned int i;
     250    28265995 :         size_t new_len, new_attr_len, orig_len = str_list_length(attrs);
     251    28265995 :         if (new_attrs == NULL || new_attrs[0] == NULL) {
     252    15397894 :                 return attrs;
     253             :         }
     254    11478485 :         new_attr_len = str_list_length(new_attrs);
     255             : 
     256    11478485 :         ret_attrs = talloc_realloc(mem_ctx,
     257             :                                    attrs, const char *, orig_len + new_attr_len + 1);
     258    11478485 :         if (ret_attrs) {
     259   361691777 :                 for (i = 0; i < new_attr_len; i++) {
     260   350213292 :                         ret_attrs[orig_len + i] = new_attrs[i];
     261             :                 }
     262    11478485 :                 new_len = orig_len + new_attr_len;
     263             : 
     264    11478485 :                 ret_attrs[new_len] = NULL;
     265             :         }
     266             : 
     267    10516697 :         return ret_attrs;
     268             : }
     269             : 
     270             : /*
     271             :   Return a merged list of the attributes of exactly one class (not
     272             :   considering subclasses, auxiliary classes etc)
     273             : */
     274             : 
     275     5660064 : const char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *sclass, enum dsdb_attr_list_query query)
     276             : {
     277     5660064 :         const char **attr_list = NULL;
     278     5660064 :         switch (query) {
     279     2812885 :         case DSDB_SCHEMA_ALL_MAY:
     280     2812885 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     281     2812885 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     282     2812885 :                 break;
     283             :                 
     284     2814532 :         case DSDB_SCHEMA_ALL_MUST:
     285     2814532 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     286     2814532 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     287     2814532 :                 break;
     288             :                 
     289           0 :         case DSDB_SCHEMA_SYS_MAY:
     290           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     291           0 :                 break;
     292             :                 
     293           0 :         case DSDB_SCHEMA_SYS_MUST:
     294           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     295           0 :                 break;
     296             :                 
     297           0 :         case DSDB_SCHEMA_MAY:
     298           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     299           0 :                 break;
     300             :                 
     301           0 :         case DSDB_SCHEMA_MUST:
     302           0 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     303           0 :                 break;
     304             :                 
     305       32647 :         case DSDB_SCHEMA_ALL:
     306       32647 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
     307       32647 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
     308       32647 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
     309       32647 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
     310       32647 :                 break;
     311             :         }
     312     5660064 :         return attr_list;
     313             : }
     314             : 
     315     5626707 : static const char **attribute_list_from_class(TALLOC_CTX *mem_ctx,
     316             :                                               const struct dsdb_schema *schema, 
     317             :                                               const struct dsdb_class *sclass,
     318             :                                               enum dsdb_attr_list_query query) 
     319             : {
     320      470008 :         const char **this_class_list;
     321      470008 :         const char **system_recursive_list;
     322      470008 :         const char **recursive_list;
     323      470008 :         const char **attr_list;
     324             : 
     325     5626707 :         this_class_list = dsdb_attribute_list(mem_ctx, sclass, query);
     326             :         
     327     6096715 :         recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
     328     5626707 :                                                            sclass->systemAuxiliaryClass,
     329             :                                                            query);
     330             :         
     331     6096715 :         system_recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
     332     5626707 :                                                                   sclass->auxiliaryClass,
     333             :                                                                   query);
     334             :         
     335     5626707 :         attr_list = this_class_list;
     336     5626707 :         attr_list = merge_attr_list(mem_ctx, attr_list, recursive_list);
     337     5626707 :         attr_list = merge_attr_list(mem_ctx, attr_list, system_recursive_list);
     338     5626707 :         return attr_list;
     339             : }
     340             : 
     341             : /* Return a full attribute list for a given class list
     342             : 
     343             :    Via attribute_list_from_class() this calls itself when recursing on auxiliary classes
     344             :  */
     345    11253414 : static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, 
     346             :                                                       const struct dsdb_schema *schema, 
     347             :                                                       const char **class_list,
     348             :                                                       enum dsdb_attr_list_query query)
     349             : {
     350      940016 :         unsigned int i;
     351    11253414 :         const char **attr_list = NULL;
     352             : 
     353    12566897 :         for (i=0; class_list && class_list[i]; i++) {
     354       28954 :                 const char **sclass_list
     355     1313483 :                         = attribute_list_from_class(mem_ctx, schema,
     356     1284529 :                                                     dsdb_class_by_lDAPDisplayName(schema, class_list[i]),
     357             :                                                     query);
     358             : 
     359     1313483 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
     360             :         }
     361    11253414 :         return attr_list;
     362             : }
     363             : 
     364             : /* Return a full attribute list for a given class list (as a ldb_message_element)
     365             : 
     366             :    Using the ldb_message_element ensures we do length-limited
     367             :    comparisons, rather than casting the possibly-unterminated string
     368             : 
     369             :    Via attribute_list_from_class() this calls 
     370             :    dsdb_full_attribute_list_internal() when recursing on auxiliary classes
     371             :  */
     372     1861139 : static const char **dsdb_full_attribute_list_internal_el(TALLOC_CTX *mem_ctx, 
     373             :                                                          const struct dsdb_schema *schema, 
     374             :                                                          const struct ldb_message_element *el,
     375             :                                                          enum dsdb_attr_list_query query)
     376             : {
     377      213644 :         unsigned int i;
     378     1861139 :         const char **attr_list = NULL;
     379             : 
     380     6174363 :         for (i=0; i < el->num_values; i++) {
     381      441054 :                 const char **sclass_list
     382     4313224 :                         = attribute_list_from_class(mem_ctx, schema,
     383     4313224 :                                                     dsdb_class_by_lDAPDisplayName_ldb_val(schema, &el->values[i]),
     384             :                                                     query);
     385             :                 
     386     4313224 :                 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
     387             :         }
     388     1861139 :         return attr_list;
     389             : }
     390             : 
     391   889750255 : static int qsort_string(const char **s1, const char **s2)
     392             : {
     393   889750255 :         return strcasecmp(*s1, *s2);
     394             : }
     395             : 
     396             : /* Helper function to remove duplicates from the attribute list to be returned */
     397     1861139 : static const char **dedup_attr_list(const char **attr_list) 
     398             : {
     399     1861139 :         size_t new_len = str_list_length(attr_list);
     400             :         /* Remove duplicates */
     401     1861139 :         if (new_len > 1) {
     402      213644 :                 size_t i;
     403     1861139 :                 TYPESAFE_QSORT(attr_list, new_len, qsort_string);
     404             :                 
     405   163884607 :                 for (i=1; i < new_len; i++) {
     406   161809824 :                         const char **val1 = &attr_list[i-1];
     407   161809824 :                         const char **val2 = &attr_list[i];
     408   161809824 :                         if (ldb_attr_cmp(*val1, *val2) == 0) {
     409     3519297 :                                 memmove(val1, val2, (new_len - i) * sizeof( *attr_list)); 
     410     3519297 :                                 attr_list[new_len-1] = NULL;
     411     3519297 :                                 new_len--;
     412     3519297 :                                 i--;
     413             :                         }
     414             :                 }
     415             :         }
     416     1861139 :         return attr_list;
     417             : }
     418             : 
     419             : /* Return a full attribute list for a given class list (as a ldb_message_element)
     420             : 
     421             :    Using the ldb_message_element ensures we do length-limited
     422             :    comparisons, rather than casting the possibly-unterminated string
     423             : 
     424             :    The result contains only unique values
     425             :  */
     426     1861139 : const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx, 
     427             :                                       const struct dsdb_schema *schema, 
     428             :                                       const struct ldb_message_element *class_list,
     429             :                                       enum dsdb_attr_list_query query)
     430             : {
     431     1861139 :         const char **attr_list = dsdb_full_attribute_list_internal_el(mem_ctx, schema, class_list, query);
     432     1861139 :         return dedup_attr_list(attr_list);
     433             : }
     434             : 
     435             : /* Return the schemaIDGUID of a class */
     436             : 
     437           0 : const struct GUID *class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
     438             :                                                           const char *name)
     439             : {
     440           0 :         const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
     441           0 :         if (!object_class)
     442           0 :                 return NULL;
     443             : 
     444           0 :         return &object_class->schemaIDGUID;
     445             : }
     446             : 
     447           0 : const struct GUID *attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
     448             :                                                               const char *name)
     449             : {
     450           0 :         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, name);
     451           0 :         if (!attr)
     452           0 :                 return NULL;
     453             : 
     454           0 :         return &attr->schemaIDGUID;
     455             : }
     456             : 
     457             : /*
     458             :  * Sort a "objectClass" attribute (LDB message element "objectclass_element")
     459             :  * into correct order and validate that all object classes specified actually
     460             :  * exist in the schema.
     461             :  * The output is written in an existing LDB message element
     462             :  * "out_objectclass_element" where the values will be allocated on "mem_ctx".
     463             :  */
     464     1590727 : int dsdb_sort_objectClass_attr(struct ldb_context *ldb,
     465             :                                const struct dsdb_schema *schema,
     466             :                                const struct ldb_message_element *objectclass_element,
     467             :                                TALLOC_CTX *mem_ctx,
     468             :                                struct ldb_message_element *out_objectclass_element)
     469             : {
     470      246206 :         unsigned int i, lowest;
     471      246206 :         struct class_list {
     472             :                 struct class_list *prev, *next;
     473             :                 const struct dsdb_class *objectclass;
     474     1590727 :         } *unsorted = NULL, *sorted = NULL, *current = NULL,
     475     1590727 :           *poss_parent = NULL, *new_parent = NULL,
     476     1590727 :           *current_lowest = NULL, *current_lowest_struct = NULL;
     477      246206 :         struct ldb_message_element *el;
     478      246206 :         TALLOC_CTX *tmp_mem_ctx;
     479             : 
     480     1590727 :         tmp_mem_ctx = talloc_new(mem_ctx);
     481     1590727 :         if (tmp_mem_ctx == NULL) {
     482           0 :                 return ldb_oom(ldb);
     483             :         }
     484             : 
     485             :         /*
     486             :          * DESIGN:
     487             :          *
     488             :          * We work on 4 different 'bins' (implemented here as linked lists):
     489             :          *
     490             :          * * sorted:       the eventual list, in the order we wish to push
     491             :          *                 into the database.  This is the only ordered list.
     492             :          *
     493             :          * * parent_class: The current parent class 'bin' we are
     494             :          *                 trying to find subclasses for
     495             :          *
     496             :          * * subclass:     The subclasses we have found so far
     497             :          *
     498             :          * * unsorted:     The remaining objectClasses
     499             :          *
     500             :          * The process is a matter of filtering objectClasses up from
     501             :          * unsorted into sorted.  Order is irrelevant in the later 3 'bins'.
     502             :          *
     503             :          * We start with 'top' (found and promoted to parent_class
     504             :          * initially).  Then we find (in unsorted) all the direct
     505             :          * subclasses of 'top'.  parent_classes is concatenated onto
     506             :          * the end of 'sorted', and subclass becomes the list in
     507             :          * parent_class.
     508             :          *
     509             :          * We then repeat, until we find no more subclasses.  Any left
     510             :          * over classes are added to the end.
     511             :          *
     512             :          */
     513             : 
     514             :         /*
     515             :          * Firstly, dump all the "objectClass" values into the unsorted bin,
     516             :          * except for 'top', which is special
     517             :          */
     518     4843888 :         for (i=0; i < objectclass_element->num_values; i++) {
     519     3253163 :                 current = talloc(tmp_mem_ctx, struct class_list);
     520     3253163 :                 if (!current) {
     521           0 :                         talloc_free(tmp_mem_ctx);
     522           0 :                         return ldb_oom(ldb);
     523             :                 }
     524     3253163 :                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
     525     3253163 :                 if (!current->objectclass) {
     526           2 :                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
     527           2 :                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
     528             :                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
     529           2 :                         talloc_free(tmp_mem_ctx);
     530           2 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     531     3253161 :                 } else if (current->objectclass->isDefunct) {
     532           0 :                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
     533           0 :                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
     534             :                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
     535           0 :                         talloc_free(tmp_mem_ctx);
     536           0 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     537             :                 }
     538             : 
     539             :                 /* Don't add top to list, we will do that later */
     540     3253161 :                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
     541     1993207 :                         DLIST_ADD_END(unsorted, current);
     542             :                 }
     543             :         }
     544             : 
     545             : 
     546             :         /* Add top here, to prevent duplicates */
     547     1590725 :         current = talloc(tmp_mem_ctx, struct class_list);
     548     1590725 :         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
     549     1590725 :         DLIST_ADD_END(sorted, current);
     550             : 
     551             :         /* For each object: find parent chain */
     552     3409822 :         for (current = unsorted; current != NULL; current = current->next) {
     553     3833860 :                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
     554     2173977 :                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
     555      155533 :                                 break;
     556             :                         }
     557             :                 }
     558             :                 /* If we didn't get to the end of the list, we need to add this parent */
     559     1819097 :                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
     560     1750165 :                         continue;
     561             :                 }
     562             : 
     563       68932 :                 new_parent = talloc(tmp_mem_ctx, struct class_list);
     564       68932 :                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
     565      318825 :                 DLIST_ADD_END(unsorted, new_parent);
     566             :         }
     567             : 
     568             :         /* For each object: order by hierarchy */
     569     3704753 :         while (unsorted != NULL) {
     570     1568348 :                 lowest = UINT_MAX;
     571     1568348 :                 current_lowest = current_lowest_struct = NULL;
     572     3992823 :                 for (current = unsorted; current != NULL; current = current->next) {
     573     2173726 :                         if (current->objectclass->subClass_order <= lowest) {
     574             :                                 /*
     575             :                                  * According to MS-ADTS 3.1.1.1.4 structural
     576             :                                  * and 88 object classes are always listed after
     577             :                                  * the other class types in a subclass hierarchy
     578             :                                  */
     579     1928468 :                                 if (current->objectclass->objectClassCategory > 1) {
     580       15173 :                                         current_lowest = current;
     581             :                                 } else {
     582     1910496 :                                         current_lowest_struct = current;
     583             :                                 }
     584     1676540 :                                 lowest = current->objectclass->subClass_order;
     585             :                         }
     586             :                 }
     587     1819097 :                 if (current_lowest == NULL) {
     588     1801128 :                         current_lowest = current_lowest_struct;
     589             :                 }
     590             : 
     591     1819097 :                 if (current_lowest != NULL) {
     592     1819097 :                         DLIST_REMOVE(unsorted,current_lowest);
     593     2316052 :                         DLIST_ADD_END(sorted,current_lowest);
     594             :                 }
     595             :         }
     596             : 
     597             :         /* Now rebuild the sorted "objectClass" message element */
     598     1590725 :         el = out_objectclass_element;
     599             : 
     600     1590725 :         el->flags = objectclass_element->flags;
     601     1590725 :         el->name = talloc_strdup(mem_ctx, objectclass_element->name);
     602     1590725 :         if (el->name == NULL) {
     603           0 :                 talloc_free(tmp_mem_ctx);
     604           0 :                 return ldb_oom(ldb);
     605             :         }
     606     1590725 :         el->num_values = 0;
     607     1590725 :         el->values = NULL;
     608     5000547 :         for (current = sorted; current != NULL; current = current->next) {
     609     3409822 :                 el->values = talloc_realloc(mem_ctx, el->values,
     610             :                                             struct ldb_val, el->num_values + 1);
     611     3409822 :                 if (el->values == NULL) {
     612           0 :                         talloc_free(tmp_mem_ctx);
     613           0 :                         return ldb_oom(ldb);
     614             :                 }
     615     3409822 :                 el->values[el->num_values] = data_blob_string_const(current->objectclass->lDAPDisplayName);
     616             : 
     617     3409822 :                 ++(el->num_values);
     618             :         }
     619             : 
     620     1590725 :         talloc_free(tmp_mem_ctx);
     621     1590725 :         return LDB_SUCCESS;
     622             : }

Generated by: LCOV version 1.14