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 : }
|