2 Unix SMB/CIFS implementation.
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', i.e. 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 '%s' for '%s'\n",
167 schema_class
->subClassOf
,
168 schema_class
->lDAPDisplayName
));
169 return LDB_ERR_OPERATIONS_ERROR
;
171 if (schema_class2
&& schema_class
!= schema_class2
) {
172 if (schema_class2
->subclasses_direct
== NULL
) {
173 schema_class2
->subclasses_direct
= const_str_list(str_list_make_empty(schema_class2
));
174 if (!schema_class2
->subclasses_direct
) {
175 return LDB_ERR_OPERATIONS_ERROR
;
178 schema_class2
->subclasses_direct
= str_list_add_const(schema_class2
->subclasses_direct
,
179 schema_class
->lDAPDisplayName
);
183 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
184 schema_class
->subclasses
= str_list_unique(schema_subclasses_recurse(schema
, schema_class
));
186 /* Initialize the subClass order, to ensure we can't have uninitialized sort on the subClass hierarchy */
187 schema_class
->subClass_order
= 0;
190 top
= discard_const_p(struct dsdb_class
, dsdb_class_by_lDAPDisplayName(schema
, "top"));
192 DEBUG(0,("ERROR: no 'top' class in loaded schema\n"));
193 return LDB_ERR_OPERATIONS_ERROR
;
196 schema_subclasses_order_recurse(schema
, top
, 1);
200 static void schema_fill_possible_inferiors(const struct dsdb_schema
*schema
,
201 struct dsdb_class
*schema_class
)
203 struct dsdb_class
*c2
;
205 for (c2
=schema
->classes
; c2
; c2
=c2
->next
) {
206 const char **superiors
= schema_posssuperiors(schema
, c2
);
207 if (c2
->systemOnly
== false
208 && c2
->objectClassCategory
!= 2
209 && c2
->objectClassCategory
!= 3
210 && str_list_check(superiors
, schema_class
->lDAPDisplayName
)) {
211 if (schema_class
->possibleInferiors
== NULL
) {
212 schema_class
->possibleInferiors
= const_str_list(str_list_make_empty(schema_class
));
214 schema_class
->possibleInferiors
= str_list_add_const(schema_class
->possibleInferiors
,
215 c2
->lDAPDisplayName
);
218 schema_class
->possibleInferiors
= str_list_unique(schema_class
->possibleInferiors
);
221 static void schema_fill_system_possible_inferiors(const struct dsdb_schema
*schema
,
222 struct dsdb_class
*schema_class
)
224 struct dsdb_class
*c2
;
226 for (c2
=schema
->classes
; c2
; c2
=c2
->next
) {
227 const char **superiors
= schema_posssuperiors(schema
, c2
);
228 if (c2
->objectClassCategory
!= 2
229 && c2
->objectClassCategory
!= 3
230 && str_list_check(superiors
, schema_class
->lDAPDisplayName
)) {
231 if (schema_class
->systemPossibleInferiors
== NULL
) {
232 schema_class
->systemPossibleInferiors
= const_str_list(str_list_make_empty(schema_class
));
234 schema_class
->systemPossibleInferiors
= str_list_add_const(schema_class
->systemPossibleInferiors
,
235 c2
->lDAPDisplayName
);
238 schema_class
->systemPossibleInferiors
= str_list_unique(schema_class
->systemPossibleInferiors
);
242 fill in a string class name from a governs_ID
244 static void schema_fill_from_class_one(const struct dsdb_schema
*schema
,
245 const struct dsdb_class
*c
,
249 if (*s
== NULL
&& id
!= 0) {
250 const struct dsdb_class
*c2
=
251 dsdb_class_by_governsID_id(schema
, id
);
253 *s
= c2
->lDAPDisplayName
;
259 fill in a list of string class names from a governs_ID list
261 static void schema_fill_from_class_list(const struct dsdb_schema
*schema
,
262 const struct dsdb_class
*c
,
266 if (*s
== NULL
&& ids
!= NULL
) {
268 for (i
=0;ids
[i
];i
++) ;
269 *s
= talloc_array(c
, const char *, i
+1);
270 for (i
=0;ids
[i
];i
++) {
271 const struct dsdb_class
*c2
=
272 dsdb_class_by_governsID_id(schema
, ids
[i
]);
274 (*s
)[i
] = c2
->lDAPDisplayName
;
284 fill in a list of string attribute names from a attributeID list
286 static void schema_fill_from_attribute_list(const struct dsdb_schema
*schema
,
287 const struct dsdb_class
*c
,
291 if (*s
== NULL
&& ids
!= NULL
) {
293 for (i
=0;ids
[i
];i
++) ;
294 *s
= talloc_array(c
, const char *, i
+1);
295 for (i
=0;ids
[i
];i
++) {
296 const struct dsdb_attribute
*a
=
297 dsdb_attribute_by_attributeID_id(schema
, ids
[i
]);
299 (*s
)[i
] = a
->lDAPDisplayName
;
309 if the schema came from DRS then some attributes will be setup as IDs
311 static void schema_fill_from_ids(const struct dsdb_schema
*schema
)
313 struct dsdb_class
*c
;
314 for (c
=schema
->classes
; c
; c
=c
->next
) {
315 schema_fill_from_class_one(schema
, c
, &c
->subClassOf
, c
->subClassOf_id
);
316 schema_fill_from_attribute_list(schema
, c
, &c
->systemMayContain
, c
->systemMayContain_ids
);
317 schema_fill_from_attribute_list(schema
, c
, &c
->systemMustContain
, c
->systemMustContain_ids
);
318 schema_fill_from_attribute_list(schema
, c
, &c
->mustContain
, c
->mustContain_ids
);
319 schema_fill_from_attribute_list(schema
, c
, &c
->mayContain
, c
->mayContain_ids
);
320 schema_fill_from_class_list(schema
, c
, &c
->possSuperiors
, c
->possSuperiors_ids
);
321 schema_fill_from_class_list(schema
, c
, &c
->systemPossSuperiors
, c
->systemPossSuperiors_ids
);
322 schema_fill_from_class_list(schema
, c
, &c
->systemAuxiliaryClass
, c
->systemAuxiliaryClass_ids
);
323 schema_fill_from_class_list(schema
, c
, &c
->auxiliaryClass
, c
->auxiliaryClass_ids
);
327 int schema_fill_constructed(const struct dsdb_schema
*schema
)
330 struct dsdb_class
*schema_class
;
332 schema_fill_from_ids(schema
);
334 ret
= schema_create_subclasses(schema
);
335 if (ret
!= LDB_SUCCESS
) {
339 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
340 schema_fill_possible_inferiors(schema
, schema_class
);
341 schema_fill_system_possible_inferiors(schema
, schema_class
);
344 /* free up our internal cache elements */
345 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
346 talloc_free(schema_class
->supclasses
);
347 talloc_free(schema_class
->subclasses_direct
);
348 talloc_free(schema_class
->subclasses
);
349 talloc_free(schema_class
->posssuperiors
);
350 schema_class
->supclasses
= NULL
;
351 schema_class
->subclasses_direct
= NULL
;
352 schema_class
->subclasses
= NULL
;
353 schema_class
->posssuperiors
= NULL
;