2 Unix SMB/CIFS mplementation.
4 implement possibleInferiors calculation
6 Copyright (C) Andrew Tridgell 2009
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This module is a C implementation of the logic in the
25 dsdb/samdb/ldb_modules/tests/possibleInferiors.py code
27 To understand the C code, please see the python code first
31 #include "dsdb/samdb/samdb.h"
35 create the SUPCLASSES() list
37 static const char **schema_supclasses(const struct dsdb_schema
*schema
,
38 struct dsdb_class
*schema_class
)
42 if (schema_class
->supclasses
) {
43 return schema_class
->supclasses
;
46 list
= const_str_list(str_list_make_empty(schema_class
));
48 DEBUG(0,(__location__
" out of memory\n"));
52 /* Cope with 'top SUP top', ie top is subClassOf top */
53 if (schema_class
->subClassOf
&&
54 strcmp(schema_class
->lDAPDisplayName
, schema_class
->subClassOf
) == 0) {
55 schema_class
->supclasses
= list
;
59 if (schema_class
->subClassOf
) {
60 const struct dsdb_class
*schema_class2
= dsdb_class_by_lDAPDisplayName(schema
, schema_class
->subClassOf
);
62 list
= str_list_add_const(list
, schema_class
->subClassOf
);
64 list2
= schema_supclasses(schema
, discard_const_p(struct dsdb_class
, schema_class2
));
65 list
= str_list_append_const(list
, list2
);
68 schema_class
->supclasses
= str_list_unique(list
);
70 return schema_class
->supclasses
;
74 this one is used internally
75 matches SUBCLASSES() python function
77 static const char **schema_subclasses(const struct dsdb_schema
*schema
,
81 const char **list
= const_str_list(str_list_make_empty(mem_ctx
));
84 for (i
=0; oclist
&& oclist
[i
]; i
++) {
85 const struct dsdb_class
*schema_class
= dsdb_class_by_lDAPDisplayName(schema
, oclist
[i
]);
87 DEBUG(0, ("ERROR: Unable to locate subClass: '%s'\n", oclist
[i
]));
90 list
= str_list_append_const(list
, schema_class
->subclasses
);
97 equivalent of the POSSSUPERIORS() python function
99 static const char **schema_posssuperiors(const struct dsdb_schema
*schema
,
100 struct dsdb_class
*schema_class
)
102 if (schema_class
->posssuperiors
== NULL
) {
103 const char **list2
= const_str_list(str_list_make_empty(schema_class
));
107 list2
= str_list_append_const(list2
, schema_class
->systemPossSuperiors
);
108 list2
= str_list_append_const(list2
, schema_class
->possSuperiors
);
109 list3
= schema_supclasses(schema
, schema_class
);
110 for (i
=0; list3
&& list3
[i
]; i
++) {
111 const struct dsdb_class
*class2
= dsdb_class_by_lDAPDisplayName(schema
, list3
[i
]);
113 DEBUG(0, ("ERROR: Unable to locate supClass: '%s'\n", list3
[i
]));
116 list2
= str_list_append_const(list2
, schema_posssuperiors(schema
,
117 discard_const_p(struct dsdb_class
, class2
)));
119 list2
= str_list_append_const(list2
, schema_subclasses(schema
, list2
, list2
));
121 schema_class
->posssuperiors
= str_list_unique(list2
);
124 return schema_class
->posssuperiors
;
127 static const char **schema_subclasses_recurse(const struct dsdb_schema
*schema
,
128 struct dsdb_class
*schema_class
)
130 const char **list
= str_list_copy_const(schema_class
, schema_class
->subclasses_direct
);
132 for (i
=0;list
&& list
[i
]; i
++) {
133 const struct dsdb_class
*schema_class2
= dsdb_class_by_lDAPDisplayName(schema
, list
[i
]);
134 if (schema_class
!= schema_class2
) {
135 list
= str_list_append_const(list
, schema_subclasses_recurse(schema
,
136 discard_const_p(struct dsdb_class
, schema_class2
)));
142 /* Walk down the subClass tree, setting a higher index as we go down
143 * each level. top is 1, subclasses of top are 2, etc */
144 void schema_subclasses_order_recurse(const struct dsdb_schema
*schema
,
145 struct dsdb_class
*schema_class
,
148 const char **list
= schema_class
->subclasses_direct
;
150 schema_class
->subClass_order
= order
;
151 for (i
=0;list
&& list
[i
]; i
++) {
152 const struct dsdb_class
*schema_class2
= dsdb_class_by_lDAPDisplayName(schema
, list
[i
]);
153 schema_subclasses_order_recurse(schema
, discard_const_p(struct dsdb_class
, schema_class2
), order
+1);
158 static int schema_create_subclasses(const struct dsdb_schema
*schema
)
160 struct dsdb_class
*schema_class
, *top
;
162 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
163 struct dsdb_class
*schema_class2
= discard_const_p(struct dsdb_class
,
164 dsdb_class_by_lDAPDisplayName(schema
, schema_class
->subClassOf
));
165 if (schema_class2
== NULL
) {
166 DEBUG(0,("ERROR: no subClassOf for '%s'\n", schema_class
->lDAPDisplayName
));
167 return LDB_ERR_OPERATIONS_ERROR
;
169 if (schema_class2
&& schema_class
!= schema_class2
) {
170 if (schema_class2
->subclasses_direct
== NULL
) {
171 schema_class2
->subclasses_direct
= const_str_list(str_list_make_empty(schema_class2
));
172 if (!schema_class2
->subclasses_direct
) {
173 return LDB_ERR_OPERATIONS_ERROR
;
176 schema_class2
->subclasses_direct
= str_list_add_const(schema_class2
->subclasses_direct
,
177 schema_class
->lDAPDisplayName
);
181 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
182 schema_class
->subclasses
= str_list_unique(schema_subclasses_recurse(schema
, schema_class
));
184 /* Initilise the subClass order, to ensure we can't have uninitilised sort on the subClass hirarchy */
185 schema_class
->subClass_order
= 0;
188 top
= discard_const_p(struct dsdb_class
, dsdb_class_by_lDAPDisplayName(schema
, "top"));
190 DEBUG(0,("ERROR: no 'top' class in loaded schema\n"));
191 return LDB_ERR_OPERATIONS_ERROR
;
194 schema_subclasses_order_recurse(schema
, top
, 1);
198 static void schema_fill_possible_inferiors(const struct dsdb_schema
*schema
,
199 struct dsdb_class
*schema_class
)
201 struct dsdb_class
*c2
;
203 for (c2
=schema
->classes
; c2
; c2
=c2
->next
) {
204 const char **superiors
= schema_posssuperiors(schema
, c2
);
205 if (c2
->systemOnly
== false
206 && c2
->objectClassCategory
!= 2
207 && c2
->objectClassCategory
!= 3
208 && str_list_check(superiors
, schema_class
->lDAPDisplayName
)) {
209 if (schema_class
->possibleInferiors
== NULL
) {
210 schema_class
->possibleInferiors
= const_str_list(str_list_make_empty(schema_class
));
212 schema_class
->possibleInferiors
= str_list_add_const(schema_class
->possibleInferiors
,
213 c2
->lDAPDisplayName
);
216 schema_class
->possibleInferiors
= str_list_unique(schema_class
->possibleInferiors
);
219 static void schema_fill_system_possible_inferiors(const struct dsdb_schema
*schema
,
220 struct dsdb_class
*schema_class
)
222 struct dsdb_class
*c2
;
224 for (c2
=schema
->classes
; c2
; c2
=c2
->next
) {
225 const char **superiors
= schema_posssuperiors(schema
, c2
);
226 if (c2
->objectClassCategory
!= 2
227 && c2
->objectClassCategory
!= 3
228 && str_list_check(superiors
, schema_class
->lDAPDisplayName
)) {
229 if (schema_class
->systemPossibleInferiors
== NULL
) {
230 schema_class
->systemPossibleInferiors
= const_str_list(str_list_make_empty(schema_class
));
232 schema_class
->systemPossibleInferiors
= str_list_add_const(schema_class
->systemPossibleInferiors
,
233 c2
->lDAPDisplayName
);
236 schema_class
->systemPossibleInferiors
= str_list_unique(schema_class
->systemPossibleInferiors
);
240 fill in a string class name from a governs_ID
242 static void schema_fill_from_class_one(const struct dsdb_schema
*schema
,
243 const struct dsdb_class
*c
,
247 if (*s
== NULL
&& id
!= 0) {
248 const struct dsdb_class
*c2
=
249 dsdb_class_by_governsID_id(schema
, id
);
251 *s
= c2
->lDAPDisplayName
;
257 fill in a list of string class names from a governs_ID list
259 static void schema_fill_from_class_list(const struct dsdb_schema
*schema
,
260 const struct dsdb_class
*c
,
264 if (*s
== NULL
&& ids
!= NULL
) {
266 for (i
=0;ids
[i
];i
++) ;
267 *s
= talloc_array(c
, const char *, i
+1);
268 for (i
=0;ids
[i
];i
++) {
269 const struct dsdb_class
*c2
=
270 dsdb_class_by_governsID_id(schema
, ids
[i
]);
272 (*s
)[i
] = c2
->lDAPDisplayName
;
282 fill in a list of string attribute names from a attributeID list
284 static void schema_fill_from_attribute_list(const struct dsdb_schema
*schema
,
285 const struct dsdb_class
*c
,
289 if (*s
== NULL
&& ids
!= NULL
) {
291 for (i
=0;ids
[i
];i
++) ;
292 *s
= talloc_array(c
, const char *, i
+1);
293 for (i
=0;ids
[i
];i
++) {
294 const struct dsdb_attribute
*a
=
295 dsdb_attribute_by_attributeID_id(schema
, ids
[i
]);
297 (*s
)[i
] = a
->lDAPDisplayName
;
307 if the schema came from DRS then some attributes will be setup as IDs
309 static void schema_fill_from_ids(const struct dsdb_schema
*schema
)
311 struct dsdb_class
*c
;
312 for (c
=schema
->classes
; c
; c
=c
->next
) {
313 schema_fill_from_class_one(schema
, c
, &c
->subClassOf
, c
->subClassOf_id
);
314 schema_fill_from_attribute_list(schema
, c
, &c
->systemMayContain
, c
->systemMayContain_ids
);
315 schema_fill_from_attribute_list(schema
, c
, &c
->systemMustContain
, c
->systemMustContain_ids
);
316 schema_fill_from_attribute_list(schema
, c
, &c
->mustContain
, c
->mustContain_ids
);
317 schema_fill_from_attribute_list(schema
, c
, &c
->mayContain
, c
->mayContain_ids
);
318 schema_fill_from_class_list(schema
, c
, &c
->possSuperiors
, c
->possSuperiors_ids
);
319 schema_fill_from_class_list(schema
, c
, &c
->systemPossSuperiors
, c
->systemPossSuperiors_ids
);
320 schema_fill_from_class_list(schema
, c
, &c
->systemAuxiliaryClass
, c
->systemAuxiliaryClass_ids
);
321 schema_fill_from_class_list(schema
, c
, &c
->auxiliaryClass
, c
->auxiliaryClass_ids
);
325 int schema_fill_constructed(const struct dsdb_schema
*schema
)
328 struct dsdb_class
*schema_class
;
330 schema_fill_from_ids(schema
);
332 ret
= schema_create_subclasses(schema
);
333 if (ret
!= LDB_SUCCESS
) {
337 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
338 schema_fill_possible_inferiors(schema
, schema_class
);
339 schema_fill_system_possible_inferiors(schema
, schema_class
);
342 /* free up our internal cache elements */
343 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
344 talloc_free(schema_class
->supclasses
);
345 talloc_free(schema_class
->subclasses_direct
);
346 talloc_free(schema_class
->subclasses
);
347 talloc_free(schema_class
->posssuperiors
);
348 schema_class
->supclasses
= NULL
;
349 schema_class
->subclasses_direct
= NULL
;
350 schema_class
->subclasses
= NULL
;
351 schema_class
->posssuperiors
= NULL
;