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
->tmp
.supclasses
) {
43 return schema_class
->tmp
.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
->tmp
.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
->tmp
.supclasses
= str_list_unique(list
);
70 return schema_class
->tmp
.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
->tmp
.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
->tmp
.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
->tmp
.posssuperiors
= str_list_unique(list2
);
124 return schema_class
->tmp
.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
->tmp
.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 static void schema_subclasses_order_recurse(const struct dsdb_schema
*schema
,
145 struct dsdb_class
*schema_class
,
148 const char **list
= schema_class
->tmp
.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
->tmp
.subclasses_direct
== NULL
) {
173 schema_class2
->tmp
.subclasses_direct
= const_str_list(str_list_make_empty(schema_class2
));
174 if (!schema_class2
->tmp
.subclasses_direct
) {
175 return LDB_ERR_OPERATIONS_ERROR
;
178 schema_class2
->tmp
.subclasses_direct
= str_list_add_const(schema_class2
->tmp
.subclasses_direct
,
179 schema_class
->lDAPDisplayName
);
183 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
184 schema_class
->tmp
.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
;
204 const char **poss_inf
= NULL
;
205 const char **sys_poss_inf
= NULL
;
207 for (c2
= schema
->classes
; c2
; c2
= c2
->next
) {
208 const char **superiors
= schema_posssuperiors(schema
, c2
);
209 if (c2
->objectClassCategory
!= 2 &&
210 c2
->objectClassCategory
!= 3 &&
211 str_list_check(superiors
, schema_class
->lDAPDisplayName
))
213 if (c2
->systemOnly
== false) {
214 if (poss_inf
== NULL
) {
215 poss_inf
= const_str_list(str_list_make_empty(schema_class
));
217 poss_inf
= str_list_add_const(poss_inf
,
218 c2
->lDAPDisplayName
);
220 if (sys_poss_inf
== NULL
) {
221 sys_poss_inf
= const_str_list(str_list_make_empty(schema_class
));
223 sys_poss_inf
= str_list_add_const(sys_poss_inf
,
224 c2
->lDAPDisplayName
);
227 schema_class
->systemPossibleInferiors
= str_list_unique(sys_poss_inf
);
228 schema_class
->possibleInferiors
= str_list_unique(poss_inf
);
232 fill in a string class name from a governs_ID
234 static void schema_fill_from_class_one(const struct dsdb_schema
*schema
,
235 const struct dsdb_class
*c
,
239 if (*s
== NULL
&& id
!= 0) {
240 const struct dsdb_class
*c2
=
241 dsdb_class_by_governsID_id(schema
, id
);
243 *s
= c2
->lDAPDisplayName
;
249 fill in a list of string class names from a governs_ID list
251 static void schema_fill_from_class_list(const struct dsdb_schema
*schema
,
252 const struct dsdb_class
*c
,
256 if (*s
== NULL
&& ids
!= NULL
) {
258 for (i
=0;ids
[i
];i
++) ;
259 *s
= talloc_array(c
, const char *, i
+1);
260 for (i
=0;ids
[i
];i
++) {
261 const struct dsdb_class
*c2
=
262 dsdb_class_by_governsID_id(schema
, ids
[i
]);
264 (*s
)[i
] = c2
->lDAPDisplayName
;
274 fill in a list of string attribute names from a attributeID list
276 static void schema_fill_from_attribute_list(const struct dsdb_schema
*schema
,
277 const struct dsdb_class
*c
,
281 if (*s
== NULL
&& ids
!= NULL
) {
283 for (i
=0;ids
[i
];i
++) ;
284 *s
= talloc_array(c
, const char *, i
+1);
285 for (i
=0;ids
[i
];i
++) {
286 const struct dsdb_attribute
*a
=
287 dsdb_attribute_by_attributeID_id(schema
, ids
[i
]);
289 (*s
)[i
] = a
->lDAPDisplayName
;
299 if the schema came from DRS then some attributes will be setup as IDs
301 static void schema_fill_from_ids(const struct dsdb_schema
*schema
)
303 struct dsdb_class
*c
;
304 for (c
=schema
->classes
; c
; c
=c
->next
) {
305 schema_fill_from_class_one(schema
, c
, &c
->subClassOf
, c
->subClassOf_id
);
306 schema_fill_from_attribute_list(schema
, c
, &c
->systemMayContain
, c
->systemMayContain_ids
);
307 schema_fill_from_attribute_list(schema
, c
, &c
->systemMustContain
, c
->systemMustContain_ids
);
308 schema_fill_from_attribute_list(schema
, c
, &c
->mustContain
, c
->mustContain_ids
);
309 schema_fill_from_attribute_list(schema
, c
, &c
->mayContain
, c
->mayContain_ids
);
310 schema_fill_from_class_list(schema
, c
, &c
->possSuperiors
, c
->possSuperiors_ids
);
311 schema_fill_from_class_list(schema
, c
, &c
->systemPossSuperiors
, c
->systemPossSuperiors_ids
);
312 schema_fill_from_class_list(schema
, c
, &c
->systemAuxiliaryClass
, c
->systemAuxiliaryClass_ids
);
313 schema_fill_from_class_list(schema
, c
, &c
->auxiliaryClass
, c
->auxiliaryClass_ids
);
317 int schema_fill_constructed(const struct dsdb_schema
*schema
)
320 struct dsdb_class
*schema_class
;
322 /* make sure we start with a clean cache */
323 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
324 ZERO_STRUCT(schema_class
->tmp
);
327 schema_fill_from_ids(schema
);
329 ret
= schema_create_subclasses(schema
);
330 if (ret
!= LDB_SUCCESS
) {
334 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
335 schema_fill_possible_inferiors(schema
, schema_class
);
338 /* free up our internal cache elements */
339 for (schema_class
=schema
->classes
; schema_class
; schema_class
=schema_class
->next
) {
340 TALLOC_FREE(schema_class
->tmp
.supclasses
);
341 TALLOC_FREE(schema_class
->tmp
.subclasses_direct
);
342 TALLOC_FREE(schema_class
->tmp
.subclasses
);
343 TALLOC_FREE(schema_class
->tmp
.posssuperiors
);