source: trunk/server/source4/dsdb/schema/schema_query.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 13.3 KB
Line 
1/*
2 Unix SMB/CIFS mplementation.
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 "lib/util/binsearch.h"
26#include "lib/util/tsort.h"
27
28static 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);
32
33static int uint32_cmp(uint32_t c1, uint32_t c2)
34{
35 if (c1 == c2) return 0;
36 return c1 > c2 ? 1 : -1;
37}
38
39static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str)
40{
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;
47 }
48 return 1;
49 }
50 return (target->length - len);
51 }
52 return ret;
53}
54
55const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
56 uint32_t id)
57{
58 struct dsdb_attribute *c;
59
60 /*
61 * 0xFFFFFFFF is used as value when no mapping table is available,
62 * so don't try to match with it
63 */
64 if (id == 0xFFFFFFFF) return NULL;
65
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;
71 }
72
73 BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_id,
74 schema->num_attributes, attributeID_id, id, uint32_cmp, c);
75 return c;
76}
77
78const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
79 const char *oid)
80{
81 struct dsdb_attribute *c;
82
83 if (!oid) return NULL;
84
85 BINARY_ARRAY_SEARCH_P(schema->attributes_by_attributeID_oid,
86 schema->num_attributes, attributeID_oid, oid, strcasecmp, c);
87 return c;
88}
89
90const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
91 const char *name)
92{
93 struct dsdb_attribute *c;
94
95 if (!name) return NULL;
96
97 BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
98 schema->num_attributes, lDAPDisplayName, name, strcasecmp, c);
99 return c;
100}
101
102const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
103 const struct ldb_val *name)
104{
105 struct dsdb_attribute *a;
106
107 if (!name) return NULL;
108
109 BINARY_ARRAY_SEARCH_P(schema->attributes_by_lDAPDisplayName,
110 schema->num_attributes, lDAPDisplayName, name, strcasecmp_with_ldb_val, a);
111 return a;
112}
113
114const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
115 int linkID)
116{
117 struct dsdb_attribute *c;
118
119 BINARY_ARRAY_SEARCH_P(schema->attributes_by_linkID,
120 schema->num_attributes, linkID, linkID, uint32_cmp, c);
121 return c;
122}
123
124const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
125 uint32_t id)
126{
127 struct dsdb_class *c;
128
129 /*
130 * 0xFFFFFFFF is used as value when no mapping table is available,
131 * so don't try to match with it
132 */
133 if (id == 0xFFFFFFFF) return NULL;
134
135 BINARY_ARRAY_SEARCH_P(schema->classes_by_governsID_id,
136 schema->num_classes, governsID_id, id, uint32_cmp, c);
137 return c;
138}
139
140const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
141 const char *oid)
142{
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;
148}
149
150const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
151 const char *name)
152{
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;
158}
159
160const struct dsdb_class *dsdb_class_by_lDAPDisplayName_ldb_val(const struct dsdb_schema *schema,
161 const struct ldb_val *name)
162{
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;
168}
169
170const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
171 const char *cn)
172{
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;
178}
179
180const struct dsdb_class *dsdb_class_by_cn_ldb_val(const struct dsdb_schema *schema,
181 const struct ldb_val *cn)
182{
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;
188}
189
190const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
191 uint32_t id)
192{
193 const struct dsdb_attribute *a;
194 const struct dsdb_class *c;
195
196 a = dsdb_attribute_by_attributeID_id(schema, id);
197 if (a) {
198 return a->lDAPDisplayName;
199 }
200
201 c = dsdb_class_by_governsID_id(schema, id);
202 if (c) {
203 return c->lDAPDisplayName;
204 }
205
206 return NULL;
207}
208
209/**
210 Return a list of linked attributes, in lDAPDisplayName format.
211
212 This may be used to determine if a modification would require
213 backlinks to be updated, for example
214*/
215
216WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
217{
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;
223
224 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
225 if (!attr_list) {
226 return WERR_NOMEM;
227 }
228 attr_list[i] = cur->lDAPDisplayName;
229 i++;
230 }
231 attr_list[i] = NULL;
232 *attr_list_ret = attr_list;
233 return WERR_OK;
234}
235
236const char **merge_attr_list(TALLOC_CTX *mem_ctx,
237 const char **attrs, const char * const*new_attrs)
238{
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;
244 }
245
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];
251 }
252 new_len = orig_len + str_list_length(new_attrs);
253
254 ret_attrs[new_len] = NULL;
255 }
256
257 return ret_attrs;
258}
259
260/*
261 Return a merged list of the attributes of exactly one class (not
262 considering subclasses, auxillary classes etc)
263*/
264
265const char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *sclass, enum dsdb_attr_list_query query)
266{
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;
273
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;
278
279 case DSDB_SCHEMA_SYS_MAY:
280 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMayContain);
281 break;
282
283 case DSDB_SCHEMA_SYS_MUST:
284 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->systemMustContain);
285 break;
286
287 case DSDB_SCHEMA_MAY:
288 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mayContain);
289 break;
290
291 case DSDB_SCHEMA_MUST:
292 attr_list = merge_attr_list(mem_ctx, attr_list, sclass->mustContain);
293 break;
294
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;
301 }
302 return attr_list;
303}
304
305static 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)
309{
310 const char **this_class_list;
311 const char **system_recursive_list;
312 const char **recursive_list;
313 const char **attr_list;
314
315 this_class_list = dsdb_attribute_list(mem_ctx, sclass, query);
316
317 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
318 sclass->systemAuxiliaryClass,
319 query);
320
321 system_recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema,
322 sclass->auxiliaryClass,
323 query);
324
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;
329}
330
331/* Return a full attribute list for a given class list (as a ldb_message_element)
332
333 Via attribute_list_from_class() this calls itself when recursing on auxiliary classes
334 */
335static 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)
339{
340 unsigned int i;
341 const char **attr_list = NULL;
342
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);
348
349 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
350 }
351 return attr_list;
352}
353
354/* Return a full attribute list for a given class list (as a ldb_message_element)
355
356 Using the ldb_message_element ensures we do length-limited
357 comparisons, rather than casting the possibly-unterminated string
358
359 Via attribute_list_from_class() this calls
360 dsdb_full_attribute_list_internal() when recursing on auxiliary classes
361 */
362static 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)
366{
367 unsigned int i;
368 const char **attr_list = NULL;
369
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);
375
376 attr_list = merge_attr_list(mem_ctx, attr_list, sclass_list);
377 }
378 return attr_list;
379}
380
381static int qsort_string(const char **s1, const char **s2)
382{
383 return strcasecmp(*s1, *s2);
384}
385
386/* Helper function to remove duplicates from the attribute list to be returned */
387static const char **dedup_attr_list(const char **attr_list)
388{
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);
394
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--;
403 }
404 }
405 }
406 return attr_list;
407}
408
409/* Return a full attribute list for a given class list (as a ldb_message_element)
410
411 Using the ldb_message_element ensures we do length-limited
412 comparisons, rather than casting the possibly-unterminated string
413
414 The result contains only unique values
415 */
416const 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)
420{
421 const char **attr_list = dsdb_full_attribute_list_internal_el(mem_ctx, schema, class_list, query);
422 return dedup_attr_list(attr_list);
423}
424
425/* Return the schemaIDGUID of a class */
426
427const struct GUID *class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
428 const char *name)
429{
430 const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
431 if (!object_class)
432 return NULL;
433
434 return &object_class->schemaIDGUID;
435}
436
437const struct GUID *attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
438 const char *name)
439{
440 const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, name);
441 if (!attr)
442 return NULL;
443
444 return &attr->schemaIDGUID;
445}
Note: See TracBrowser for help on using the repository browser.