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"
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
);
43 size_t len
= strlen(str
);
44 if (target
->length
> len
) {
45 if (target
->data
[len
] == 0) {
50 return (target
->length
- len
);
55 const struct dsdb_attribute
*dsdb_attribute_by_attributeID_id(const struct dsdb_schema
*schema
,
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
);
73 BINARY_ARRAY_SEARCH_P(schema
->attributes_by_attributeID_id
,
74 schema
->num_attributes
, attributeID_id
, id
, uint32_cmp
, c
);
78 const struct dsdb_attribute
*dsdb_attribute_by_attributeID_oid(const struct dsdb_schema
*schema
,
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
);
90 const struct dsdb_attribute
*dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema
*schema
,
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
);
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
);
114 const struct dsdb_attribute
*dsdb_attribute_by_linkID(const struct dsdb_schema
*schema
,
117 struct dsdb_attribute
*c
;
119 BINARY_ARRAY_SEARCH_P(schema
->attributes_by_linkID
,
120 schema
->num_attributes
, linkID
, linkID
, uint32_cmp
, c
);
124 const struct dsdb_class
*dsdb_class_by_governsID_id(const struct dsdb_schema
*schema
,
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
);
140 const struct dsdb_class
*dsdb_class_by_governsID_oid(const struct dsdb_schema
*schema
,
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
);
150 const struct dsdb_class
*dsdb_class_by_lDAPDisplayName(const struct dsdb_schema
*schema
,
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
);
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
);
170 const struct dsdb_class
*dsdb_class_by_cn(const struct dsdb_schema
*schema
,
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
);
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
);
190 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema
*schema
,
193 const struct dsdb_attribute
*a
;
194 const struct dsdb_class
*c
;
196 a
= dsdb_attribute_by_attributeID_id(schema
, id
);
198 return a
->lDAPDisplayName
;
201 c
= dsdb_class_by_governsID_id(schema
, id
);
203 return c
->lDAPDisplayName
;
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
;
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);
228 attr_list
[i
] = cur
->lDAPDisplayName
;
232 *attr_list_ret
= attr_list
;
236 const char **merge_attr_list(TALLOC_CTX
*mem_ctx
,
237 const char **attrs
, const char * const*new_attrs
)
239 const char **ret_attrs
;
241 size_t new_len
, orig_len
= str_list_length(attrs
);
246 ret_attrs
= talloc_realloc(mem_ctx
,
247 attrs
, const char *, orig_len
+ str_list_length(new_attrs
) + 1);
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
;
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
;
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
);
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
);
279 case DSDB_SCHEMA_SYS_MAY
:
280 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMayContain
);
283 case DSDB_SCHEMA_SYS_MUST
:
284 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->systemMustContain
);
287 case DSDB_SCHEMA_MAY
:
288 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mayContain
);
291 case DSDB_SCHEMA_MUST
:
292 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass
->mustContain
);
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
);
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
,
321 system_recursive_list
= dsdb_full_attribute_list_internal(mem_ctx
, schema
,
322 sclass
->auxiliaryClass
,
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
);
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
)
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
]),
349 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass_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
)
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
]),
376 attr_list
= merge_attr_list(mem_ctx
, attr_list
, sclass_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 */
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
;
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
,
430 const struct dsdb_class
*object_class
= dsdb_class_by_lDAPDisplayName(schema
, name
);
434 return &object_class
->schemaIDGUID
;
437 const struct GUID
*attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema
*schema
,
440 const struct dsdb_attribute
*attr
= dsdb_attribute_by_lDAPDisplayName(schema
, name
);
444 return &attr
->schemaIDGUID
;