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 int uint32_cmp(uint32_t c1, uint32_t c2)
60 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
63 struct dsdb_attribute *c;
66 * 0xFFFFFFFF is used as value when no mapping table is available,
67 * so don't try to match with it
69 if (id == 0xFFFFFFFF) return NULL;
71 BINARY_ARRAY_SEARCH(schema->attributes_by_attributeID_id,
72 schema->num_attributes, attributeID_id, id, uint32_cmp, c);
76 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
79 struct dsdb_attribute *c;
81 if (!oid) return NULL;
83 BINARY_ARRAY_SEARCH(schema->attributes_by_attributeID_oid,
84 schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
88 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
91 struct dsdb_attribute *c;
93 if (!name) return NULL;
95 BINARY_ARRAY_SEARCH(schema->attributes_by_lDAPDisplayName,
96 schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
100 const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
103 struct dsdb_attribute *c;
105 BINARY_ARRAY_SEARCH(schema->attributes_by_linkID,
106 schema->num_attributes, linkID, linkID, uint32_cmp, c);
110 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
113 struct dsdb_class *c;
116 * 0xFFFFFFFF is used as value when no mapping table is available,
117 * so don't try to match with it
119 if (id == 0xFFFFFFFF) return NULL;
121 BINARY_ARRAY_SEARCH(schema->classes_by_governsID_id,
122 schema->num_classes, governsID_id, id, uint32_cmp, c);
126 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
129 struct dsdb_class *c;
130 if (!oid) return NULL;
131 BINARY_ARRAY_SEARCH(schema->classes_by_governsID_oid,
132 schema->num_classes, governsID_oid, oid, strcasecmp, c);
136 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
139 struct dsdb_class *c;
140 if (!name) return NULL;
141 BINARY_ARRAY_SEARCH(schema->classes_by_lDAPDisplayName,
142 schema->num_classes, lDAPDisplayName, name, strcasecmp, c);
146 const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
149 struct dsdb_class *c;
150 if (!cn) return NULL;
151 BINARY_ARRAY_SEARCH(schema->classes_by_cn,
152 schema->num_classes, cn, cn, strcasecmp, c);
156 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
159 const struct dsdb_attribute *a;
160 const struct dsdb_class *c;
162 a = dsdb_attribute_by_attributeID_id(schema, id);
164 return a->lDAPDisplayName;
167 c = dsdb_class_by_governsID_id(schema, id);
169 return c->lDAPDisplayName;
176 Return a list of linked attributes, in lDAPDisplayName format.
178 This may be used to determine if a modification would require
179 backlinks to be updated, for example
182 WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
184 const char **attr_list = NULL;
185 struct dsdb_attribute *cur;
187 for (cur = schema->attributes; cur; cur = cur->next) {
188 if (cur->linkID == 0) continue;
190 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
194 attr_list[i] = cur->lDAPDisplayName;
198 *attr_list_ret = attr_list;
202 const char **merge_attr_list(TALLOC_CTX *mem_ctx,
203 const char **attrs, const char * const*new_attrs)
205 const char **ret_attrs;
207 size_t new_len, orig_len = str_list_length(attrs);
212 ret_attrs = talloc_realloc(mem_ctx,
213 attrs, const char *, orig_len + str_list_length(new_attrs) + 1);
215 for (i=0; i < str_list_length(new_attrs); i++) {
216 ret_attrs[orig_len + i] = new_attrs[i];
218 new_len = orig_len + str_list_length(new_attrs);
220 ret_attrs[new_len] = NULL;
227 Return a merged list of the attributes of exactly one class (not
228 considering subclasses, auxillary classes etc)
231 const char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *sclass, enum dsdb_attr_list_query query)
233 const char **attr_list = NULL;
235 case DSDB_SCHEMA_ALL_MAY:
236 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
237 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
240 case DSDB_SCHEMA_ALL_MUST:
241 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
242 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
245 case DSDB_SCHEMA_SYS_MAY:
246 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
249 case DSDB_SCHEMA_SYS_MUST:
250 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
253 case DSDB_SCHEMA_MAY:
254 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
257 case DSDB_SCHEMA_MUST:
258 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
261 case DSDB_SCHEMA_ALL:
262 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
263 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
264 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
265 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
271 static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
272 const struct dsdb_schema *schema,
273 const char **class_list,
274 enum dsdb_attr_list_query query)
277 const struct dsdb_class *sclass;
279 const char **attr_list = NULL;
280 const char **this_class_list;
281 const char **recursive_list;
283 for (i=0; class_list && class_list[i]; i++) {
284 sclass = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
286 this_class_list = dsdb_attribute_list(mem_ctx, sclass, query);
287 attr_list = merge_attr_list(mem_ctx, attr_list, this_class_list);
289 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
290 sclass->systemAuxiliaryClass,
293 attr_list = merge_attr_list(mem_ctx, attr_list, recursive_list);
295 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
296 sclass->auxiliaryClass,
299 attr_list = merge_attr_list(mem_ctx, attr_list, recursive_list);
305 const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
306 const struct dsdb_schema *schema,
307 const char **class_list,
308 enum dsdb_attr_list_query query)
310 const char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query);
311 size_t new_len = str_list_length(attr_list);
313 /* Remove duplicates */
316 qsort(attr_list, new_len,
318 (comparison_fn_t)strcasecmp);
320 for (i=1 ; i < new_len; i++) {
321 const char **val1 = &attr_list[i-1];
322 const char **val2 = &attr_list[i];
323 if (ldb_attr_cmp(*val1, *val2) == 0) {
324 memmove(val1, val2, (new_len - i) * sizeof( *attr_list));