2 Unix SMB/CIFS mplementation.
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
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.
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.
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/>.
24 #include "dsdb/samdb/samdb.h"
26 /* a binary array search, where the array is an array of pointers to structures,
27 and we want to find a match for 'target' on 'field' in those structures.
30 array: base pointer to an array of structures
31 arrray_size: number of elements in the array
32 field: the name of the field in the structure we are keying off
33 target: the field value we are looking for
34 comparison_fn: the comparison function
35 result: where the result of the search is put
37 if the element is found, then 'result' is set to point to the found array element. If not,
38 then 'result' is set to NULL.
40 The array is assumed to be sorted by the same comparison_fn as the
41 search (with, for example, qsort)
43 #define BINARY_ARRAY_SEARCH(array, array_size, field, target, comparison_fn, result) do { \
46 for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
47 int32_t _i = (_b+_e)/2; \
48 int _r = comparison_fn(target, array[_i]->field); \
49 if (_r == 0) { (result) = array[_i]; break; } \
50 if (_r < 0) _e = _i - 1; else _b = _i + 1; \
54 static const char **dsdb_full_attribute_list_internal(TALLOC_CTX
*mem_ctx
,
55 const struct dsdb_schema
*schema
,
56 const char **class_list
,
57 enum dsdb_attr_list_query query
);
59 static int uint32_cmp(uint32_t c1
, uint32_t c2
)
64 static int strcasecmp_with_ldb_val(const struct ldb_val
*target
, const char *str
)
66 int ret
= strncasecmp((const char *)target
->data
, str
, target
->length
);
68 return (target
->length
- strlen(str
));
73 const struct dsdb_attribute
*dsdb_attribute_by_attributeID_id(const struct dsdb_schema
*schema
,
76 struct dsdb_attribute
*c
;
79 * 0xFFFFFFFF is used as value when no mapping table is available,
80 * so don't try to match with it
82 if (id
== 0xFFFFFFFF) return NULL
;
84 BINARY_ARRAY_SEARCH(schema
->attributes_by_attributeID_id
,
85 schema
->num_attributes
, attributeID_id
, id
, uint32_cmp
, c
);
89 const struct dsdb_attribute
*dsdb_attribute_by_attributeID_oid(const struct dsdb_schema
*schema
,
92 struct dsdb_attribute
*c
;
94 if (!oid
) return NULL
;
96 BINARY_ARRAY_SEARCH(schema
->attributes_by_attributeID_oid
,
97 schema
->num_attributes
, attributeID_oid
, oid
, strcasecmp
, c
);
101 const struct dsdb_attribute
*dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema
*schema
,
104 struct dsdb_attribute
*c
;
106 if (!name
) return NULL
;
108 BINARY_ARRAY_SEARCH(schema
->attributes_by_lDAPDisplayName
,
109 schema
->num_attributes
, lDAPDisplayName
, name
, strcasecmp
, c
);
113 const struct dsdb_attribute
*dsdb_attribute_by_linkID(const struct dsdb_schema
*schema
,
116 struct dsdb_attribute
*c
;
118 BINARY_ARRAY_SEARCH(schema
->attributes_by_linkID
,
119 schema
->num_attributes
, linkID
, linkID
, uint32_cmp
, c
);
123 const struct dsdb_class
*dsdb_class_by_governsID_id(const struct dsdb_schema
*schema
,
126 struct dsdb_class
*c
;
129 * 0xFFFFFFFF is used as value when no mapping table is available,
130 * so don't try to match with it
132 if (id
== 0xFFFFFFFF) return NULL
;
134 BINARY_ARRAY_SEARCH(schema
->classes_by_governsID_id
,
135 schema
->num_classes
, governsID_id
, id
, uint32_cmp
, c
);
139 const struct dsdb_class
*dsdb_class_by_governsID_oid(const struct dsdb_schema
*schema
,
142 struct dsdb_class
*c
;
143 if (!oid
) return NULL
;
144 BINARY_ARRAY_SEARCH(schema
->classes_by_governsID_oid
,
145 schema
->num_classes
, governsID_oid
, oid
, strcasecmp
, c
);
149 const struct dsdb_class
*dsdb_class_by_lDAPDisplayName(const struct dsdb_schema
*schema
,
152 struct dsdb_class
*c
;
153 if (!name
) return NULL
;
154 BINARY_ARRAY_SEARCH(schema
->classes_by_lDAPDisplayName
,
155 schema
->num_classes
, lDAPDisplayName
, name
, strcasecmp
, c
);
159 const struct dsdb_class
*dsdb_class_by_lDAPDisplayName_ldb_val(const struct dsdb_schema
*schema
,
160 const struct ldb_val
*name
)
162 struct dsdb_class
*c
;
163 if (!name
) return NULL
;
164 BINARY_ARRAY_SEARCH(schema
->classes_by_lDAPDisplayName
,
165 schema
->num_classes
, lDAPDisplayName
, name
, strcasecmp_with_ldb_val
, c
);
169 const struct dsdb_class
*dsdb_class_by_cn(const struct dsdb_schema
*schema
,
172 struct dsdb_class
*c
;
173 if (!cn
) return NULL
;
174 BINARY_ARRAY_SEARCH(schema
->classes_by_cn
,
175 schema
->num_classes
, cn
, cn
, strcasecmp
, c
);
179 const struct dsdb_class
*dsdb_class_by_cn_ldb_val(const struct dsdb_schema
*schema
,
180 const struct ldb_val
*cn
)
182 struct dsdb_class
*c
;
183 if (!cn
) return NULL
;
184 BINARY_ARRAY_SEARCH(schema
->classes_by_cn
,
185 schema
->num_classes
, cn
, cn
, strcasecmp_with_ldb_val
, c
);
189 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema
*schema
,
192 const struct dsdb_attribute
*a
;
193 const struct dsdb_class
*c
;
195 a
= dsdb_attribute_by_attributeID_id(schema
, id
);
197 return a
->lDAPDisplayName
;
200 c
= dsdb_class_by_governsID_id(schema
, id
);
202 return c
->lDAPDisplayName
;
209 Return a list of linked attributes, in lDAPDisplayName format.
211 This may be used to determine if a modification would require
212 backlinks to be updated, for example
215 WERROR
dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema
*schema
, TALLOC_CTX
*mem_ctx
, const char ***attr_list_ret
)
217 const char **attr_list
= NULL
;
218 struct dsdb_attribute
*cur
;
220 for (cur
= schema
->attributes
; cur
; cur
= cur
->next
) {
221 if (cur
->linkID
== 0) continue;
223 attr_list
= talloc_realloc(mem_ctx
, attr_list
, const char *, i
+2);
227 attr_list
[i
] = cur
->lDAPDisplayName
;
231 *attr_list_ret
= attr_list
;
235 const char **merge_attr_list(TALLOC_CTX
*mem_ctx
,
236 const char **attrs
, const char * const*new_attrs
)
238 const char **ret_attrs
;
240 size_t new_len
, orig_len
= str_list_length(attrs
);
245 ret_attrs
= talloc_realloc(mem_ctx
,
246 attrs
, const char *, orig_len
+ str_list_length(new_attrs
) + 1);
248 for (i
=0; i
< str_list_length(new_attrs
); i
++) {
249 ret_attrs
[orig_len
+ i
] = new_attrs
[i
];
251 new_len
= orig_len
+ str_list_length(new_attrs
);
253 ret_attrs
[new_len
] = NULL
;
260 Return a merged list of the attributes of exactly one class (not
261 considering subclasses, auxillary classes etc)
264 const char **dsdb_attribute_list(TALLOC_CTX
*mem_ctx
, const struct dsdb_class
*sclass
, enum dsdb_attr_list_query query
)
266 const char **attr_list
= NULL
;
268 case DSDB_SCHEMA_ALL_MAY
:
269 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mayContain
);
270 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMayContain
);
273 case DSDB_SCHEMA_ALL_MUST
:
274 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mustContain
);
275 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMustContain
);
278 case DSDB_SCHEMA_SYS_MAY
:
279 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMayContain
);
282 case DSDB_SCHEMA_SYS_MUST
:
283 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMustContain
);
286 case DSDB_SCHEMA_MAY
:
287 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mayContain
);
290 case DSDB_SCHEMA_MUST
:
291 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mustContain
);
294 case DSDB_SCHEMA_ALL
:
295 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mayContain
);
296 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMayContain
);
297 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mustContain
);
298 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMustContain
);
304 static const char **attribute_list_from_class(TALLOC_CTX
*mem_ctx
,
305 const struct dsdb_schema
*schema
,
306 const struct dsdb_class
*sclass
,
307 enum dsdb_attr_list_query query
)
309 const char **this_class_list
;
310 const char **system_recursive_list
;
311 const char **recursive_list
;
312 const char **attr_list
;
314 this_class_list
= dsdb_attribute_list(mem_ctx
, sclass
, query
);
316 recursive_list
= dsdb_full_attribute_list_internal(mem_ctx
, schema
,
317 sclass
->systemAuxiliaryClass
,
320 system_recursive_list
= dsdb_full_attribute_list_internal(mem_ctx
, schema
,
321 sclass
->auxiliaryClass
,
324 attr_list
= this_class_list
;
325 attr_list
= merge_attr_list(mem_ctx
, attr_list
, recursive_list
);
326 attr_list
= merge_attr_list(mem_ctx
, attr_list
, system_recursive_list
);
330 /* Return a full attribute list for a given class list (as a ldb_message_element)
332 Via attribute_list_from_class() this calls itself when recursing on auxiliary classes
334 static const char **dsdb_full_attribute_list_internal(TALLOC_CTX
*mem_ctx
,
335 const struct dsdb_schema
*schema
,
336 const char **class_list
,
337 enum dsdb_attr_list_query query
)
340 const char **attr_list
= NULL
;
342 for (i
=0; class_list
&& class_list
[i
]; i
++) {
343 const char **sclass_list
344 = attribute_list_from_class(mem_ctx
, schema
,
345 dsdb_class_by_lDAPDisplayName(schema
, class_list
[i
]),
348 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass_list
);
353 /* Return a full attribute list for a given class list (as a ldb_message_element)
355 Using the ldb_message_element ensures we do length-limited
356 comparisons, rather than casting the possibly-unterminated string
358 Via attribute_list_from_class() this calls
359 dsdb_full_attribute_list_internal() when recursing on auxiliary classes
361 static const char **dsdb_full_attribute_list_internal_el(TALLOC_CTX
*mem_ctx
,
362 const struct dsdb_schema
*schema
,
363 const struct ldb_message_element
*el
,
364 enum dsdb_attr_list_query query
)
367 const char **attr_list
= NULL
;
369 for (i
=0; i
< el
->num_values
; i
++) {
370 const char **sclass_list
371 = attribute_list_from_class(mem_ctx
, schema
,
372 dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &el
->values
[i
]),
375 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass_list
);
380 /* Helper function to remove duplicates from the attribute list to be returned */
381 static const char **dedup_attr_list(const char **attr_list
)
383 size_t new_len
= str_list_length(attr_list
);
384 /* Remove duplicates */
387 qsort(attr_list
, new_len
,
389 (comparison_fn_t
)strcasecmp
);
391 for (i
=1 ; i
< new_len
; i
++) {
392 const char **val1
= &attr_list
[i
-1];
393 const char **val2
= &attr_list
[i
];
394 if (ldb_attr_cmp(*val1
, *val2
) == 0) {
395 memmove(val1
, val2
, (new_len
- i
) * sizeof( *attr_list
));
404 /* Return a full attribute list for a given class list (as a ldb_message_element)
406 Using the ldb_message_element ensures we do length-limited
407 comparisons, rather than casting the possibly-unterminated string
409 The result contains only unique values
411 const char **dsdb_full_attribute_list(TALLOC_CTX
*mem_ctx
,
412 const struct dsdb_schema
*schema
,
413 const struct ldb_message_element
*class_list
,
414 enum dsdb_attr_list_query query
)
416 const char **attr_list
= dsdb_full_attribute_list_internal_el(mem_ctx
, schema
, class_list
, query
);
417 return dedup_attr_list(attr_list
);