Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Simo Sorce 2006-2008
5 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 : Copyright (C) Matthias Dieter Wallnöfer 2010-2011
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : /*
23 : * Name: ldb
24 : *
25 : * Component: objectClass sorting and constraint checking module
26 : *
27 : * Description:
28 : * - sort the objectClass attribute into the class
29 : * hierarchy and perform constraint checks (correct RDN name,
30 : * valid parent),
31 : * - fix DNs into 'standard' case
32 : * - Add objectCategory and some other attribute defaults
33 : *
34 : * Author: Andrew Bartlett
35 : */
36 :
37 :
38 : #include "includes.h"
39 : #include "ldb_module.h"
40 : #include "dsdb/samdb/samdb.h"
41 : #include "librpc/ndr/libndr.h"
42 : #include "librpc/gen_ndr/ndr_security.h"
43 : #include "libcli/security/security.h"
44 : #include "auth/auth.h"
45 : #include "param/param.h"
46 : #include "../libds/common/flags.h"
47 : #include "dsdb/samdb/ldb_modules/util.h"
48 :
49 : #undef strcasecmp
50 :
51 : struct oc_context {
52 :
53 : struct ldb_module *module;
54 : struct ldb_request *req;
55 : const struct dsdb_schema *schema;
56 :
57 : struct ldb_reply *search_res;
58 : struct ldb_reply *search_res2;
59 :
60 : int (*step_fn)(struct oc_context *);
61 : };
62 :
63 846128 : static struct oc_context *oc_init_context(struct ldb_module *module,
64 : struct ldb_request *req)
65 : {
66 : struct ldb_context *ldb;
67 : struct oc_context *ac;
68 :
69 846128 : ldb = ldb_module_get_ctx(module);
70 :
71 846128 : ac = talloc_zero(req, struct oc_context);
72 846128 : if (ac == NULL) {
73 0 : ldb_oom(ldb);
74 0 : return NULL;
75 : }
76 :
77 846128 : ac->module = module;
78 846128 : ac->req = req;
79 846128 : ac->schema = dsdb_get_schema(ldb, ac);
80 :
81 846128 : return ac;
82 : }
83 :
84 : static int objectclass_do_add(struct oc_context *ac);
85 :
86 : /*
87 : * This checks if we have unrelated object classes in our entry's "objectClass"
88 : * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
89 : * or two or more disjunct structural ones.
90 : * If one of these conditions are true, blame.
91 : */
92 489933 : static int check_unrelated_objectclasses(struct ldb_module *module,
93 : const struct dsdb_schema *schema,
94 : const struct dsdb_class *struct_objectclass,
95 : struct ldb_message_element *objectclass_element)
96 : {
97 489933 : struct ldb_context *ldb = ldb_module_get_ctx(module);
98 : unsigned int i;
99 : bool found;
100 :
101 489933 : if (schema == NULL) {
102 0 : return LDB_SUCCESS;
103 : }
104 :
105 1440877 : for (i = 0; i < objectclass_element->num_values; i++) {
106 1027523 : const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
107 1027523 : &objectclass_element->values[i]);
108 1027523 : const struct dsdb_class *tmp_class2 = struct_objectclass;
109 :
110 : /* Pointer comparison can be used due to the same schema str. */
111 1181981 : if (tmp_class == NULL ||
112 692053 : tmp_class == struct_objectclass ||
113 953454 : tmp_class->objectClassCategory > 2 ||
114 537484 : ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
115 979972 : continue;
116 : }
117 :
118 46247 : found = false;
119 206773 : while (!found &&
120 71805 : ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
121 71800 : tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
122 18457 : tmp_class2->subClassOf);
123 71800 : if (tmp_class2 == tmp_class) {
124 47546 : found = true;
125 : }
126 : }
127 47551 : if (found) {
128 47546 : continue;
129 : }
130 :
131 5 : ldb_asprintf_errstring(ldb,
132 : "objectclass: the objectclass '%s' seems to be unrelated to %s!",
133 0 : tmp_class->lDAPDisplayName,
134 0 : struct_objectclass->lDAPDisplayName);
135 5 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
136 : }
137 :
138 413354 : return LDB_SUCCESS;
139 : }
140 :
141 1113424 : static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
142 : {
143 : struct ldb_context *ldb;
144 : struct oc_context *ac;
145 : int ret;
146 :
147 1113424 : ac = talloc_get_type(req->context, struct oc_context);
148 1113424 : ldb = ldb_module_get_ctx(ac->module);
149 :
150 1113424 : if (!ares) {
151 0 : return ldb_module_done(ac->req, NULL, NULL,
152 : LDB_ERR_OPERATIONS_ERROR);
153 : }
154 1127372 : if (ares->error != LDB_SUCCESS &&
155 23572 : ares->error != LDB_ERR_NO_SUCH_OBJECT) {
156 2 : return ldb_module_done(ac->req, ares->controls,
157 : ares->response, ares->error);
158 : }
159 :
160 1113422 : ldb_reset_err_string(ldb);
161 :
162 1113422 : switch (ares->type) {
163 544910 : case LDB_REPLY_ENTRY:
164 544910 : if (ac->search_res != NULL) {
165 0 : ldb_set_errstring(ldb, "Too many results");
166 0 : talloc_free(ares);
167 0 : return ldb_module_done(ac->req, NULL, NULL,
168 : LDB_ERR_OPERATIONS_ERROR);
169 : }
170 :
171 544910 : ac->search_res = talloc_steal(ac, ares);
172 544910 : break;
173 :
174 0 : case LDB_REPLY_REFERRAL:
175 : /* ignore */
176 0 : talloc_free(ares);
177 0 : break;
178 :
179 568512 : case LDB_REPLY_DONE:
180 568512 : talloc_free(ares);
181 568512 : ret = ac->step_fn(ac);
182 568512 : if (ret != LDB_SUCCESS) {
183 24107 : return ldb_module_done(ac->req, NULL, NULL, ret);
184 : }
185 467683 : break;
186 : }
187 :
188 935891 : return LDB_SUCCESS;
189 : }
190 :
191 : /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
192 :
193 : This should mean that if the parent is:
194 : CN=Users,DC=samba,DC=example,DC=com
195 : and a proposed child is
196 : cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
197 :
198 : The resulting DN should be:
199 :
200 : CN=Admins,CN=Users,DC=samba,DC=example,DC=com
201 :
202 : */
203 490488 : static int fix_dn(struct ldb_context *ldb,
204 : TALLOC_CTX *mem_ctx,
205 : struct ldb_dn *newdn, struct ldb_dn *parent_dn,
206 : struct ldb_dn **fixed_dn)
207 : {
208 : char *upper_rdn_attr;
209 : const struct ldb_val *rdn_val;
210 :
211 : /* Fix up the DN to be in the standard form, taking particular care to
212 : * match the parent DN */
213 490488 : *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
214 490488 : if (*fixed_dn == NULL) {
215 0 : return ldb_oom(ldb);
216 : }
217 :
218 : /* We need the attribute name in upper case */
219 490488 : upper_rdn_attr = strupper_talloc(*fixed_dn,
220 : ldb_dn_get_rdn_name(newdn));
221 490488 : if (upper_rdn_attr == NULL) {
222 0 : return ldb_oom(ldb);
223 : }
224 :
225 : /* Create a new child */
226 490488 : if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
227 0 : return ldb_operr(ldb);
228 : }
229 :
230 490488 : rdn_val = ldb_dn_get_rdn_val(newdn);
231 490488 : if (rdn_val == NULL) {
232 0 : return ldb_operr(ldb);
233 : }
234 :
235 : #if 0
236 : /* the rules for rDN length constraints are more complex than
237 : this. Until we understand them we need to leave this
238 : constraint out. Otherwise we break replication, as windows
239 : does sometimes send us rDNs longer than 64 */
240 : if (!rdn_val || rdn_val->length > 64) {
241 : DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
242 : }
243 : #endif
244 :
245 :
246 : /* And replace it with CN=foo (we need the attribute in upper case) */
247 490488 : return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
248 : }
249 :
250 :
251 490202 : static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
252 : {
253 : struct ldb_context *ldb;
254 : struct ldb_request *search_req;
255 : struct oc_context *ac;
256 : struct ldb_dn *parent_dn;
257 : const struct ldb_val *val;
258 : int ret;
259 : static const char * const parent_attrs[] = { "objectClass", NULL };
260 :
261 490202 : ldb = ldb_module_get_ctx(module);
262 :
263 490202 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
264 :
265 : /* do not manipulate our control entries */
266 490202 : if (ldb_dn_is_special(req->op.add.message->dn)) {
267 508 : return ldb_next_request(module, req);
268 : }
269 :
270 : /* An add operation on the basedn without "NC-add" operation isn't
271 : * allowed. */
272 489694 : if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
273 : unsigned int instanceType;
274 :
275 122 : instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
276 : "instanceType", 0);
277 122 : if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
278 : char *referral_uri;
279 : /* When we are trying to readd the root basedn then
280 : * this is denied, but with an interesting mechanism:
281 : * there is generated a referral with the last
282 : * component value as hostname. */
283 1 : val = ldb_dn_get_component_val(req->op.add.message->dn,
284 1 : ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
285 1 : if (val == NULL) {
286 0 : return ldb_operr(ldb);
287 : }
288 1 : referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
289 1 : ldb_dn_get_linearized(req->op.add.message->dn));
290 1 : if (referral_uri == NULL) {
291 0 : return ldb_module_oom(module);
292 : }
293 :
294 1 : return ldb_module_send_referral(req, referral_uri);
295 : }
296 : }
297 :
298 489693 : ac = oc_init_context(module, req);
299 489693 : if (ac == NULL) {
300 0 : return ldb_operr(ldb);
301 : }
302 :
303 : /* If there isn't a parent, just go on to the add processing */
304 489693 : if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
305 9 : return objectclass_do_add(ac);
306 : }
307 :
308 : /* get copy of parent DN */
309 489684 : parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
310 489684 : if (parent_dn == NULL) {
311 0 : return ldb_operr(ldb);
312 : }
313 :
314 489684 : ret = ldb_build_search_req(&search_req, ldb,
315 : ac, parent_dn, LDB_SCOPE_BASE,
316 : "(objectClass=*)", parent_attrs,
317 : NULL,
318 : ac, get_search_callback,
319 : req);
320 489684 : LDB_REQ_SET_LOCATION(search_req);
321 489684 : if (ret != LDB_SUCCESS) {
322 0 : return ret;
323 : }
324 :
325 489684 : ret = dsdb_request_add_controls(search_req,
326 : DSDB_FLAG_AS_SYSTEM |
327 : DSDB_SEARCH_SHOW_RECYCLED);
328 489684 : if (ret != LDB_SUCCESS) {
329 0 : return ret;
330 : }
331 :
332 489684 : ac->step_fn = objectclass_do_add;
333 :
334 489684 : return ldb_next_request(ac->module, search_req);
335 : }
336 :
337 :
338 : /*
339 : check if this is a special RODC nTDSDSA add
340 : */
341 42 : static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
342 : const struct dsdb_class *objectclass)
343 : {
344 : struct ldb_control *rodc_control;
345 :
346 42 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
347 1 : return false;
348 : }
349 41 : rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
350 41 : if (!rodc_control) {
351 0 : return false;
352 : }
353 :
354 41 : rodc_control->critical = false;
355 41 : return true;
356 : }
357 :
358 489693 : static int objectclass_do_add(struct oc_context *ac)
359 : {
360 489693 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
361 : struct ldb_request *add_req;
362 : struct ldb_message_element *objectclass_element, *el;
363 : struct ldb_message *msg;
364 489693 : const char *rdn_name = NULL;
365 : char *value;
366 : const struct dsdb_class *objectclass;
367 : struct ldb_dn *objectcategory;
368 489693 : int32_t systemFlags = 0;
369 : unsigned int i, j;
370 : bool found;
371 : int ret;
372 :
373 489693 : msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
374 489693 : if (msg == NULL) {
375 0 : return ldb_module_oom(ac->module);
376 : }
377 :
378 : /* Check if we have a valid parent - this check is needed since
379 : * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
380 489693 : if (ac->search_res == NULL) {
381 : unsigned int instanceType;
382 :
383 : /* An add operation on partition DNs without "NC-add" operation
384 : * isn't allowed. */
385 122 : instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
386 : 0);
387 122 : if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
388 1 : ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
389 : ldb_dn_get_linearized(msg->dn));
390 1 : return LDB_ERR_NO_SUCH_OBJECT;
391 : }
392 :
393 : /* Don't keep any error messages - we've to add a partition */
394 121 : ldb_set_errstring(ldb, NULL);
395 : } else {
396 : /* Fix up the DN to be in the standard form, taking
397 : * particular care to match the parent DN */
398 1249863 : ret = fix_dn(ldb, msg,
399 489571 : ac->req->op.add.message->dn,
400 489571 : ac->search_res->message->dn,
401 : &msg->dn);
402 489571 : if (ret != LDB_SUCCESS) {
403 0 : ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
404 0 : ldb_dn_get_linearized(ac->req->op.add.message->dn));
405 0 : return ret;
406 : }
407 : }
408 :
409 489692 : if (ac->schema != NULL) {
410 489692 : unsigned int linkID = 0;
411 : /*
412 : * Notice: by the normalization function call in "ldb_request()"
413 : * case "LDB_ADD" we have always only *one* "objectClass"
414 : * attribute at this stage!
415 : */
416 :
417 489692 : objectclass_element = ldb_msg_find_element(msg, "objectClass");
418 489692 : if (!objectclass_element) {
419 1 : ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
420 : ldb_dn_get_linearized(msg->dn));
421 1 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
422 : }
423 489691 : if (objectclass_element->num_values == 0) {
424 1 : ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
425 : ldb_dn_get_linearized(msg->dn));
426 1 : return LDB_ERR_CONSTRAINT_VIOLATION;
427 : }
428 :
429 : /* Now do the sorting */
430 489690 : ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
431 : objectclass_element, msg,
432 : objectclass_element);
433 489690 : if (ret != LDB_SUCCESS) {
434 1 : return ret;
435 : }
436 :
437 : /*
438 : * Get the new top-most structural object class and check for
439 : * unrelated structural classes
440 : */
441 489689 : objectclass = dsdb_get_last_structural_class(ac->schema,
442 : objectclass_element);
443 489689 : if (objectclass == NULL) {
444 1 : ldb_asprintf_errstring(ldb,
445 : "Failed to find a structural class for %s",
446 : ldb_dn_get_linearized(msg->dn));
447 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
448 : }
449 :
450 489688 : ret = check_unrelated_objectclasses(ac->module, ac->schema,
451 : objectclass,
452 : objectclass_element);
453 489688 : if (ret != LDB_SUCCESS) {
454 2 : return ret;
455 : }
456 :
457 489686 : rdn_name = ldb_dn_get_rdn_name(msg->dn);
458 489686 : if (rdn_name == NULL) {
459 0 : return ldb_operr(ldb);
460 : }
461 413118 : found = false;
462 1320029 : for (i = 0; (!found) && (i < objectclass_element->num_values);
463 526677 : i++) {
464 409265 : const struct dsdb_class *tmp_class =
465 526677 : dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
466 526677 : &objectclass_element->values[i]);
467 :
468 526677 : if (tmp_class == NULL) continue;
469 :
470 526677 : if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
471 489685 : found = true;
472 : }
473 489686 : if (!found) {
474 1 : ldb_asprintf_errstring(ldb,
475 : "objectclass: Invalid RDN '%s' for objectclass '%s'!",
476 0 : rdn_name, objectclass->lDAPDisplayName);
477 1 : return LDB_ERR_NAMING_VIOLATION;
478 : }
479 :
480 491204 : if (objectclass->systemOnly &&
481 1549 : !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
482 42 : !check_rodc_ntdsdsa_add(ac, objectclass)) {
483 1 : ldb_asprintf_errstring(ldb,
484 : "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
485 0 : objectclass->lDAPDisplayName,
486 : ldb_dn_get_linearized(msg->dn));
487 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
488 : }
489 :
490 489684 : if (ac->search_res && ac->search_res->message) {
491 380138 : struct ldb_message_element *oc_el
492 413016 : = ldb_msg_find_element(ac->search_res->message, "objectClass");
493 :
494 489563 : bool allowed_class = false;
495 1475270 : for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
496 : const struct dsdb_class *sclass;
497 :
498 985707 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
499 985707 : &oc_el->values[i]);
500 985707 : if (!sclass) {
501 : /* We don't know this class? what is going on? */
502 0 : continue;
503 : }
504 9002792 : for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
505 8660214 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
506 413013 : allowed_class = true;
507 413013 : break;
508 : }
509 : }
510 : }
511 :
512 489563 : if (!allowed_class) {
513 3 : ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
514 3 : objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
515 3 : return LDB_ERR_NAMING_VIOLATION;
516 : }
517 : }
518 :
519 489681 : objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
520 : "objectCategory");
521 489681 : if (objectcategory == NULL) {
522 379946 : struct dsdb_extended_dn_store_format *dn_format =
523 489234 : talloc_get_type(ldb_module_get_private(ac->module),
524 : struct dsdb_extended_dn_store_format);
525 489234 : if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
526 : /* Strip off extended components */
527 0 : struct ldb_dn *dn = ldb_dn_new(ac, ldb,
528 0 : objectclass->defaultObjectCategory);
529 0 : value = ldb_dn_alloc_linearized(msg, dn);
530 0 : talloc_free(dn);
531 : } else {
532 489234 : value = talloc_strdup(msg,
533 109288 : objectclass->defaultObjectCategory);
534 : }
535 489234 : if (value == NULL) {
536 0 : return ldb_module_oom(ac->module);
537 : }
538 :
539 489234 : ret = ldb_msg_add_string(msg, "objectCategory", value);
540 489234 : if (ret != LDB_SUCCESS) {
541 0 : return ret;
542 : }
543 : } else {
544 283 : const struct dsdb_class *ocClass =
545 447 : dsdb_class_by_cn_ldb_val(ac->schema,
546 : ldb_dn_get_rdn_val(objectcategory));
547 447 : if (ocClass != NULL) {
548 446 : struct ldb_dn *dn = ldb_dn_new(ac, ldb,
549 164 : ocClass->defaultObjectCategory);
550 446 : if (ldb_dn_compare(objectcategory, dn) != 0) {
551 0 : ocClass = NULL;
552 : }
553 : }
554 447 : talloc_free(objectcategory);
555 447 : if (ocClass == NULL) {
556 1 : ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
557 : ldb_dn_get_linearized(msg->dn));
558 1 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
559 : }
560 : }
561 :
562 489680 : if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
563 235374 : ldb_msg_add_string(msg, "showInAdvancedViewOnly",
564 : "TRUE");
565 : }
566 :
567 : /* There are very special rules for systemFlags, see MS-ADTS
568 : * MS-ADTS 3.1.1.5.2.4 */
569 :
570 489680 : el = ldb_msg_find_element(msg, "systemFlags");
571 489680 : if ((el != NULL) && (el->num_values > 1)) {
572 1 : ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
573 : ldb_dn_get_linearized(msg->dn));
574 1 : return LDB_ERR_CONSTRAINT_VIOLATION;
575 : }
576 :
577 489679 : systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
578 :
579 489679 : ldb_msg_remove_attr(msg, "systemFlags");
580 :
581 : /* Only the following flags may be set by a client */
582 489679 : if (ldb_request_get_control(ac->req,
583 : LDB_CONTROL_RELAX_OID) == NULL) {
584 232362 : systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
585 : | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
586 : | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
587 : | SYSTEM_FLAG_ATTR_IS_RDN );
588 : }
589 :
590 : /* But the last one ("ATTR_IS_RDN") is only allowed on
591 : * "attributeSchema" objects. So truncate if it does not fit. */
592 489679 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
593 315245 : systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
594 : }
595 :
596 489679 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
597 553 : systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
598 489126 : } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
599 488938 : || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
600 488750 : || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
601 639 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
602 188 : systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
603 639 : systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
604 488487 : } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
605 488348 : || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
606 488141 : || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
607 488141 : || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
608 404 : systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
609 : }
610 : /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
611 :
612 489679 : linkID = ldb_msg_find_attr_as_int(msg, "linkID", 0);
613 489679 : if (linkID > 0 && linkID % 2 == 1) {
614 6179 : systemFlags |= DS_FLAG_ATTR_NOT_REPLICATED;
615 : }
616 :
617 489679 : if (el || systemFlags != 0) {
618 195282 : ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
619 : systemFlags);
620 195282 : if (ret != LDB_SUCCESS) {
621 0 : return ret;
622 : }
623 : }
624 :
625 : /* make sure that "isCriticalSystemObject" is not specified! */
626 489679 : el = ldb_msg_find_element(msg, "isCriticalSystemObject");
627 501928 : if ((el != NULL) &&
628 12249 : !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
629 1 : ldb_set_errstring(ldb,
630 : "objectclass: 'isCriticalSystemObject' must not be specified!");
631 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
632 : }
633 : }
634 :
635 793336 : ret = ldb_build_add_req(&add_req, ldb, ac,
636 : msg,
637 413110 : ac->req->controls,
638 413110 : ac->req, dsdb_next_callback,
639 : ac->req);
640 489678 : LDB_REQ_SET_LOCATION(add_req);
641 489678 : if (ret != LDB_SUCCESS) {
642 0 : return ret;
643 : }
644 :
645 : /* perform the add */
646 489678 : return ldb_next_request(ac->module, add_req);
647 : }
648 :
649 : static int oc_modify_callback(struct ldb_request *req,
650 : struct ldb_reply *ares);
651 : static int objectclass_do_mod(struct oc_context *ac);
652 :
653 279487 : static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
654 : {
655 279487 : struct ldb_context *ldb = ldb_module_get_ctx(module);
656 : struct ldb_message_element *objectclass_element;
657 : struct ldb_message *msg;
658 : struct ldb_request *down_req;
659 : struct oc_context *ac;
660 279487 : bool oc_changes = false;
661 : int ret;
662 :
663 279487 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
664 :
665 : /* do not manipulate our control entries */
666 279487 : if (ldb_dn_is_special(req->op.mod.message->dn)) {
667 657 : return ldb_next_request(module, req);
668 : }
669 :
670 : /* As with the "real" AD we don't accept empty messages */
671 278830 : if (req->op.mod.message->num_elements == 0) {
672 2 : ldb_set_errstring(ldb, "objectclass: modify message must have "
673 : "elements/attributes!");
674 2 : return LDB_ERR_UNWILLING_TO_PERFORM;
675 : }
676 :
677 278828 : ac = oc_init_context(module, req);
678 278828 : if (ac == NULL) {
679 0 : return ldb_operr(ldb);
680 : }
681 :
682 : /* Without schema, there isn't much to do here */
683 278828 : if (ac->schema == NULL) {
684 0 : talloc_free(ac);
685 0 : return ldb_next_request(module, req);
686 : }
687 :
688 278828 : msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
689 278828 : if (msg == NULL) {
690 0 : return ldb_module_oom(ac->module);
691 : }
692 :
693 : /* For now change everything except the objectclasses */
694 :
695 278828 : objectclass_element = ldb_msg_find_element(msg, "objectClass");
696 278828 : if (objectclass_element != NULL) {
697 345 : ldb_msg_remove_attr(msg, "objectClass");
698 345 : oc_changes = true;
699 : }
700 :
701 : /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
702 : * only on application NCs - not on the default ones */
703 263101 : if (oc_changes &&
704 345 : (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
705 : struct ldb_dn *nc_root;
706 :
707 0 : ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
708 : &nc_root);
709 0 : if (ret != LDB_SUCCESS) {
710 0 : return ret;
711 : }
712 :
713 0 : if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
714 0 : (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
715 0 : (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
716 0 : ldb_set_errstring(ldb,
717 : "objectclass: object class changes on objects under the standard name contexts not allowed!");
718 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
719 : }
720 :
721 0 : talloc_free(nc_root);
722 : }
723 :
724 278828 : if (oc_changes) {
725 345 : ret = ldb_build_mod_req(&down_req, ldb, ac,
726 : msg,
727 : req->controls, ac,
728 : oc_modify_callback,
729 : req);
730 : } else {
731 278483 : ret = ldb_build_mod_req(&down_req, ldb, ac,
732 : msg,
733 : req->controls, req,
734 : dsdb_next_callback,
735 : req);
736 : }
737 278828 : LDB_REQ_SET_LOCATION(down_req);
738 278828 : if (ret != LDB_SUCCESS) {
739 0 : return ret;
740 : }
741 :
742 278828 : return ldb_next_request(module, down_req);
743 : }
744 :
745 345 : static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
746 : {
747 : static const char * const attrs[] = { "objectClass", NULL };
748 : struct ldb_context *ldb;
749 : struct ldb_request *search_req;
750 : struct oc_context *ac;
751 : int ret;
752 :
753 345 : ac = talloc_get_type(req->context, struct oc_context);
754 345 : ldb = ldb_module_get_ctx(ac->module);
755 :
756 345 : if (!ares) {
757 0 : return ldb_module_done(ac->req, NULL, NULL,
758 : LDB_ERR_OPERATIONS_ERROR);
759 : }
760 :
761 345 : if (ares->type == LDB_REPLY_REFERRAL) {
762 0 : return ldb_module_send_referral(ac->req, ares->referral);
763 : }
764 :
765 345 : if (ares->error != LDB_SUCCESS) {
766 48 : return ldb_module_done(ac->req, ares->controls,
767 : ares->response, ares->error);
768 : }
769 :
770 297 : if (ares->type != LDB_REPLY_DONE) {
771 0 : talloc_free(ares);
772 0 : return ldb_module_done(ac->req, NULL, NULL,
773 : LDB_ERR_OPERATIONS_ERROR);
774 : }
775 :
776 297 : talloc_free(ares);
777 :
778 : /* this looks up the real existing object for fetching some important
779 : * information (objectclasses) */
780 594 : ret = ldb_build_search_req(&search_req, ldb,
781 297 : ac, ac->req->op.mod.message->dn,
782 : LDB_SCOPE_BASE,
783 : "(objectClass=*)",
784 : attrs, NULL,
785 : ac, get_search_callback,
786 : ac->req);
787 297 : LDB_REQ_SET_LOCATION(search_req);
788 297 : if (ret != LDB_SUCCESS) {
789 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
790 : }
791 :
792 297 : ret = dsdb_request_add_controls(search_req,
793 : DSDB_FLAG_AS_SYSTEM |
794 : DSDB_SEARCH_SHOW_RECYCLED);
795 297 : if (ret != LDB_SUCCESS) {
796 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
797 : }
798 :
799 297 : ac->step_fn = objectclass_do_mod;
800 :
801 297 : ret = ldb_next_request(ac->module, search_req);
802 297 : if (ret != LDB_SUCCESS) {
803 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
804 : }
805 :
806 291 : return LDB_SUCCESS;
807 : }
808 :
809 297 : static int objectclass_do_mod(struct oc_context *ac)
810 : {
811 : struct ldb_context *ldb;
812 : struct ldb_request *mod_req;
813 : struct ldb_message_element *oc_el_entry, *oc_el_change;
814 : struct ldb_val *vals;
815 : struct ldb_message *msg;
816 : const struct dsdb_class *objectclass;
817 : unsigned int i, j, k;
818 : bool found;
819 : int ret;
820 :
821 297 : ldb = ldb_module_get_ctx(ac->module);
822 :
823 : /* we should always have a valid entry when we enter here */
824 297 : if (ac->search_res == NULL) {
825 0 : return ldb_operr(ldb);
826 : }
827 :
828 297 : oc_el_entry = ldb_msg_find_element(ac->search_res->message,
829 : "objectClass");
830 297 : if (oc_el_entry == NULL) {
831 : /* existing entry without a valid object class? */
832 0 : return ldb_operr(ldb);
833 : }
834 :
835 : /* use a new message structure */
836 297 : msg = ldb_msg_new(ac);
837 297 : if (msg == NULL) {
838 0 : return ldb_module_oom(ac->module);
839 : }
840 :
841 297 : msg->dn = ac->req->op.mod.message->dn;
842 :
843 : /* We've to walk over all "objectClass" message elements */
844 641 : for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
845 400 : if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
846 : "objectClass") != 0) {
847 102 : continue;
848 : }
849 :
850 298 : oc_el_change = &ac->req->op.mod.message->elements[k];
851 :
852 298 : switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
853 107 : case LDB_FLAG_MOD_ADD:
854 : /* Merge the two message elements */
855 171 : for (i = 0; i < oc_el_change->num_values; i++) {
856 491 : for (j = 0; j < oc_el_entry->num_values; j++) {
857 433 : if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
858 : (char *)oc_el_entry->values[j].data) == 0) {
859 49 : ldb_asprintf_errstring(ldb,
860 : "objectclass: cannot re-add an existing objectclass: '%.*s'!",
861 49 : (int)oc_el_change->values[i].length,
862 49 : (const char *)oc_el_change->values[i].data);
863 49 : return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
864 : }
865 : }
866 : /* append the new object class value - code was
867 : * copied from "ldb_msg_add_value" */
868 64 : vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
869 : struct ldb_val,
870 : oc_el_entry->num_values + 1);
871 64 : if (vals == NULL) {
872 0 : return ldb_module_oom(ac->module);
873 : }
874 64 : oc_el_entry->values = vals;
875 64 : oc_el_entry->values[oc_el_entry->num_values] =
876 64 : oc_el_change->values[i];
877 64 : ++(oc_el_entry->num_values);
878 : }
879 :
880 58 : break;
881 :
882 120 : case LDB_FLAG_MOD_REPLACE:
883 : /*
884 : * In this case the new "oc_el_entry" is simply
885 : * "oc_el_change"
886 : */
887 120 : oc_el_entry = oc_el_change;
888 :
889 120 : break;
890 :
891 65 : case LDB_FLAG_MOD_DELETE:
892 : /* Merge the two message elements */
893 129 : for (i = 0; i < oc_el_change->num_values; i++) {
894 65 : found = false;
895 141 : for (j = 0; j < oc_el_entry->num_values; j++) {
896 140 : if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
897 : (char *)oc_el_entry->values[j].data) == 0) {
898 64 : found = true;
899 : /* delete the object class value
900 : * - code was copied from
901 : * "ldb_msg_remove_element" */
902 64 : if (j != oc_el_entry->num_values - 1) {
903 116 : memmove(&oc_el_entry->values[j],
904 58 : &oc_el_entry->values[j+1],
905 58 : ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
906 : }
907 64 : --(oc_el_entry->num_values);
908 64 : break;
909 : }
910 : }
911 65 : if (!found) {
912 : /* we cannot delete a not existing
913 : * object class */
914 1 : ldb_asprintf_errstring(ldb,
915 : "objectclass: cannot delete this objectclass: '%.*s'!",
916 1 : (int)oc_el_change->values[i].length,
917 1 : (const char *)oc_el_change->values[i].data);
918 1 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
919 : }
920 : }
921 :
922 64 : break;
923 : }
924 :
925 : /* Now do the sorting */
926 248 : ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
927 : msg, oc_el_entry);
928 248 : if (ret != LDB_SUCCESS) {
929 1 : return ret;
930 : }
931 :
932 : /*
933 : * Get the new top-most structural object class and check for
934 : * unrelated structural classes
935 : */
936 247 : objectclass = dsdb_get_last_structural_class(ac->schema,
937 : oc_el_entry);
938 247 : if (objectclass == NULL) {
939 2 : ldb_set_errstring(ldb,
940 : "objectclass: cannot delete all structural objectclasses!");
941 2 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
942 : }
943 :
944 : /* Check for unrelated objectclasses */
945 245 : ret = check_unrelated_objectclasses(ac->module, ac->schema,
946 : objectclass,
947 : oc_el_entry);
948 245 : if (ret != LDB_SUCCESS) {
949 3 : return ret;
950 : }
951 : }
952 :
953 : /* Now add the new object class attribute to the change message */
954 241 : ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
955 241 : if (ret != LDB_SUCCESS) {
956 0 : ldb_module_oom(ac->module);
957 0 : return ret;
958 : }
959 :
960 : /* Now we have the real and definitive change left to do */
961 :
962 476 : ret = ldb_build_mod_req(&mod_req, ldb, ac,
963 : msg,
964 235 : ac->req->controls,
965 235 : ac->req, dsdb_next_callback,
966 : ac->req);
967 241 : LDB_REQ_SET_LOCATION(mod_req);
968 241 : if (ret != LDB_SUCCESS) {
969 0 : return ret;
970 : }
971 :
972 241 : return ldb_next_request(ac->module, mod_req);
973 : }
974 :
975 : static int objectclass_do_rename(struct oc_context *ac);
976 :
977 930 : static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
978 : {
979 : static const char * const attrs[] = { "objectClass", NULL };
980 : struct ldb_context *ldb;
981 : struct ldb_request *search_req;
982 : struct oc_context *ac;
983 : struct ldb_dn *parent_dn;
984 : int ret;
985 :
986 930 : ldb = ldb_module_get_ctx(module);
987 :
988 930 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
989 :
990 : /* do not manipulate our control entries */
991 930 : if (ldb_dn_is_special(req->op.rename.olddn)) {
992 0 : return ldb_next_request(module, req);
993 : }
994 :
995 : /*
996 : * Bypass the constraint checks when we do have the "DBCHECK" control
997 : * set, so we can force objects under the deleted objects container.
998 : */
999 930 : if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK) != NULL) {
1000 1 : return ldb_next_request(module, req);
1001 : }
1002 :
1003 929 : ac = oc_init_context(module, req);
1004 929 : if (ac == NULL) {
1005 0 : return ldb_operr(ldb);
1006 : }
1007 :
1008 929 : parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1009 929 : if (parent_dn == NULL) {
1010 0 : ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1011 : ldb_dn_get_linearized(req->op.rename.olddn));
1012 0 : return LDB_ERR_NO_SUCH_OBJECT;
1013 : }
1014 :
1015 : /* this looks up the parent object for fetching some important
1016 : * information (objectclasses, DN normalisation...) */
1017 929 : ret = ldb_build_search_req(&search_req, ldb,
1018 : ac, parent_dn, LDB_SCOPE_BASE,
1019 : "(objectClass=*)",
1020 : attrs, NULL,
1021 : ac, get_search_callback,
1022 : req);
1023 929 : LDB_REQ_SET_LOCATION(search_req);
1024 929 : if (ret != LDB_SUCCESS) {
1025 0 : return ret;
1026 : }
1027 :
1028 : /* we have to add the show recycled control, as otherwise DRS
1029 : deletes will be refused as we will think the target parent
1030 : does not exist */
1031 929 : ret = dsdb_request_add_controls(search_req,
1032 : DSDB_FLAG_AS_SYSTEM |
1033 : DSDB_SEARCH_SHOW_RECYCLED);
1034 929 : if (ret != LDB_SUCCESS) {
1035 0 : return ret;
1036 : }
1037 :
1038 929 : ac->step_fn = objectclass_do_rename;
1039 :
1040 929 : return ldb_next_request(ac->module, search_req);
1041 : }
1042 :
1043 : static int objectclass_do_rename2(struct oc_context *ac);
1044 :
1045 929 : static int objectclass_do_rename(struct oc_context *ac)
1046 : {
1047 : static const char * const attrs[] = { "objectClass", NULL };
1048 : struct ldb_context *ldb;
1049 : struct ldb_request *search_req;
1050 : int ret;
1051 :
1052 929 : ldb = ldb_module_get_ctx(ac->module);
1053 :
1054 : /* Check if we have a valid parent - this check is needed since
1055 : * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1056 929 : if (ac->search_res == NULL) {
1057 3 : ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1058 3 : ldb_dn_get_linearized(ac->req->op.rename.olddn));
1059 3 : return LDB_ERR_OTHER;
1060 : }
1061 :
1062 : /* now assign "search_res2" to the parent entry to have "search_res"
1063 : * free for another lookup */
1064 926 : ac->search_res2 = ac->search_res;
1065 926 : ac->search_res = NULL;
1066 :
1067 : /* this looks up the real existing object for fetching some important
1068 : * information (objectclasses) */
1069 1636 : ret = ldb_build_search_req(&search_req, ldb,
1070 921 : ac, ac->req->op.rename.olddn,
1071 : LDB_SCOPE_BASE,
1072 : "(objectClass=*)",
1073 : attrs, NULL,
1074 : ac, get_search_callback,
1075 : ac->req);
1076 926 : LDB_REQ_SET_LOCATION(search_req);
1077 926 : if (ret != LDB_SUCCESS) {
1078 0 : return ret;
1079 : }
1080 :
1081 926 : ret = dsdb_request_add_controls(search_req,
1082 : DSDB_FLAG_AS_SYSTEM |
1083 : DSDB_SEARCH_SHOW_RECYCLED);
1084 926 : if (ret != LDB_SUCCESS) {
1085 0 : return ret;
1086 : }
1087 :
1088 926 : ac->step_fn = objectclass_do_rename2;
1089 :
1090 926 : return ldb_next_request(ac->module, search_req);
1091 : }
1092 :
1093 925 : static int objectclass_do_rename2(struct oc_context *ac)
1094 : {
1095 : struct ldb_context *ldb;
1096 : struct ldb_request *rename_req;
1097 : struct ldb_dn *fixed_dn;
1098 : int ret;
1099 :
1100 925 : ldb = ldb_module_get_ctx(ac->module);
1101 :
1102 : /* Check if we have a valid entry - this check is needed since
1103 : * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1104 925 : if (ac->search_res == NULL) {
1105 2 : ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1106 2 : ldb_dn_get_linearized(ac->req->op.rename.olddn));
1107 2 : return LDB_ERR_NO_SUCH_OBJECT;
1108 : }
1109 :
1110 923 : if (ac->schema != NULL) {
1111 : struct ldb_message_element *oc_el_entry, *oc_el_parent;
1112 : const struct dsdb_class *objectclass;
1113 : const char *rdn_name;
1114 923 : bool allowed_class = false;
1115 : unsigned int i, j;
1116 : bool found;
1117 :
1118 923 : oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1119 : "objectClass");
1120 923 : if (oc_el_entry == NULL) {
1121 : /* existing entry without a valid object class? */
1122 0 : return ldb_operr(ldb);
1123 : }
1124 923 : objectclass = dsdb_get_last_structural_class(ac->schema,
1125 : oc_el_entry);
1126 923 : if (objectclass == NULL) {
1127 : /* existing entry without a valid object class? */
1128 0 : return ldb_operr(ldb);
1129 : }
1130 :
1131 923 : rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1132 923 : if (rdn_name == NULL) {
1133 0 : return ldb_operr(ldb);
1134 : }
1135 918 : found = false;
1136 1952 : for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1137 814 : const struct dsdb_class *tmp_class =
1138 1034 : dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1139 1034 : &oc_el_entry->values[i]);
1140 :
1141 1034 : if (tmp_class == NULL) continue;
1142 :
1143 1034 : if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1144 921 : found = true;
1145 : }
1146 923 : if (!found) {
1147 2 : ldb_asprintf_errstring(ldb,
1148 : "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1149 0 : rdn_name, objectclass->lDAPDisplayName);
1150 2 : return LDB_ERR_UNWILLING_TO_PERFORM;
1151 : }
1152 :
1153 921 : oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1154 : "objectClass");
1155 921 : if (oc_el_parent == NULL) {
1156 : /* existing entry without a valid object class? */
1157 0 : return ldb_operr(ldb);
1158 : }
1159 :
1160 2804 : for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1161 : const struct dsdb_class *sclass;
1162 :
1163 1888 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1164 1888 : &oc_el_parent->values[i]);
1165 1888 : if (!sclass) {
1166 : /* We don't know this class? what is going on? */
1167 0 : continue;
1168 : }
1169 85461 : for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1170 84502 : if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1171 914 : allowed_class = true;
1172 914 : break;
1173 : }
1174 : }
1175 : }
1176 :
1177 921 : if (!allowed_class) {
1178 2 : ldb_asprintf_errstring(ldb,
1179 : "objectclass: structural objectClass %s is not a valid child class for %s",
1180 2 : objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1181 2 : return LDB_ERR_NAMING_VIOLATION;
1182 : }
1183 : }
1184 :
1185 : /* Ensure we are not trying to rename it to be a child of itself */
1186 919 : if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1187 927 : ac->req->op.rename.newdn) == 0) &&
1188 8 : (ldb_dn_compare(ac->req->op.rename.olddn,
1189 8 : ac->req->op.rename.newdn) != 0)) {
1190 2 : ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1191 2 : ldb_dn_get_linearized(ac->req->op.rename.olddn));
1192 2 : return LDB_ERR_UNWILLING_TO_PERFORM;
1193 : }
1194 :
1195 : /* Fix up the DN to be in the standard form, taking
1196 : * particular care to match the parent DN */
1197 1623 : ret = fix_dn(ldb, ac,
1198 917 : ac->req->op.rename.newdn,
1199 917 : ac->search_res2->message->dn,
1200 : &fixed_dn);
1201 917 : if (ret != LDB_SUCCESS) {
1202 0 : ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1203 0 : ldb_dn_get_linearized(ac->req->op.rename.newdn));
1204 0 : return ret;
1205 :
1206 : }
1207 :
1208 2319 : ret = ldb_build_rename_req(&rename_req, ldb, ac,
1209 912 : ac->req->op.rename.olddn, fixed_dn,
1210 912 : ac->req->controls,
1211 912 : ac->req, dsdb_next_callback,
1212 : ac->req);
1213 917 : LDB_REQ_SET_LOCATION(rename_req);
1214 917 : if (ret != LDB_SUCCESS) {
1215 0 : return ret;
1216 : }
1217 :
1218 : /* perform the rename */
1219 917 : return ldb_next_request(ac->module, rename_req);
1220 : }
1221 :
1222 : static int objectclass_do_delete(struct oc_context *ac);
1223 :
1224 76702 : static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1225 : {
1226 : static const char * const attrs[] = { "nCName", "objectClass",
1227 : "systemFlags",
1228 : "isDeleted",
1229 : "isCriticalSystemObject", NULL };
1230 : struct ldb_context *ldb;
1231 : struct ldb_request *search_req;
1232 : struct oc_context *ac;
1233 : int ret;
1234 :
1235 76702 : ldb = ldb_module_get_ctx(module);
1236 :
1237 76702 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1238 :
1239 : /* do not manipulate our control entries */
1240 76702 : if (ldb_dn_is_special(req->op.del.dn)) {
1241 1 : return ldb_next_request(module, req);
1242 : }
1243 :
1244 : /* Bypass the constraint checks when we do have the "RELAX" control
1245 : * set. */
1246 76701 : if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1247 23 : return ldb_next_request(module, req);
1248 : }
1249 :
1250 76678 : ac = oc_init_context(module, req);
1251 76678 : if (ac == NULL) {
1252 0 : return ldb_operr(ldb);
1253 : }
1254 :
1255 : /* this looks up the entry object for fetching some important
1256 : * information (object classes, system flags...) */
1257 76678 : ret = ldb_build_search_req(&search_req, ldb,
1258 : ac, req->op.del.dn, LDB_SCOPE_BASE,
1259 : "(objectClass=*)",
1260 : attrs, NULL,
1261 : ac, get_search_callback,
1262 : req);
1263 76678 : LDB_REQ_SET_LOCATION(search_req);
1264 76678 : if (ret != LDB_SUCCESS) {
1265 0 : return ret;
1266 : }
1267 :
1268 76678 : ret = dsdb_request_add_controls(search_req,
1269 : DSDB_FLAG_AS_SYSTEM |
1270 : DSDB_SEARCH_SHOW_RECYCLED);
1271 76678 : if (ret != LDB_SUCCESS) {
1272 0 : return ret;
1273 : }
1274 :
1275 76678 : ac->step_fn = objectclass_do_delete;
1276 :
1277 76678 : return ldb_next_request(ac->module, search_req);
1278 : }
1279 :
1280 76677 : static int objectclass_do_delete(struct oc_context *ac)
1281 : {
1282 : struct ldb_context *ldb;
1283 : struct ldb_dn *dn;
1284 : int32_t systemFlags;
1285 : bool isCriticalSystemObject;
1286 : int ret;
1287 :
1288 76677 : ldb = ldb_module_get_ctx(ac->module);
1289 :
1290 : /* Check if we have a valid entry - this check is needed since
1291 : * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1292 76677 : if (ac->search_res == NULL) {
1293 23484 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1294 23484 : ldb_dn_get_linearized(ac->req->op.del.dn));
1295 23484 : return LDB_ERR_NO_SUCH_OBJECT;
1296 : }
1297 :
1298 : /* DC's ntDSDSA object */
1299 53193 : if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1300 2 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1301 2 : ldb_dn_get_linearized(ac->req->op.del.dn));
1302 2 : return LDB_ERR_UNWILLING_TO_PERFORM;
1303 : }
1304 :
1305 : /* DC's rIDSet object */
1306 : /* Perform this check only when it does exist - this is needed in order
1307 : * to don't let existing provisions break, and to delete . */
1308 53191 : ret = samdb_rid_set_dn(ldb, ac, &dn);
1309 53191 : if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_ATTRIBUTE)
1310 0 : && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1311 0 : ldb_asprintf_errstring(ldb, "objectclass: Unable to determine if %s, is this DC's rIDSet object: %s ",
1312 0 : ldb_dn_get_linearized(ac->req->op.del.dn),
1313 : ldb_errstring(ldb));
1314 0 : return ret;
1315 : }
1316 53191 : if (ret == LDB_SUCCESS) {
1317 53190 : if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1318 4 : talloc_free(dn);
1319 4 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1320 4 : ldb_dn_get_linearized(ac->req->op.del.dn));
1321 4 : return LDB_ERR_UNWILLING_TO_PERFORM;
1322 : }
1323 53186 : talloc_free(dn);
1324 : }
1325 :
1326 : /* Only trusted request from system account are allowed to delete
1327 : * deleted objects.
1328 : */
1329 53187 : if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1330 0 : (ldb_req_is_untrusted(ac->req) ||
1331 0 : !dsdb_module_am_system(ac->module))) {
1332 0 : ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1333 0 : ldb_dn_get_linearized(ac->req->op.del.dn));
1334 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1335 : }
1336 :
1337 : /* crossRef objects regarding config, schema and default domain NCs */
1338 53187 : if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1339 : "crossRef") != NULL) {
1340 12 : dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1341 : "nCName");
1342 20 : if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1343 8 : (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1344 8 : talloc_free(dn);
1345 :
1346 8 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1347 8 : ldb_dn_get_linearized(ac->req->op.del.dn));
1348 8 : return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1349 : }
1350 4 : if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1351 4 : talloc_free(dn);
1352 :
1353 4 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1354 4 : ldb_dn_get_linearized(ac->req->op.del.dn));
1355 4 : return LDB_ERR_UNWILLING_TO_PERFORM;
1356 : }
1357 0 : talloc_free(dn);
1358 : }
1359 :
1360 : /* systemFlags */
1361 :
1362 53175 : systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1363 : "systemFlags", 0);
1364 53175 : if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1365 5 : ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1366 5 : ldb_dn_get_linearized(ac->req->op.del.dn));
1367 5 : return LDB_ERR_UNWILLING_TO_PERFORM;
1368 : }
1369 :
1370 : /* isCriticalSystemObject - but this only applies on tree delete
1371 : * operations - MS-ADTS 3.1.1.5.5.7.2 */
1372 53170 : if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1373 26364 : isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1374 : "isCriticalSystemObject", false);
1375 26364 : if (isCriticalSystemObject) {
1376 : /*
1377 : * Following the explaination from Microsoft
1378 : * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1379 : * "I finished the investigation on this behavior.
1380 : * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1381 : * every object in the tree will be checked to see if it has isCriticalSystemObject
1382 : * set to TRUE, including the root node on which the delete operation is performed
1383 : * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1384 : * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1385 : * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1386 : * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1387 : */
1388 :
1389 484 : if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1390 484 : samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1391 484 : samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1392 242 : samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1393 0 : ldb_asprintf_errstring(ldb,
1394 : "objectclass: Cannot tree-delete %s, it's a critical system object!",
1395 0 : ldb_dn_get_linearized(ac->req->op.del.dn));
1396 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1397 : }
1398 : }
1399 : }
1400 :
1401 53170 : return ldb_next_request(ac->module, ac->req);
1402 : }
1403 :
1404 132453 : static int objectclass_init(struct ldb_module *module)
1405 : {
1406 132453 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1407 : int ret;
1408 :
1409 : /* Init everything else */
1410 132453 : ret = ldb_next_init(module);
1411 132453 : if (ret != LDB_SUCCESS) {
1412 0 : return ret;
1413 : }
1414 :
1415 : /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1416 132453 : ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1417 :
1418 132453 : ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1419 132453 : if (ret != LDB_SUCCESS) {
1420 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1421 : "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1422 0 : return ldb_operr(ldb);
1423 : }
1424 :
1425 127712 : return ret;
1426 : }
1427 :
1428 : static const struct ldb_module_ops ldb_objectclass_module_ops = {
1429 : .name = "objectclass",
1430 : .add = objectclass_add,
1431 : .modify = objectclass_modify,
1432 : .rename = objectclass_rename,
1433 : .del = objectclass_delete,
1434 : .init_context = objectclass_init
1435 : };
1436 :
1437 5536 : int ldb_objectclass_module_init(const char *version)
1438 : {
1439 5536 : LDB_MODULE_CHECK_VERSION(version);
1440 5536 : return ldb_register_module(&ldb_objectclass_module_ops);
1441 : }
|