4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: objectClass sorting module
27 * - sort the objectClass attribute into the class
29 * - fix DNs and attributes into 'standard' case
30 * - Add objectCategory and ntSecurityDescriptor defaults
32 * Author: Andrew Bartlett
37 #include "ldb_module.h"
38 #include "dlinklist.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/ndr/libndr.h"
41 #include "librpc/gen_ndr/ndr_security.h"
42 #include "libcli/security/security.h"
43 #include "auth/auth.h"
44 #include "param/param.h"
45 #include "../libds/common/flags.h"
49 struct ldb_module
*module
;
50 struct ldb_request
*req
;
52 struct ldb_reply
*search_res
;
54 int (*step_fn
)(struct oc_context
*);
58 struct class_list
*prev
, *next
;
59 const struct dsdb_class
*objectclass
;
62 static struct oc_context
*oc_init_context(struct ldb_module
*module
,
63 struct ldb_request
*req
)
65 struct ldb_context
*ldb
;
66 struct oc_context
*ac
;
68 ldb
= ldb_module_get_ctx(module
);
70 ac
= talloc_zero(req
, struct oc_context
);
72 ldb_set_errstring(ldb
, "Out of Memory");
82 static int objectclass_do_add(struct oc_context
*ac
);
84 /* Sort objectClasses into correct order, and validate that all
85 * objectClasses specified actually exist in the schema
88 static int objectclass_sort(struct ldb_module
*module
,
89 const struct dsdb_schema
*schema
,
91 struct ldb_message_element
*objectclass_element
,
92 struct class_list
**sorted_out
)
94 struct ldb_context
*ldb
;
97 struct class_list
*sorted
= NULL
, *parent_class
= NULL
,
98 *subclass
= NULL
, *unsorted
= NULL
, *current
, *poss_subclass
, *poss_parent
, *new_parent
;
100 ldb
= ldb_module_get_ctx(module
);
104 * We work on 4 different 'bins' (implemented here as linked lists):
106 * * sorted: the eventual list, in the order we wish to push
107 * into the database. This is the only ordered list.
109 * * parent_class: The current parent class 'bin' we are
110 * trying to find subclasses for
112 * * subclass: The subclasses we have found so far
114 * * unsorted: The remaining objectClasses
116 * The process is a matter of filtering objectClasses up from
117 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
119 * We start with 'top' (found and promoted to parent_class
120 * initially). Then we find (in unsorted) all the direct
121 * subclasses of 'top'. parent_classes is concatenated onto
122 * the end of 'sorted', and subclass becomes the list in
125 * We then repeat, until we find no more subclasses. Any left
126 * over classes are added to the end.
130 /* Firstly, dump all the objectClass elements into the
131 * unsorted bin, except for 'top', which is special */
132 for (i
=0; i
< objectclass_element
->num_values
; i
++) {
133 current
= talloc(mem_ctx
, struct class_list
);
136 return LDB_ERR_OPERATIONS_ERROR
;
138 current
->objectclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &objectclass_element
->values
[i
]);
139 if (!current
->objectclass
) {
140 ldb_asprintf_errstring(ldb
, "objectclass %.*s is not a valid objectClass in schema",
141 (int)objectclass_element
->values
[i
].length
, (const char *)objectclass_element
->values
[i
].data
);
142 /* This looks weird, but windows apparently returns this for invalid objectClass values */
143 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
144 } else if (current
->objectclass
->isDefunct
) {
145 ldb_asprintf_errstring(ldb
, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
146 (int)objectclass_element
->values
[i
].length
, (const char *)objectclass_element
->values
[i
].data
);
147 /* This looks weird, but windows apparently returns this for invalid objectClass values */
148 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
151 /* this is the root of the tree. We will start
152 * looking for subclasses from here */
153 if (ldb_attr_cmp("top", current
->objectclass
->lDAPDisplayName
) == 0) {
154 DLIST_ADD_END(parent_class
, current
, struct class_list
*);
156 DLIST_ADD_END(unsorted
, current
, struct class_list
*);
160 if (parent_class
== NULL
) {
161 current
= talloc(mem_ctx
, struct class_list
);
162 current
->objectclass
= dsdb_class_by_lDAPDisplayName(schema
, "top");
163 DLIST_ADD_END(parent_class
, current
, struct class_list
*);
166 /* For each object: find parent chain */
167 for (current
= unsorted
; schema
&& current
; current
= current
->next
) {
168 for (poss_parent
= unsorted
; poss_parent
; poss_parent
= poss_parent
->next
) {
169 if (ldb_attr_cmp(poss_parent
->objectclass
->lDAPDisplayName
, current
->objectclass
->subClassOf
) == 0) {
173 /* If we didn't get to the end of the list, we need to add this parent */
174 if (poss_parent
|| (ldb_attr_cmp("top", current
->objectclass
->subClassOf
) == 0)) {
178 new_parent
= talloc(mem_ctx
, struct class_list
);
179 new_parent
->objectclass
= dsdb_class_by_lDAPDisplayName(schema
, current
->objectclass
->subClassOf
);
180 DLIST_ADD_END(unsorted
, new_parent
, struct class_list
*);
183 /* DEBUGGING aid: how many layers are we down now? */
187 /* Find all the subclasses of classes in the
188 * parent_classes. Push them onto the subclass list */
190 /* Ensure we don't bother if there are no unsorted entries left */
191 for (current
= parent_class
; schema
&& unsorted
&& current
; current
= current
->next
) {
192 /* Walk the list of possible subclasses in unsorted */
193 for (poss_subclass
= unsorted
; poss_subclass
; ) {
194 struct class_list
*next
;
196 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
197 next
= poss_subclass
->next
;
199 if (ldb_attr_cmp(poss_subclass
->objectclass
->subClassOf
, current
->objectclass
->lDAPDisplayName
) == 0) {
200 DLIST_REMOVE(unsorted
, poss_subclass
);
201 DLIST_ADD(subclass
, poss_subclass
);
205 poss_subclass
= next
;
209 /* Now push the parent_classes as sorted, we are done with
210 these. Add to the END of the list by concatenation */
211 DLIST_CONCATENATE(sorted
, parent_class
, struct class_list
*);
213 /* and now find subclasses of these */
214 parent_class
= subclass
;
217 /* If we didn't find any subclasses we will fall out
219 } while (parent_class
);
222 *sorted_out
= sorted
;
227 /* If we don't have schema yet, then just merge the lists again */
228 DLIST_CONCATENATE(sorted
, unsorted
, struct class_list
*);
229 *sorted_out
= sorted
;
233 /* This shouldn't happen, and would break MMC, perhaps there
234 * was no 'top', a conflict in the objectClasses or some other
237 ldb_asprintf_errstring(ldb
, "objectclass %s is not a valid objectClass in objectClass chain", unsorted
->objectclass
->lDAPDisplayName
);
238 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
241 static int get_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
243 struct ldb_context
*ldb
;
244 struct oc_context
*ac
;
247 ac
= talloc_get_type(req
->context
, struct oc_context
);
248 ldb
= ldb_module_get_ctx(ac
->module
);
251 return ldb_module_done(ac
->req
, NULL
, NULL
,
252 LDB_ERR_OPERATIONS_ERROR
);
254 if (ares
->error
!= LDB_SUCCESS
&&
255 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
256 return ldb_module_done(ac
->req
, ares
->controls
,
257 ares
->response
, ares
->error
);
260 ldb_reset_err_string(ldb
);
262 switch (ares
->type
) {
263 case LDB_REPLY_ENTRY
:
264 if (ac
->search_res
!= NULL
) {
265 ldb_set_errstring(ldb
, "Too many results");
267 return ldb_module_done(ac
->req
, NULL
, NULL
,
268 LDB_ERR_OPERATIONS_ERROR
);
271 ac
->search_res
= talloc_steal(ac
, ares
);
274 case LDB_REPLY_REFERRAL
:
281 ret
= ac
->step_fn(ac
);
282 if (ret
!= LDB_SUCCESS
) {
283 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
291 static int oc_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
293 struct oc_context
*ac
;
295 ac
= talloc_get_type(req
->context
, struct oc_context
);
298 return ldb_module_done(ac
->req
, NULL
, NULL
,
299 LDB_ERR_OPERATIONS_ERROR
);
301 if (ares
->error
!= LDB_SUCCESS
) {
302 return ldb_module_done(ac
->req
, ares
->controls
,
303 ares
->response
, ares
->error
);
306 if (ares
->type
!= LDB_REPLY_DONE
) {
308 return ldb_module_done(ac
->req
, NULL
, NULL
,
309 LDB_ERR_OPERATIONS_ERROR
);
312 return ldb_module_done(ac
->req
, ares
->controls
,
313 ares
->response
, ares
->error
);
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
318 This should mean that if the parent is:
319 CN=Users,DC=samba,DC=example,DC=com
320 and a proposed child is
321 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
323 The resulting DN should be:
325 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
328 static int fix_dn(TALLOC_CTX
*mem_ctx
,
329 struct ldb_dn
*newdn
, struct ldb_dn
*parent_dn
,
330 struct ldb_dn
**fixed_dn
)
332 char *upper_rdn_attr
;
333 const struct ldb_val
*rdn_val
;
335 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
336 *fixed_dn
= ldb_dn_copy(mem_ctx
, parent_dn
);
338 /* We need the attribute name in upper case */
339 upper_rdn_attr
= strupper_talloc(*fixed_dn
,
340 ldb_dn_get_rdn_name(newdn
));
341 if (!upper_rdn_attr
) {
342 return LDB_ERR_OPERATIONS_ERROR
;
345 /* Create a new child */
346 if (ldb_dn_add_child_fmt(*fixed_dn
, "X=X") == false) {
347 return LDB_ERR_OPERATIONS_ERROR
;
351 rdn_val
= ldb_dn_get_rdn_val(newdn
);
354 /* the rules for rDN length constraints are more complex than
355 this. Until we understand them we need to leave this
356 constraint out. Otherwise we break replication, as windows
357 does sometimes send us rDNs longer than 64 */
358 if (!rdn_val
|| rdn_val
->length
> 64) {
359 DEBUG(2,(__location__
": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn
)));
364 /* And replace it with CN=foo (we need the attribute in upper case */
365 return ldb_dn_set_component(*fixed_dn
, 0, upper_rdn_attr
, *rdn_val
);
368 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
369 static int fix_check_attributes(struct ldb_context
*ldb
,
370 const struct dsdb_schema
*schema
,
371 struct ldb_message
*msg
,
372 enum ldb_request_type op
)
375 for (i
=0; i
< msg
->num_elements
; i
++) {
376 const struct dsdb_attribute
*attribute
= dsdb_attribute_by_lDAPDisplayName(schema
, msg
->elements
[i
].name
);
377 /* Add in a very special case for 'clearTextPassword',
378 * which is used for internal processing only, and is
379 * not presented in the schema */
381 if (strcasecmp(msg
->elements
[i
].name
, "clearTextPassword") != 0) {
382 ldb_asprintf_errstring(ldb
, "attribute %s is not a valid attribute in schema", msg
->elements
[i
].name
);
383 /* Apparently Windows sends exactly this behaviour */
384 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
387 msg
->elements
[i
].name
= attribute
->lDAPDisplayName
;
389 /* We have to deny write operations on constructed attributes */
390 if ((attribute
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
) != 0) {
392 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE
;
394 return LDB_ERR_CONSTRAINT_VIOLATION
;
404 static int objectclass_do_add(struct oc_context
*ac
);
406 static int objectclass_add(struct ldb_module
*module
, struct ldb_request
*req
)
408 struct ldb_context
*ldb
;
409 struct ldb_request
*search_req
;
410 struct oc_context
*ac
;
411 struct ldb_dn
*parent_dn
;
413 static const char * const parent_attrs
[] = { "objectGUID", "objectClass", NULL
};
415 ldb
= ldb_module_get_ctx(module
);
417 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_add\n");
419 /* do not manipulate our control entries */
420 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
421 return ldb_next_request(module
, req
);
424 /* the objectClass must be specified on add */
425 if (ldb_msg_find_element(req
->op
.add
.message
,
426 "objectClass") == NULL
) {
427 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
430 ac
= oc_init_context(module
, req
);
432 return LDB_ERR_OPERATIONS_ERROR
;
435 /* If there isn't a parent, just go on to the add processing */
436 if (ldb_dn_get_comp_num(ac
->req
->op
.add
.message
->dn
) == 1) {
437 return objectclass_do_add(ac
);
440 /* get copy of parent DN */
441 parent_dn
= ldb_dn_get_parent(ac
, ac
->req
->op
.add
.message
->dn
);
442 if (parent_dn
== NULL
) {
444 return LDB_ERR_OPERATIONS_ERROR
;
447 ret
= ldb_build_search_req(&search_req
, ldb
,
448 ac
, parent_dn
, LDB_SCOPE_BASE
,
449 "(objectClass=*)", parent_attrs
,
451 ac
, get_search_callback
,
453 if (ret
!= LDB_SUCCESS
) {
456 talloc_steal(search_req
, parent_dn
);
458 ac
->step_fn
= objectclass_do_add
;
460 return ldb_next_request(ac
->module
, search_req
);
463 static int objectclass_do_add(struct oc_context
*ac
)
465 struct ldb_context
*ldb
;
466 const struct dsdb_schema
*schema
;
467 struct ldb_request
*add_req
;
469 struct ldb_message_element
*objectclass_element
;
470 struct ldb_message
*msg
;
472 struct class_list
*sorted
, *current
;
475 ldb
= ldb_module_get_ctx(ac
->module
);
476 schema
= dsdb_get_schema(ldb
);
478 mem_ctx
= talloc_new(ac
);
479 if (mem_ctx
== NULL
) {
480 return LDB_ERR_OPERATIONS_ERROR
;
483 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
485 /* Check we have a valid parent */
486 if (ac
->search_res
== NULL
) {
487 if (ldb_dn_compare(ldb_get_root_basedn(ldb
),
489 /* Allow the tree to be started */
491 /* but don't keep any error string, it's meaningless */
492 ldb_set_errstring(ldb
, NULL
);
494 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, parent does not exist!",
495 ldb_dn_get_linearized(msg
->dn
));
496 talloc_free(mem_ctx
);
497 return LDB_ERR_NO_SUCH_OBJECT
;
501 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
503 ac
->req
->op
.add
.message
->dn
,
504 ac
->search_res
->message
->dn
,
507 if (ret
!= LDB_SUCCESS
) {
508 ldb_asprintf_errstring(ldb
, "Could not munge DN %s into normal form",
509 ldb_dn_get_linearized(ac
->req
->op
.add
.message
->dn
));
510 talloc_free(mem_ctx
);
516 ret
= fix_check_attributes(ldb
, schema
, msg
, ac
->req
->operation
);
517 if (ret
!= LDB_SUCCESS
) {
518 talloc_free(mem_ctx
);
522 /* This is now the objectClass list from the database */
523 objectclass_element
= ldb_msg_find_element(msg
, "objectClass");
525 if (!objectclass_element
) {
526 /* Where did it go? bail now... */
527 talloc_free(mem_ctx
);
528 return LDB_ERR_OPERATIONS_ERROR
;
530 ret
= objectclass_sort(ac
->module
, schema
, mem_ctx
, objectclass_element
, &sorted
);
531 if (ret
!= LDB_SUCCESS
) {
532 talloc_free(mem_ctx
);
536 ldb_msg_remove_attr(msg
, "objectClass");
537 ret
= ldb_msg_add_empty(msg
, "objectClass", 0, NULL
);
539 if (ret
!= LDB_SUCCESS
) {
540 talloc_free(mem_ctx
);
544 /* We must completely replace the existing objectClass entry,
545 * because we need it sorted */
547 /* Move from the linked list back into an ldb msg */
548 for (current
= sorted
; current
; current
= current
->next
) {
549 value
= talloc_strdup(msg
, current
->objectclass
->lDAPDisplayName
);
552 talloc_free(mem_ctx
);
553 return LDB_ERR_OPERATIONS_ERROR
;
555 ret
= ldb_msg_add_string(msg
, "objectClass", value
);
556 if (ret
!= LDB_SUCCESS
) {
557 ldb_set_errstring(ldb
,
558 "objectclass: could not re-add sorted "
559 "objectclass to modify msg");
560 talloc_free(mem_ctx
);
563 /* Last one is the critical one */
564 if (!current
->next
) {
565 struct ldb_message_element
*el
;
566 int32_t systemFlags
= 0;
567 const char *rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
568 if (current
->objectclass
->rDNAttID
569 && ldb_attr_cmp(rdn_name
, current
->objectclass
->rDNAttID
) != 0) {
570 ldb_asprintf_errstring(ldb
,
571 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
572 rdn_name
, current
->objectclass
->lDAPDisplayName
, current
->objectclass
->rDNAttID
);
573 return LDB_ERR_NAMING_VIOLATION
;
576 if (ac
->search_res
&& ac
->search_res
->message
) {
577 struct ldb_message_element
*oc_el
578 = ldb_msg_find_element(ac
->search_res
->message
, "objectClass");
580 bool allowed_class
= false;
582 for (i
=0; allowed_class
== false && oc_el
&& i
< oc_el
->num_values
; i
++) {
583 const struct dsdb_class
*sclass
;
585 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &oc_el
->values
[i
]);
587 /* We don't know this class? what is going on? */
590 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
591 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
592 if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
593 allowed_class
= true;
598 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
599 if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
600 allowed_class
= true;
607 if (!allowed_class
) {
608 ldb_asprintf_errstring(ldb
, "structural objectClass %s is not a valid child class for %s",
609 current
->objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(ac
->search_res
->message
->dn
));
610 return LDB_ERR_NAMING_VIOLATION
;
614 if (current
->objectclass
->systemOnly
&& !ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
615 ldb_asprintf_errstring(ldb
, "objectClass %s is systemOnly, rejecting creation of %s",
616 current
->objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(msg
->dn
));
617 return LDB_ERR_UNWILLING_TO_PERFORM
;
620 if (!ldb_msg_find_element(msg
, "objectCategory")) {
621 struct dsdb_extended_dn_store_format
*dn_format
= talloc_get_type(ldb_module_get_private(ac
->module
), struct dsdb_extended_dn_store_format
);
622 if (dn_format
&& dn_format
->store_extended_dn_in_ldb
== false) {
623 /* Strip off extended components */
624 struct ldb_dn
*dn
= ldb_dn_new(msg
, ldb
, current
->objectclass
->defaultObjectCategory
);
625 value
= ldb_dn_alloc_linearized(msg
, dn
);
628 value
= talloc_strdup(msg
, current
->objectclass
->defaultObjectCategory
);
632 talloc_free(mem_ctx
);
633 return LDB_ERR_OPERATIONS_ERROR
;
635 ldb_msg_add_string(msg
, "objectCategory", value
);
637 if (!ldb_msg_find_element(msg
, "showInAdvancedViewOnly") && (current
->objectclass
->defaultHidingValue
== true)) {
638 ldb_msg_add_string(msg
, "showInAdvancedViewOnly",
642 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
643 el
= ldb_msg_find_element(msg
, "systemFlags");
645 systemFlags
= ldb_msg_find_attr_as_int(msg
, "systemFlags", 0);
648 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
649 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
650 ldb_msg_remove_element(msg
, el
);
653 /* This flag is only allowed on attributeSchema objects */
654 if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "attributeSchema") == 0) {
655 systemFlags
&= ~SYSTEM_FLAG_ATTR_IS_RDN
;
658 if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "server") == 0) {
659 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
| SYSTEM_FLAG_CONFIG_ALLOW_RENAME
| SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
);
660 } else if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "site") == 0
661 || ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "serverContainer") == 0
662 || ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "ntDSDSA") == 0) {
663 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
665 } else if (ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "siteLink") == 0
666 || ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "siteLinkBridge") == 0
667 || ldb_attr_cmp(current
->objectclass
->lDAPDisplayName
, "nTDSConnection") == 0) {
668 systemFlags
|= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
671 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
673 if (el
|| systemFlags
!= 0) {
674 samdb_msg_add_int(ldb
, msg
, msg
, "systemFlags", systemFlags
);
680 talloc_free(mem_ctx
);
681 ret
= ldb_msg_sanity_check(ldb
, msg
);
684 if (ret
!= LDB_SUCCESS
) {
688 ret
= ldb_build_add_req(&add_req
, ldb
, ac
,
693 if (ret
!= LDB_SUCCESS
) {
697 /* perform the add */
698 return ldb_next_request(ac
->module
, add_req
);
701 static int oc_modify_callback(struct ldb_request
*req
,
702 struct ldb_reply
*ares
);
703 static int objectclass_do_mod(struct oc_context
*ac
);
705 static int objectclass_modify(struct ldb_module
*module
, struct ldb_request
*req
)
707 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
708 struct ldb_message_element
*objectclass_element
;
709 struct ldb_message
*msg
;
710 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
711 struct class_list
*sorted
, *current
;
712 struct ldb_request
*down_req
;
713 struct oc_context
*ac
;
718 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_modify\n");
720 /* do not manipulate our control entries */
721 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
722 return ldb_next_request(module
, req
);
725 /* Without schema, there isn't much to do here */
727 return ldb_next_request(module
, req
);
730 /* As with the "real" AD we don't accept empty messages */
731 if (req
->op
.mod
.message
->num_elements
== 0) {
732 ldb_set_errstring(ldb
, "objectclass: modify message must have "
733 "elements/attributes!");
734 return LDB_ERR_UNWILLING_TO_PERFORM
;
737 ac
= oc_init_context(module
, req
);
739 return LDB_ERR_OPERATIONS_ERROR
;
742 /* If no part of this touches the objectClass, then we don't
743 * need to make any changes. */
744 objectclass_element
= ldb_msg_find_element(req
->op
.mod
.message
, "objectClass");
746 /* If the only operation is the deletion of the objectClass
747 * then go on with just fixing the attribute case */
748 if (!objectclass_element
) {
749 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
751 return LDB_ERR_OPERATIONS_ERROR
;
754 ret
= fix_check_attributes(ldb
, schema
, msg
, req
->operation
);
755 if (ret
!= LDB_SUCCESS
) {
759 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
764 if (ret
!= LDB_SUCCESS
) {
768 /* go on with the call chain */
769 return ldb_next_request(module
, down_req
);
772 switch (objectclass_element
->flags
& LDB_FLAG_MOD_MASK
) {
773 case LDB_FLAG_MOD_DELETE
:
774 if (objectclass_element
->num_values
== 0) {
775 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED
;
779 case LDB_FLAG_MOD_REPLACE
:
780 mem_ctx
= talloc_new(ac
);
781 if (mem_ctx
== NULL
) {
782 return LDB_ERR_OPERATIONS_ERROR
;
785 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
787 talloc_free(mem_ctx
);
788 return LDB_ERR_OPERATIONS_ERROR
;
791 ret
= fix_check_attributes(ldb
, schema
, msg
, req
->operation
);
792 if (ret
!= LDB_SUCCESS
) {
793 talloc_free(mem_ctx
);
797 ret
= objectclass_sort(module
, schema
, mem_ctx
, objectclass_element
, &sorted
);
798 if (ret
!= LDB_SUCCESS
) {
799 talloc_free(mem_ctx
);
803 /* We must completely replace the existing objectClass entry,
804 * because we need it sorted */
806 ldb_msg_remove_attr(msg
, "objectClass");
807 ret
= ldb_msg_add_empty(msg
, "objectClass", LDB_FLAG_MOD_REPLACE
, NULL
);
809 if (ret
!= LDB_SUCCESS
) {
810 talloc_free(mem_ctx
);
814 /* Move from the linked list back into an ldb msg */
815 for (current
= sorted
; current
; current
= current
->next
) {
816 /* copy the value as this string is on the schema
817 * context and we can't rely on it not changing
818 * before the operation is over */
819 value
= talloc_strdup(msg
,
820 current
->objectclass
->lDAPDisplayName
);
823 talloc_free(mem_ctx
);
824 return LDB_ERR_OPERATIONS_ERROR
;
826 ret
= ldb_msg_add_string(msg
, "objectClass", value
);
827 if (ret
!= LDB_SUCCESS
) {
828 ldb_set_errstring(ldb
,
829 "objectclass: could not re-add sorted "
830 "objectclass to modify msg");
831 talloc_free(mem_ctx
);
836 talloc_free(mem_ctx
);
838 ret
= ldb_msg_sanity_check(ldb
, msg
);
839 if (ret
!= LDB_SUCCESS
) {
843 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
848 if (ret
!= LDB_SUCCESS
) {
852 /* go on with the call chain */
853 return ldb_next_request(module
, down_req
);
856 /* This isn't the default branch of the switch, but a 'in any
857 * other case'. When a delete isn't for all objectClasses for
861 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
864 return LDB_ERR_OPERATIONS_ERROR
;
867 ret
= fix_check_attributes(ldb
, schema
, msg
, req
->operation
);
868 if (ret
!= LDB_SUCCESS
) {
873 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
876 ac
, oc_modify_callback
,
878 if (ret
!= LDB_SUCCESS
) {
882 return ldb_next_request(module
, down_req
);
885 static int oc_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
887 struct ldb_context
*ldb
;
888 static const char * const attrs
[] = { "objectClass", NULL
};
889 struct ldb_request
*search_req
;
890 struct oc_context
*ac
;
893 ac
= talloc_get_type(req
->context
, struct oc_context
);
894 ldb
= ldb_module_get_ctx(ac
->module
);
897 return ldb_module_done(ac
->req
, NULL
, NULL
,
898 LDB_ERR_OPERATIONS_ERROR
);
900 if (ares
->error
!= LDB_SUCCESS
) {
901 return ldb_module_done(ac
->req
, ares
->controls
,
902 ares
->response
, ares
->error
);
905 if (ares
->type
!= LDB_REPLY_DONE
) {
907 return ldb_module_done(ac
->req
, NULL
, NULL
,
908 LDB_ERR_OPERATIONS_ERROR
);
913 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
914 ac
->req
->op
.mod
.message
->dn
, LDB_SCOPE_BASE
,
917 ac
, get_search_callback
,
919 if (ret
!= LDB_SUCCESS
) {
920 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
923 ac
->step_fn
= objectclass_do_mod
;
925 ret
= ldb_next_request(ac
->module
, search_req
);
926 if (ret
!= LDB_SUCCESS
) {
927 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
932 static int objectclass_do_mod(struct oc_context
*ac
)
934 struct ldb_context
*ldb
;
935 const struct dsdb_schema
*schema
;
936 struct ldb_request
*mod_req
;
938 struct ldb_message_element
*objectclass_element
;
939 struct ldb_message
*msg
;
941 struct class_list
*sorted
, *current
;
944 ldb
= ldb_module_get_ctx(ac
->module
);
946 if (ac
->search_res
== NULL
) {
947 return LDB_ERR_OPERATIONS_ERROR
;
949 schema
= dsdb_get_schema(ldb
);
951 mem_ctx
= talloc_new(ac
);
952 if (mem_ctx
== NULL
) {
953 return LDB_ERR_OPERATIONS_ERROR
;
956 /* use a new message structure */
957 msg
= ldb_msg_new(ac
);
959 ldb_set_errstring(ldb
,
960 "objectclass: could not create new modify msg");
961 talloc_free(mem_ctx
);
962 return LDB_ERR_OPERATIONS_ERROR
;
965 /* This is now the objectClass list from the database */
966 objectclass_element
= ldb_msg_find_element(ac
->search_res
->message
,
968 if (!objectclass_element
) {
969 /* Where did it go? bail now... */
970 talloc_free(mem_ctx
);
971 return LDB_ERR_OPERATIONS_ERROR
;
975 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
977 ret
= objectclass_sort(ac
->module
, schema
, mem_ctx
, objectclass_element
, &sorted
);
978 if (ret
!= LDB_SUCCESS
) {
982 /* We must completely replace the existing objectClass entry.
983 * We could do a constrained add/del, but we are meant to be
984 * in a transaction... */
986 ret
= ldb_msg_add_empty(msg
, "objectClass", LDB_FLAG_MOD_REPLACE
, NULL
);
987 if (ret
!= LDB_SUCCESS
) {
988 ldb_set_errstring(ldb
, "objectclass: could not clear objectclass in modify msg");
989 talloc_free(mem_ctx
);
993 /* Move from the linked list back into an ldb msg */
994 for (current
= sorted
; current
; current
= current
->next
) {
995 value
= talloc_strdup(msg
, current
->objectclass
->lDAPDisplayName
);
998 return LDB_ERR_OPERATIONS_ERROR
;
1000 ret
= ldb_msg_add_string(msg
, "objectClass", value
);
1001 if (ret
!= LDB_SUCCESS
) {
1002 ldb_set_errstring(ldb
, "objectclass: could not re-add sorted objectclass to modify msg");
1003 talloc_free(mem_ctx
);
1008 ret
= ldb_msg_sanity_check(ldb
, msg
);
1009 if (ret
!= LDB_SUCCESS
) {
1010 talloc_free(mem_ctx
);
1014 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
1019 if (ret
!= LDB_SUCCESS
) {
1020 talloc_free(mem_ctx
);
1024 talloc_free(mem_ctx
);
1025 /* perform the modify */
1026 return ldb_next_request(ac
->module
, mod_req
);
1029 static int objectclass_do_rename(struct oc_context
*ac
);
1031 static int objectclass_rename(struct ldb_module
*module
, struct ldb_request
*req
)
1033 static const char * const attrs
[] = { NULL
};
1034 struct ldb_context
*ldb
;
1035 struct ldb_request
*search_req
;
1036 struct oc_context
*ac
;
1037 struct ldb_dn
*parent_dn
;
1040 ldb
= ldb_module_get_ctx(module
);
1042 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_rename\n");
1044 if (ldb_dn_is_special(req
->op
.rename
.newdn
)) { /* do not manipulate our control entries */
1045 return ldb_next_request(module
, req
);
1048 /* Firstly ensure we are not trying to rename it to be a child of itself */
1049 if ((ldb_dn_compare_base(req
->op
.rename
.olddn
, req
->op
.rename
.newdn
) == 0)
1050 && (ldb_dn_compare(req
->op
.rename
.olddn
, req
->op
.rename
.newdn
) != 0)) {
1051 ldb_asprintf_errstring(ldb
, "Cannot rename %s to be a child of itself",
1052 ldb_dn_get_linearized(req
->op
.rename
.olddn
));
1053 return LDB_ERR_UNWILLING_TO_PERFORM
;
1056 ac
= oc_init_context(module
, req
);
1058 return LDB_ERR_OPERATIONS_ERROR
;
1061 parent_dn
= ldb_dn_get_parent(ac
, req
->op
.rename
.newdn
);
1062 if (parent_dn
== NULL
) {
1064 return LDB_ERR_OPERATIONS_ERROR
;
1068 it makes a search request, looking for the parent DN to fix up the new DN
1069 to a standard one, at objectclass_do_rename()
1071 ret
= ldb_build_search_req(&search_req
, ldb
,
1072 ac
, parent_dn
, LDB_SCOPE_BASE
,
1075 ac
, get_search_callback
,
1077 if (ret
!= LDB_SUCCESS
) {
1081 /* we have to add the show deleted control, as otherwise DRS
1082 deletes will be refused as we will think the target parent
1084 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_DELETED_OID
, false, NULL
);
1086 if (ret
!= LDB_SUCCESS
) {
1090 ac
->step_fn
= objectclass_do_rename
;
1092 return ldb_next_request(ac
->module
, search_req
);
1097 static int objectclass_do_rename(struct oc_context
*ac
)
1099 struct ldb_context
*ldb
;
1100 struct ldb_request
*rename_req
;
1101 struct ldb_dn
*fixed_dn
;
1104 ldb
= ldb_module_get_ctx(ac
->module
);
1106 /* Check we have a valid parent */
1107 if (ac
->search_res
== NULL
) {
1108 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s, parent does not exist!",
1109 ldb_dn_get_linearized(ac
->req
->op
.rename
.newdn
));
1110 return LDB_ERR_UNWILLING_TO_PERFORM
;
1113 /* Fix up the DN to be in the standard form,
1114 * taking particular care to match the parent DN */
1116 ac
->req
->op
.rename
.newdn
,
1117 ac
->search_res
->message
->dn
,
1119 if (ret
!= LDB_SUCCESS
) {
1123 /* TODO: Check this is a valid child to this parent,
1124 * by reading the allowedChildClasses and
1125 * allowedChildClasssesEffective attributes */
1127 ret
= ldb_build_rename_req(&rename_req
, ldb
, ac
,
1128 ac
->req
->op
.rename
.olddn
, fixed_dn
,
1132 if (ret
!= LDB_SUCCESS
) {
1136 /* perform the rename */
1137 return ldb_next_request(ac
->module
, rename_req
);
1140 static int objectclass_init(struct ldb_module
*module
)
1142 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
1144 /* Init everything else */
1145 ret
= ldb_next_init(module
);
1146 if (ret
!= LDB_SUCCESS
) {
1150 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1151 ldb_module_set_private(module
, ldb_get_opaque(ldb
, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME
));
1153 return ldb_next_init(module
);
1156 _PUBLIC_
const struct ldb_module_ops ldb_objectclass_module_ops
= {
1157 .name
= "objectclass",
1158 .add
= objectclass_add
,
1159 .modify
= objectclass_modify
,
1160 .rename
= objectclass_rename
,
1161 .init_context
= objectclass_init