s3:registry: wrap reg_createkey() in a transaction
[Samba.git] / source4 / dsdb / schema / schema_query.c
blobc92d273edf1960a83198ed82c9de32be9f29c813
1 /*
2 Unix SMB/CIFS mplementation.
3 DSDB schema header
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/>.
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "lib/util/binsearch.h"
26 #include "lib/util/tsort.h"
28 static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
29 const struct dsdb_schema *schema,
30 const char **class_list,
31 enum dsdb_attr_list_query query);
33 static int uint32_cmp(uint32_t c1, uint32_t c2)
35 if (c1 == c2) return 0;
36 return c1 > c2 ? 1 : -1;
39 static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str)
41 int ret = strncasecmp((const char *)target->data, str, target->length);
42 if (ret == 0) {
43 size_t len = strlen(str);
44 if (target->length > len) {
45 if (target->data[len] == 0) {
46 return 0;
48 return 1;
50 return (target->length - len);
52 return ret;
55 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
56 uint32_t id)
58 struct dsdb_attribute *c;
61 * 0xFFFFFFFF is used as value when no mapping table is available,
62 * so don't try to match with it
64 if (id == 0xFFFFFFFF) return NULL;
66 /* check for msDS-IntId type attribute */
67 if (dsdb_pfm_get_attid_type(id) == DSDB_ATTID_TYPE_INTID) {
68 BINARY_ARRAY_SEARCH_P(schema->attributes_by_msDS_IntId,
69 schema->num_int_id_attr, msDS_IntId, id, uint32_cmp, c);
70 return c;
73 BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_id,
74 schema->num_attributes, attributeID_id, id, uint32_cmp, c);
75 return c;
78 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
79 const char *oid)
81 struct dsdb_attribute *c;
83 if (!oid) return NULL;
85 BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_oid,
86 schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
87 return c;
90 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
91 const char *name)
93 struct dsdb_attribute *c;
95 if (!name) return NULL;
97 BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
98 schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
99 return c;
102 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
103 const struct ldb_val *name)
105 struct dsdb_attribute *a;
107 if (!name) return NULL;
109 BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
110 schema->num_attributes, lDAPDisplayName, name, strcasecmp_with_ldb_val, a);
111 return a;
114 const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
115 int linkID)
117 struct dsdb_attribute *c;
119 BINARY_ARRAY_SEARCH_P(schema->attributes_by_linkID,
120 schema->num_attributes, linkID, linkID, uint32_cmp, c);
121 return c;
124 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
125 uint32_t id)
127 struct dsdb_class *c;
130 * 0xFFFFFFFF is used as value when no mapping table is available,
131 * so don't try to match with it
133 if (id == 0xFFFFFFFF) return NULL;
135 BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_id,
136 schema->num_classes, governsID_id, id, uint32_cmp, c);
137 return c;
140 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
141 const char *oid)
143 struct dsdb_class *c;
144 if (!oid) return NULL;
145 BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_oid,
146 schema->num_classes, governsID_oid, oid, strcasecmp, c);
147 return c;
150 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
151 const char *name)
153 struct dsdb_class *c;
154 if (!name) return NULL;
155 BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
156 schema->num_classes, lDAPDisplayName, name, strcasecmp, c);
157 return c;
160 const struct dsdb_class *dsdb_class_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
161 const struct ldb_val *name)
163 struct dsdb_class *c;
164 if (!name) return NULL;
165 BINARY_ARRAY_SEARCH_P(schema->classes_by_lDAPDisplayName,
166 schema->num_classes, lDAPDisplayName, name, strcasecmp_with_ldb_val, c);
167 return c;
170 const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
171 const char *cn)
173 struct dsdb_class *c;
174 if (!cn) return NULL;
175 BINARY_ARRAY_SEARCH_P(schema->classes_by_cn,
176 schema->num_classes, cn, cn, strcasecmp, c);
177 return c;
180 const struct dsdb_class *dsdb_class_by_cn_ldb_val(const struct dsdb_schema *schema,
181 const struct ldb_val *cn)
183 struct dsdb_class *c;
184 if (!cn) return NULL;
185 BINARY_ARRAY_SEARCH_P(schema->classes_by_cn,
186 schema->num_classes, cn, cn, strcasecmp_with_ldb_val, c);
187 return c;
190 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
191 uint32_t id)
193 const struct dsdb_attribute *a;
194 const struct dsdb_class *c;
196 a = dsdb_attribute_by_attributeID_id(schema, id);
197 if (a) {
198 return a->lDAPDisplayName;
201 c = dsdb_class_by_governsID_id(schema, id);
202 if (c) {
203 return c->lDAPDisplayName;
206 return NULL;
209 /**
210 Return a list of linked attributes, in lDAPDisplayName format.
212 This may be used to determine if a modification would require
213 backlinks to be updated, for example
216 WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
218 const char **attr_list = NULL;
219 struct dsdb_attribute *cur;
220 unsigned int i = 0;
221 for (cur = schema->attributes; cur; cur = cur->next) {
222 if (cur->linkID == 0) continue;
224 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
225 if (!attr_list) {
226 return WERR_NOMEM;
228 attr_list[i] = cur->lDAPDisplayName;
229 i++;
231 attr_list[i] = NULL;
232 *attr_list_ret = attr_list;
233 return WERR_OK;
236 const char **merge_attr_list(TALLOC_CTX *mem_ctx,
237 const char **attrs, const char * const*new_attrs)
239 const char **ret_attrs;
240 unsigned int i;
241 size_t new_len, orig_len = str_list_length(attrs);
242 if (!new_attrs) {
243 return attrs;
246 ret_attrs = talloc_realloc(mem_ctx,
247 attrs, const char *, orig_len + str_list_length(new_attrs) + 1);
248 if (ret_attrs) {
249 for (i=0; i < str_list_length(new_attrs); i++) {
250 ret_attrs[orig_len + i] = new_attrs[i];
252 new_len = orig_len + str_list_length(new_attrs);
254 ret_attrs[new_len] = NULL;
257 return ret_attrs;
261 Return a merged list of the attributes of exactly one class (not
262 considering subclasses, auxillary classes etc)
265 const char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *sclass, enum dsdb_attr_list_query query)
267 const char **attr_list = NULL;
268 switch (query) {
269 case DSDB_SCHEMA_ALL_MAY:
270 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
271 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
272 break;
274 case DSDB_SCHEMA_ALL_MUST:
275 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
276 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
277 break;
279 case DSDB_SCHEMA_SYS_MAY:
280 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
281 break;
283 case DSDB_SCHEMA_SYS_MUST:
284 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
285 break;
287 case DSDB_SCHEMA_MAY:
288 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
289 break;
291 case DSDB_SCHEMA_MUST:
292 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
293 break;
295 case DSDB_SCHEMA_ALL:
296 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
297 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
298 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
299 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
300 break;
302 return attr_list;
305 static const char **attribute_list_from_class(TALLOC_CTX *mem_ctx,
306 const struct dsdb_schema *schema,
307 const struct dsdb_class *sclass,
308 enum dsdb_attr_list_query query)
310 const char **this_class_list;
311 const char **system_recursive_list;
312 const char **recursive_list;
313 const char **attr_list;
315 this_class_list = dsdb_attribute_list(mem_ctx, sclass, query);
317 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
318 sclass->systemAuxiliaryClass,
319 query);
321 system_recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
322 sclass->auxiliaryClass,
323 query);
325 attr_list = this_class_list;
326 attr_list = merge_attr_list(mem_ctx, attr_list, recursive_list);
327 attr_list = merge_attr_list(mem_ctx, attr_list, system_recursive_list);
328 return attr_list;
331 /* Return a full attribute list for a given class list (as a ldb_message_element)
333 Via attribute_list_from_class() this calls itself when recursing on auxiliary classes
335 static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx,
336 const struct dsdb_schema *schema,
337 const char **class_list,
338 enum dsdb_attr_list_query query)
340 unsigned int i;
341 const char **attr_list = NULL;
343 for (i=0; class_list && class_list[i]; i++) {
344 const char **sclass_list
345 = attribute_list_from_class(mem_ctx, schema,
346 dsdb_class_by_lDAPDisplayName(schema, class_list[i]),
347 query);
349 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
351 return attr_list;
354 /* Return a full attribute list for a given class list (as a ldb_message_element)
356 Using the ldb_message_element ensures we do length-limited
357 comparisons, rather than casting the possibly-unterminated string
359 Via attribute_list_from_class() this calls
360 dsdb_full_attribute_list_internal() when recursing on auxiliary classes
362 static const char **dsdb_full_attribute_list_internal_el(TALLOC_CTX *mem_ctx,
363 const struct dsdb_schema *schema,
364 const struct ldb_message_element *el,
365 enum dsdb_attr_list_query query)
367 unsigned int i;
368 const char **attr_list = NULL;
370 for (i=0; i < el->num_values; i++) {
371 const char **sclass_list
372 = attribute_list_from_class(mem_ctx, schema,
373 dsdb_class_by_lDAPDisplayName_ldb_val(schema, &el->values[i]),
374 query);
376 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
378 return attr_list;
381 static int qsort_string(const char **s1, const char **s2)
383 return strcasecmp(*s1, *s2);
386 /* Helper function to remove duplicates from the attribute list to be returned */
387 static const char **dedup_attr_list(const char **attr_list)
389 size_t new_len = str_list_length(attr_list);
390 /* Remove duplicates */
391 if (new_len > 1) {
392 size_t i;
393 TYPESAFE_QSORT(attr_list, new_len, qsort_string);
395 for (i=1; i < new_len; i++) {
396 const char **val1 = &attr_list[i-1];
397 const char **val2 = &attr_list[i];
398 if (ldb_attr_cmp(*val1, *val2) == 0) {
399 memmove(val1, val2, (new_len - i) * sizeof( *attr_list));
400 attr_list[new_len-1] = NULL;
401 new_len--;
402 i--;
406 return attr_list;
409 /* Return a full attribute list for a given class list (as a ldb_message_element)
411 Using the ldb_message_element ensures we do length-limited
412 comparisons, rather than casting the possibly-unterminated string
414 The result contains only unique values
416 const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
417 const struct dsdb_schema *schema,
418 const struct ldb_message_element *class_list,
419 enum dsdb_attr_list_query query)
421 const char **attr_list = dsdb_full_attribute_list_internal_el(mem_ctx, schema, class_list, query);
422 return dedup_attr_list(attr_list);
425 /* Return the schemaIDGUID of a class */
427 const struct GUID *class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
428 const char *name)
430 const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
431 if (!object_class)
432 return NULL;
434 return &object_class->schemaIDGUID;
437 const struct GUID *attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
438 const char *name)
440 const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, name);
441 if (!attr)
442 return NULL;
444 return &attr->schemaIDGUID;