s4:repl_meta_data: add support for DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID
[Samba.git] / source4 / dsdb / samdb / ldb_modules / samldb.c
blob81d8c96437c9754e933e9aeb8f4d2cb7e40ca163
1 /*
2 SAM ldb module
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2014
5 Copyright (C) Simo Sorce 2004-2008
6 Copyright (C) Matthias Dieter Wallnöfer 2009-2011
7 Copyright (C) Matthieu Patou 2012
8 Copyright (C) Catalyst.Net Ltd 2017
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Name: ldb
27 * Component: ldb samldb module
29 * Description: various internal DSDB triggers - most for SAM specific objects
31 * Author: Simo Sorce
34 #include "includes.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "ldb_module.h"
37 #include "auth/auth.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "dsdb/samdb/ldb_modules/util.h"
40 #include "dsdb/samdb/ldb_modules/ridalloc.h"
41 #include "libcli/security/security.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "ldb_wrap.h"
44 #include "param/param.h"
45 #include "libds/common/flag_mapping.h"
46 #include "system/network.h"
47 #include "librpc/gen_ndr/irpc.h"
49 struct samldb_ctx;
50 enum samldb_add_type {
51 SAMLDB_TYPE_USER,
52 SAMLDB_TYPE_GROUP,
53 SAMLDB_TYPE_CLASS,
54 SAMLDB_TYPE_ATTRIBUTE
57 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
59 struct samldb_step {
60 struct samldb_step *next;
61 samldb_step_fn_t fn;
64 struct samldb_ctx {
65 struct ldb_module *module;
66 struct ldb_request *req;
68 /* used for add operations */
69 enum samldb_add_type type;
71 /* the resulting message */
72 struct ldb_message *msg;
74 /* used in "samldb_find_for_defaultObjectCategory" */
75 struct ldb_dn *dn, *res_dn;
77 /* all the async steps necessary to complete the operation */
78 struct samldb_step *steps;
79 struct samldb_step *curstep;
81 /* If someone set an ares to forward controls and response back to the caller */
82 struct ldb_reply *ares;
85 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
86 struct ldb_request *req)
88 struct ldb_context *ldb;
89 struct samldb_ctx *ac;
91 ldb = ldb_module_get_ctx(module);
93 ac = talloc_zero(req, struct samldb_ctx);
94 if (ac == NULL) {
95 ldb_oom(ldb);
96 return NULL;
99 ac->module = module;
100 ac->req = req;
102 return ac;
105 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
107 struct samldb_step *step, *stepper;
109 step = talloc_zero(ac, struct samldb_step);
110 if (step == NULL) {
111 return ldb_oom(ldb_module_get_ctx(ac->module));
114 step->fn = fn;
116 if (ac->steps == NULL) {
117 ac->steps = step;
118 ac->curstep = step;
119 } else {
120 if (ac->curstep == NULL)
121 return ldb_operr(ldb_module_get_ctx(ac->module));
122 for (stepper = ac->curstep; stepper->next != NULL;
123 stepper = stepper->next);
124 stepper->next = step;
127 return LDB_SUCCESS;
130 static int samldb_first_step(struct samldb_ctx *ac)
132 if (ac->steps == NULL) {
133 return ldb_operr(ldb_module_get_ctx(ac->module));
136 ac->curstep = ac->steps;
137 return ac->curstep->fn(ac);
140 static int samldb_next_step(struct samldb_ctx *ac)
142 if (ac->curstep->next) {
143 ac->curstep = ac->curstep->next;
144 return ac->curstep->fn(ac);
147 /* We exit the samldb module here. If someone set an "ares" to forward
148 * controls and response back to the caller, use them. */
149 if (ac->ares) {
150 return ldb_module_done(ac->req, ac->ares->controls,
151 ac->ares->response, LDB_SUCCESS);
152 } else {
153 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
157 static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr,
158 const char *attr_conflict,
159 struct ldb_dn *base_dn)
161 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
162 const char * const no_attrs[] = { NULL };
163 struct ldb_result *res;
164 const char *enc_str;
165 struct ldb_message_element *el;
166 int ret;
168 el = dsdb_get_single_valued_attr(ac->msg, attr,
169 ac->req->operation);
170 if (el == NULL) {
171 /* we are not affected */
172 return LDB_SUCCESS;
175 if (el->num_values > 1) {
176 ldb_asprintf_errstring(ldb,
177 "samldb: %s has %u values, should be single-valued!",
178 attr, el->num_values);
179 return LDB_ERR_CONSTRAINT_VIOLATION;
180 } else if (el->num_values == 0) {
181 ldb_asprintf_errstring(ldb,
182 "samldb: new value for %s not provided for mandatory, single-valued attribute!",
183 attr);
184 return LDB_ERR_OBJECT_CLASS_VIOLATION;
186 if (el->values[0].length == 0) {
187 ldb_asprintf_errstring(ldb,
188 "samldb: %s is of zero length, should have a value!",
189 attr);
190 return LDB_ERR_OBJECT_CLASS_VIOLATION;
192 enc_str = ldb_binary_encode(ac, el->values[0]);
194 if (enc_str == NULL) {
195 return ldb_module_oom(ac->module);
198 /* Make sure that attr (eg) "sAMAccountName" is only used once */
200 if (attr_conflict != NULL) {
201 ret = dsdb_module_search(ac->module, ac, &res,
202 base_dn,
203 LDB_SCOPE_SUBTREE, no_attrs,
204 DSDB_FLAG_NEXT_MODULE, ac->req,
205 "(|(%s=%s)(%s=%s))",
206 attr, enc_str,
207 attr_conflict, enc_str);
208 } else {
209 ret = dsdb_module_search(ac->module, ac, &res,
210 base_dn,
211 LDB_SCOPE_SUBTREE, no_attrs,
212 DSDB_FLAG_NEXT_MODULE, ac->req,
213 "(%s=%s)", attr, enc_str);
215 if (ret != LDB_SUCCESS) {
216 return ret;
218 if (res->count > 1) {
219 return ldb_operr(ldb);
220 } else if (res->count == 1) {
221 if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0) {
222 ldb_asprintf_errstring(ldb,
223 "samldb: %s '%s' already in use!",
224 attr, enc_str);
225 return LDB_ERR_ENTRY_ALREADY_EXISTS;
228 talloc_free(res);
230 return LDB_SUCCESS;
233 static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac)
235 int ret = samldb_unique_attr_check(ac, "samAccountName", NULL,
236 ldb_get_default_basedn(
237 ldb_module_get_ctx(ac->module)));
238 if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) {
239 ret = LDB_ERR_CONSTRAINT_VIOLATION;
241 return ret;
244 static int samldb_schema_attributeid_valid_check(struct samldb_ctx *ac)
246 int ret = samldb_unique_attr_check(ac, "attributeID", "governsID",
247 ldb_get_schema_basedn(
248 ldb_module_get_ctx(ac->module)));
249 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
250 ret = LDB_ERR_UNWILLING_TO_PERFORM;
252 return ret;
255 static int samldb_schema_governsid_valid_check(struct samldb_ctx *ac)
257 int ret = samldb_unique_attr_check(ac, "governsID", "attributeID",
258 ldb_get_schema_basedn(
259 ldb_module_get_ctx(ac->module)));
260 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
261 ret = LDB_ERR_UNWILLING_TO_PERFORM;
263 return ret;
266 static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx *ac)
268 int ret = samldb_unique_attr_check(ac, "lDAPDisplayName", NULL,
269 ldb_get_schema_basedn(
270 ldb_module_get_ctx(ac->module)));
271 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
272 ret = LDB_ERR_UNWILLING_TO_PERFORM;
274 return ret;
277 static int samldb_check_linkid_used(struct samldb_ctx *ac,
278 struct dsdb_schema *schema,
279 struct ldb_dn *schema_dn,
280 struct ldb_context *ldb,
281 int32_t linkID,
282 bool *found)
284 int ret;
285 struct ldb_result *ldb_res;
287 if (dsdb_attribute_by_linkID(schema, linkID)) {
288 *found = true;
289 return LDB_SUCCESS;
292 ret = dsdb_module_search(ac->module, ac,
293 &ldb_res,
294 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
295 DSDB_FLAG_NEXT_MODULE,
296 ac->req,
297 "(linkID=%d)", linkID);
298 if (ret != LDB_SUCCESS) {
299 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
300 __location__": Searching for linkID=%d failed - %s\n",
301 linkID,
302 ldb_errstring(ldb));
303 return ldb_operr(ldb);
306 *found = (ldb_res->count != 0);
307 talloc_free(ldb_res);
309 return LDB_SUCCESS;
312 /* Find the next open forward linkID in the schema. */
313 static int samldb_generate_next_linkid(struct samldb_ctx *ac,
314 struct dsdb_schema *schema,
315 int32_t *next_linkID)
317 int ret;
318 struct ldb_context *ldb;
319 struct ldb_dn *schema_dn;
320 bool linkID_used = true;
323 * Windows starts at about 0xB0000000 in order to stop potential
324 * collisions with future additions to the schema. We pass this
325 * around as a signed int sometimes, but this should be sufficient.
327 *next_linkID = 0x40000000;
329 ldb = ldb_module_get_ctx(ac->module);
330 schema_dn = ldb_get_schema_basedn(ldb);
332 while (linkID_used) {
333 *next_linkID += 2;
334 ret = samldb_check_linkid_used(ac, schema,
335 schema_dn, ldb,
336 *next_linkID, &linkID_used);
337 if (ret != LDB_SUCCESS) {
338 return ret;
342 return LDB_SUCCESS;
345 static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
347 int ret;
348 bool ok, found = false;
349 struct ldb_message_element *el;
350 const char *enc_str;
351 const struct dsdb_attribute *attr;
352 struct ldb_context *ldb;
353 struct ldb_dn *schema_dn;
354 struct dsdb_schema *schema;
355 int32_t new_linkID = 0;
357 ldb = ldb_module_get_ctx(ac->module);
358 schema = dsdb_get_schema(ldb, ac);
359 schema_dn = ldb_get_schema_basedn(ldb);
361 el = dsdb_get_single_valued_attr(ac->msg, "linkID",
362 ac->req->operation);
363 if (el == NULL) {
364 return LDB_SUCCESS;
367 enc_str = ldb_binary_encode(ac, el->values[0]);
368 if (enc_str == NULL) {
369 return ldb_module_oom(ac->module);
372 ok = (strcmp(enc_str, "0") == 0);
373 if (ok) {
374 return LDB_SUCCESS;
378 * This OID indicates that the caller wants the linkID
379 * to be automatically generated. We therefore assign
380 * it the next open linkID.
382 ok = (strcmp(enc_str, "1.2.840.113556.1.2.50") == 0);
383 if (ok) {
384 ret = samldb_generate_next_linkid(ac, schema, &new_linkID);
385 if (ret != LDB_SUCCESS) {
386 return ret;
389 ldb_msg_remove_element(ac->msg, el);
390 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
391 new_linkID);
392 return ret;
396 * Using either the attributeID or lDAPDisplayName of
397 * another attribute in the linkID field indicates that
398 * we should make this the backlink of that attribute.
400 attr = dsdb_attribute_by_attributeID_oid(schema, enc_str);
401 if (attr == NULL) {
402 attr = dsdb_attribute_by_lDAPDisplayName(schema, enc_str);
405 if (attr != NULL) {
407 * The attribute we're adding this as a backlink of must
408 * be a forward link.
410 if (attr->linkID % 2 != 0) {
411 return LDB_ERR_UNWILLING_TO_PERFORM;
414 new_linkID = attr->linkID + 1;
416 /* Make sure that this backlink doesn't already exist. */
417 ret = samldb_check_linkid_used(ac, schema,
418 schema_dn, ldb,
419 new_linkID, &found);
420 if (ret != LDB_SUCCESS) {
421 return ret;
424 if (found) {
425 return LDB_ERR_UNWILLING_TO_PERFORM;
428 ldb_msg_remove_element(ac->msg, el);
429 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
430 new_linkID);
431 return ret;
434 schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
435 ret = samldb_unique_attr_check(ac, "linkID", NULL, schema_dn);
436 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
437 return LDB_ERR_UNWILLING_TO_PERFORM;
438 } else {
439 return ret;
443 static int samldb_check_mapiid_used(struct samldb_ctx *ac,
444 struct dsdb_schema *schema,
445 struct ldb_dn *schema_dn,
446 struct ldb_context *ldb,
447 int32_t mapiid,
448 bool *found)
450 int ret;
451 struct ldb_result *ldb_res;
453 ret = dsdb_module_search(ac->module, ac,
454 &ldb_res,
455 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
456 DSDB_FLAG_NEXT_MODULE,
457 ac->req,
458 "(mAPIID=%d)", mapiid);
459 if (ret != LDB_SUCCESS) {
460 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
461 __location__": Searching for mAPIID=%d failed - %s\n",
462 mapiid,
463 ldb_errstring(ldb));
464 return ldb_operr(ldb);
467 *found = (ldb_res->count != 0);
468 talloc_free(ldb_res);
470 return LDB_SUCCESS;
473 static int samldb_generate_next_mapiid(struct samldb_ctx *ac,
474 struct dsdb_schema *schema,
475 int32_t *next_mapiid)
477 int ret;
478 struct ldb_context *ldb;
479 struct ldb_dn *schema_dn;
480 bool mapiid_used = true;
482 /* Windows' generation seems to start about here */
483 *next_mapiid = 60000;
485 ldb = ldb_module_get_ctx(ac->module);
486 schema_dn = ldb_get_schema_basedn(ldb);
488 while (mapiid_used) {
489 *next_mapiid += 1;
490 ret = samldb_check_mapiid_used(ac, schema,
491 schema_dn, ldb,
492 *next_mapiid, &mapiid_used);
493 if (ret != LDB_SUCCESS) {
494 return ret;
498 return LDB_SUCCESS;
501 static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
503 int ret;
504 bool ok;
505 struct ldb_message_element *el;
506 const char *enc_str;
507 struct ldb_context *ldb;
508 struct ldb_dn *schema_dn;
509 struct dsdb_schema *schema;
510 int32_t new_mapiid = 0;
513 * The mAPIID of a new attribute should be automatically generated
514 * if a specific OID is put as the mAPIID, as according to
515 * [MS-ADTS] 3.1.1.2.3.2.
518 ldb = ldb_module_get_ctx(ac->module);
519 schema = dsdb_get_schema(ldb, ac);
520 schema_dn = ldb_get_schema_basedn(ldb);
522 el = dsdb_get_single_valued_attr(ac->msg, "mAPIID",
523 ac->req->operation);
524 if (el == NULL) {
525 return LDB_SUCCESS;
528 enc_str = ldb_binary_encode(ac, el->values[0]);
529 if (enc_str == NULL) {
530 return ldb_module_oom(ac->module);
533 ok = (strcmp(enc_str, "1.2.840.113556.1.2.49") == 0);
534 if (ok) {
535 ret = samldb_generate_next_mapiid(ac, schema,
536 &new_mapiid);
537 if (ret != LDB_SUCCESS) {
538 return ret;
541 ldb_msg_remove_element(ac->msg, el);
542 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
543 "mAPIID", new_mapiid);
544 return ret;
547 schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
548 ret = samldb_unique_attr_check(ac, "mAPIID", NULL, schema_dn);
549 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
550 return LDB_ERR_UNWILLING_TO_PERFORM;
551 } else {
552 return ret;
556 /* sAMAccountName handling */
557 static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
558 struct ldb_message *msg)
560 char *name;
562 /* Format: $000000-000000000000 */
564 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
565 (unsigned int)generate_random(),
566 (unsigned int)generate_random(),
567 (unsigned int)generate_random());
568 if (name == NULL) {
569 return ldb_oom(ldb);
571 return ldb_msg_add_steal_string(msg, "sAMAccountName", name);
574 static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
576 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
577 int ret;
579 if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
580 ret = samldb_generate_sAMAccountName(ldb, ac->msg);
581 if (ret != LDB_SUCCESS) {
582 return ret;
586 ret = samldb_sam_accountname_valid_check(ac);
587 if (ret != LDB_SUCCESS) {
588 return ret;
591 return samldb_next_step(ac);
595 static bool samldb_msg_add_sid(struct ldb_message *msg,
596 const char *name,
597 const struct dom_sid *sid)
599 struct ldb_val v;
600 enum ndr_err_code ndr_err;
602 ndr_err = ndr_push_struct_blob(&v, msg, sid,
603 (ndr_push_flags_fn_t)ndr_push_dom_sid);
604 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
605 return false;
607 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
611 /* allocate a SID using our RID Set */
612 static int samldb_allocate_sid(struct samldb_ctx *ac)
614 uint32_t rid;
615 struct dom_sid *sid;
616 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
617 int ret;
619 ret = ridalloc_allocate_rid(ac->module, &rid, ac->req);
620 if (ret != LDB_SUCCESS) {
621 return ret;
624 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
625 if (sid == NULL) {
626 return ldb_module_oom(ac->module);
629 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
630 return ldb_operr(ldb);
633 return samldb_next_step(ac);
637 see if a krbtgt_number is available
639 static bool samldb_krbtgtnumber_available(struct samldb_ctx *ac,
640 uint32_t krbtgt_number)
642 TALLOC_CTX *tmp_ctx = talloc_new(ac);
643 struct ldb_result *res;
644 const char * const no_attrs[] = { NULL };
645 int ret;
647 ret = dsdb_module_search(ac->module, tmp_ctx, &res,
648 ldb_get_default_basedn(ldb_module_get_ctx(ac->module)),
649 LDB_SCOPE_SUBTREE, no_attrs,
650 DSDB_FLAG_NEXT_MODULE,
651 ac->req,
652 "(msDC-SecondaryKrbTgtNumber=%u)",
653 krbtgt_number);
654 if (ret == LDB_SUCCESS && res->count == 0) {
655 talloc_free(tmp_ctx);
656 return true;
658 talloc_free(tmp_ctx);
659 return false;
662 /* special handling for add in RODC join */
663 static int samldb_rodc_add(struct samldb_ctx *ac)
665 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
666 uint32_t krbtgt_number, i_start, i;
667 int ret;
668 struct ldb_val newpass_utf16;
670 /* find a unused msDC-SecondaryKrbTgtNumber */
671 i_start = generate_random() & 0xFFFF;
672 if (i_start == 0) {
673 i_start = 1;
676 for (i=i_start; i<=0xFFFF; i++) {
677 if (samldb_krbtgtnumber_available(ac, i)) {
678 krbtgt_number = i;
679 goto found;
682 for (i=1; i<i_start; i++) {
683 if (samldb_krbtgtnumber_available(ac, i)) {
684 krbtgt_number = i;
685 goto found;
689 ldb_asprintf_errstring(ldb,
690 "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
691 W_ERROR_V(WERR_NO_SYSTEM_RESOURCES));
692 return LDB_ERR_OTHER;
694 found:
695 ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber",
696 LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL);
697 if (ret != LDB_SUCCESS) {
698 return ldb_operr(ldb);
701 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
702 "msDS-SecondaryKrbTgtNumber", krbtgt_number);
703 if (ret != LDB_SUCCESS) {
704 return ldb_operr(ldb);
707 ret = ldb_msg_add_fmt(ac->msg, "sAMAccountName", "krbtgt_%u",
708 krbtgt_number);
709 if (ret != LDB_SUCCESS) {
710 return ldb_operr(ldb);
713 newpass_utf16 = data_blob_talloc_zero(ac->module, 256);
714 if (newpass_utf16.data == NULL) {
715 return ldb_oom(ldb);
718 * Note that the password_hash module will ignore
719 * this value and use it's own generate_secret_buffer()
720 * that's why we can just use generate_random_buffer()
721 * here.
723 generate_random_buffer(newpass_utf16.data, newpass_utf16.length);
724 ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
725 if (ret != LDB_SUCCESS) {
726 return ldb_operr(ldb);
729 return samldb_next_step(ac);
732 static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
734 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
735 struct ldb_result *res;
736 const char * const no_attrs[] = { NULL };
737 int ret;
739 ac->res_dn = NULL;
741 ret = dsdb_module_search(ac->module, ac, &res,
742 ac->dn, LDB_SCOPE_BASE, no_attrs,
743 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
744 | DSDB_FLAG_NEXT_MODULE,
745 ac->req,
746 "(objectClass=classSchema)");
747 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
748 /* Don't be pricky when the DN doesn't exist if we have the */
749 /* RELAX control specified */
750 if (ldb_request_get_control(ac->req,
751 LDB_CONTROL_RELAX_OID) == NULL) {
752 ldb_set_errstring(ldb,
753 "samldb_find_defaultObjectCategory: "
754 "Invalid DN for 'defaultObjectCategory'!");
755 return LDB_ERR_CONSTRAINT_VIOLATION;
758 if ((ret != LDB_ERR_NO_SUCH_OBJECT) && (ret != LDB_SUCCESS)) {
759 return ret;
762 if (ret == LDB_SUCCESS) {
763 /* ensure the defaultObjectCategory has a full GUID */
764 struct ldb_message *m;
765 m = ldb_msg_new(ac->msg);
766 if (m == NULL) {
767 return ldb_oom(ldb);
769 m->dn = ac->msg->dn;
770 if (ldb_msg_add_string(m, "defaultObjectCategory",
771 ldb_dn_get_extended_linearized(m, res->msgs[0]->dn, 1)) !=
772 LDB_SUCCESS) {
773 return ldb_oom(ldb);
775 m->elements[0].flags = LDB_FLAG_MOD_REPLACE;
777 ret = dsdb_module_modify(ac->module, m,
778 DSDB_FLAG_NEXT_MODULE,
779 ac->req);
780 if (ret != LDB_SUCCESS) {
781 return ret;
786 ac->res_dn = ac->dn;
788 return samldb_next_step(ac);
792 * msDS-IntId attributeSchema attribute handling
793 * during LDB_ADD request processing
795 static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac)
797 int ret;
798 bool id_exists;
799 uint32_t msds_intid;
800 int32_t system_flags;
801 struct ldb_context *ldb;
802 struct ldb_result *ldb_res;
803 struct ldb_dn *schema_dn;
804 struct samldb_msds_intid_persistant *msds_intid_struct;
805 struct dsdb_schema *schema;
807 ldb = ldb_module_get_ctx(ac->module);
808 schema_dn = ldb_get_schema_basedn(ldb);
810 /* replicated update should always go through */
811 if (ldb_request_get_control(ac->req,
812 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
813 return LDB_SUCCESS;
816 /* msDS-IntId is handled by system and should never be
817 * passed by clients */
818 if (ldb_msg_find_element(ac->msg, "msDS-IntId")) {
819 return LDB_ERR_UNWILLING_TO_PERFORM;
822 /* do not generate msDS-IntId if Relax control is passed */
823 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
824 return LDB_SUCCESS;
827 /* check Functional Level */
828 if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
829 return LDB_SUCCESS;
832 /* check systemFlags for SCHEMA_BASE_OBJECT flag */
833 system_flags = ldb_msg_find_attr_as_int(ac->msg, "systemFlags", 0);
834 if (system_flags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) {
835 return LDB_SUCCESS;
837 schema = dsdb_get_schema(ldb, NULL);
838 if (!schema) {
839 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
840 "samldb_schema_info_update: no dsdb_schema loaded");
841 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
842 return ldb_operr(ldb);
845 msds_intid_struct = (struct samldb_msds_intid_persistant*) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
846 if (!msds_intid_struct) {
847 msds_intid_struct = talloc(ldb, struct samldb_msds_intid_persistant);
848 /* Generate new value for msDs-IntId
849 * Value should be in 0x80000000..0xBFFFFFFF range */
850 msds_intid = generate_random() % 0X3FFFFFFF;
851 msds_intid += 0x80000000;
852 msds_intid_struct->msds_intid = msds_intid;
853 DEBUG(2, ("No samldb_msds_intid_persistant struct, allocating a new one\n"));
854 } else {
855 msds_intid = msds_intid_struct->msds_intid;
858 /* probe id values until unique one is found */
859 do {
860 msds_intid++;
861 if (msds_intid > 0xBFFFFFFF) {
862 msds_intid = 0x80000001;
865 * We search in the schema if we have already this
866 * intid (using dsdb_attribute_by_attributeID_id
867 * because in the range 0x80000000 0xBFFFFFFFF,
868 * attributeID is a DSDB_ATTID_TYPE_INTID).
870 * If so generate another random value.
872 * We have to check the DB in case someone else has
873 * modified the database while we are doing our
874 * changes too (this case should be very bery rare) in
875 * order to be sure.
877 if (dsdb_attribute_by_attributeID_id(schema, msds_intid)) {
878 id_exists = true;
879 msds_intid = generate_random() % 0X3FFFFFFF;
880 msds_intid += 0x80000000;
881 continue;
885 ret = dsdb_module_search(ac->module, ac,
886 &ldb_res,
887 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
888 DSDB_FLAG_NEXT_MODULE,
889 ac->req,
890 "(msDS-IntId=%d)", msds_intid);
891 if (ret != LDB_SUCCESS) {
892 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
893 __location__": Searching for msDS-IntId=%d failed - %s\n",
894 msds_intid,
895 ldb_errstring(ldb));
896 return ldb_operr(ldb);
898 id_exists = (ldb_res->count > 0);
899 talloc_free(ldb_res);
901 } while(id_exists);
902 msds_intid_struct->msds_intid = msds_intid;
903 ldb_set_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE, msds_intid_struct);
905 return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
906 msds_intid);
911 * samldb_add_entry (async)
914 static int samldb_add_entry_callback(struct ldb_request *req,
915 struct ldb_reply *ares)
917 struct ldb_context *ldb;
918 struct samldb_ctx *ac;
919 int ret;
921 ac = talloc_get_type(req->context, struct samldb_ctx);
922 ldb = ldb_module_get_ctx(ac->module);
924 if (!ares) {
925 return ldb_module_done(ac->req, NULL, NULL,
926 LDB_ERR_OPERATIONS_ERROR);
929 if (ares->type == LDB_REPLY_REFERRAL) {
930 return ldb_module_send_referral(ac->req, ares->referral);
933 if (ares->error != LDB_SUCCESS) {
934 return ldb_module_done(ac->req, ares->controls,
935 ares->response, ares->error);
937 if (ares->type != LDB_REPLY_DONE) {
938 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
939 return ldb_module_done(ac->req, NULL, NULL,
940 LDB_ERR_OPERATIONS_ERROR);
943 /* The caller may wish to get controls back from the add */
944 ac->ares = talloc_steal(ac, ares);
946 ret = samldb_next_step(ac);
947 if (ret != LDB_SUCCESS) {
948 return ldb_module_done(ac->req, NULL, NULL, ret);
950 return ret;
953 static int samldb_add_entry(struct samldb_ctx *ac)
955 struct ldb_context *ldb;
956 struct ldb_request *req;
957 int ret;
959 ldb = ldb_module_get_ctx(ac->module);
961 ret = ldb_build_add_req(&req, ldb, ac,
962 ac->msg,
963 ac->req->controls,
964 ac, samldb_add_entry_callback,
965 ac->req);
966 LDB_REQ_SET_LOCATION(req);
967 if (ret != LDB_SUCCESS) {
968 return ret;
971 return ldb_next_request(ac->module, req);
975 * return true if msg carries an attributeSchema that is intended to be RODC
976 * filtered but is also a system-critical attribute.
978 static bool check_rodc_critical_attribute(struct ldb_message *msg)
980 uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
982 schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
983 searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
984 rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
985 | SEARCH_FLAG_CONFIDENTIAL);
987 if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
988 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
989 return true;
990 } else {
991 return false;
996 static int samldb_fill_object(struct samldb_ctx *ac)
998 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
999 int ret;
1001 /* Add information for the different account types */
1002 switch(ac->type) {
1003 case SAMLDB_TYPE_USER: {
1004 struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
1005 LDB_CONTROL_RODC_DCPROMO_OID);
1006 if (rodc_control != NULL) {
1007 /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
1008 rodc_control->critical = false;
1009 ret = samldb_add_step(ac, samldb_rodc_add);
1010 if (ret != LDB_SUCCESS) return ret;
1013 /* check if we have a valid sAMAccountName */
1014 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1015 if (ret != LDB_SUCCESS) return ret;
1017 ret = samldb_add_step(ac, samldb_add_entry);
1018 if (ret != LDB_SUCCESS) return ret;
1019 break;
1022 case SAMLDB_TYPE_GROUP: {
1023 /* check if we have a valid sAMAccountName */
1024 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1025 if (ret != LDB_SUCCESS) return ret;
1027 ret = samldb_add_step(ac, samldb_add_entry);
1028 if (ret != LDB_SUCCESS) return ret;
1029 break;
1032 case SAMLDB_TYPE_CLASS: {
1033 const char *lDAPDisplayName = NULL;
1034 const struct ldb_val *rdn_value, *def_obj_cat_val;
1035 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
1037 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
1038 if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
1039 ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
1040 if (ret != LDB_SUCCESS) return ret;
1043 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1044 "rdnAttId", "cn");
1045 if (ret != LDB_SUCCESS) return ret;
1047 /* do not allow one to mark an attributeSchema as RODC filtered if it
1048 * is system-critical */
1049 if (check_rodc_critical_attribute(ac->msg)) {
1050 ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
1051 ldb_dn_get_linearized(ac->msg->dn));
1052 return LDB_ERR_UNWILLING_TO_PERFORM;
1055 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1056 if (rdn_value == NULL) {
1057 return ldb_operr(ldb);
1059 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1060 /* the RDN has prefix "CN" */
1061 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1062 samdb_cn_to_lDAPDisplayName(ac->msg,
1063 (const char *) rdn_value->data));
1064 if (ret != LDB_SUCCESS) {
1065 ldb_oom(ldb);
1066 return ret;
1070 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1071 "lDAPDisplayName",
1072 NULL);
1073 ret = ldb_valid_attr_name(lDAPDisplayName);
1074 if (ret != 1 ||
1075 lDAPDisplayName[0] == '*' ||
1076 lDAPDisplayName[0] == '@')
1078 return dsdb_module_werror(ac->module,
1079 LDB_ERR_UNWILLING_TO_PERFORM,
1080 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1081 "lDAPDisplayName is invalid");
1084 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1085 struct GUID guid;
1086 /* a new GUID */
1087 guid = GUID_random();
1088 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1089 if (ret != LDB_SUCCESS) {
1090 ldb_oom(ldb);
1091 return ret;
1095 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
1096 "defaultObjectCategory");
1097 if (def_obj_cat_val != NULL) {
1098 /* "defaultObjectCategory" has been set by the caller.
1099 * Do some checks for consistency.
1100 * NOTE: The real constraint check (that
1101 * 'defaultObjectCategory' is the DN of the new
1102 * objectclass or any parent of it) is still incomplete.
1103 * For now we say that 'defaultObjectCategory' is valid
1104 * if it exists and it is of objectclass "classSchema".
1106 ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
1107 if (ac->dn == NULL) {
1108 ldb_set_errstring(ldb,
1109 "Invalid DN for 'defaultObjectCategory'!");
1110 return LDB_ERR_CONSTRAINT_VIOLATION;
1112 } else {
1113 /* "defaultObjectCategory" has not been set by the
1114 * caller. Use the entry DN for it. */
1115 ac->dn = ac->msg->dn;
1117 ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
1118 ldb_dn_alloc_linearized(ac->msg, ac->dn));
1119 if (ret != LDB_SUCCESS) {
1120 ldb_oom(ldb);
1121 return ret;
1125 ret = samldb_add_step(ac, samldb_add_entry);
1126 if (ret != LDB_SUCCESS) return ret;
1128 /* Now perform the checks for the 'defaultObjectCategory'. The
1129 * lookup DN was already saved in "ac->dn" */
1130 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
1131 if (ret != LDB_SUCCESS) return ret;
1133 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
1134 if (v == -2) {
1135 /* Windows 2003 does this*/
1136 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
1137 if (ret != LDB_SUCCESS) {
1138 return ret;
1141 break;
1144 case SAMLDB_TYPE_ATTRIBUTE: {
1145 const char *lDAPDisplayName = NULL;
1146 const struct ldb_val *rdn_value;
1147 struct ldb_message_element *el;
1148 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1149 if (rdn_value == NULL) {
1150 return ldb_operr(ldb);
1152 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1153 /* the RDN has prefix "CN" */
1154 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1155 samdb_cn_to_lDAPDisplayName(ac->msg,
1156 (const char *) rdn_value->data));
1157 if (ret != LDB_SUCCESS) {
1158 ldb_oom(ldb);
1159 return ret;
1163 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1164 "lDAPDisplayName",
1165 NULL);
1166 ret = ldb_valid_attr_name(lDAPDisplayName);
1167 if (ret != 1 ||
1168 lDAPDisplayName[0] == '*' ||
1169 lDAPDisplayName[0] == '@')
1171 return dsdb_module_werror(ac->module,
1172 LDB_ERR_UNWILLING_TO_PERFORM,
1173 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1174 "lDAPDisplayName is invalid");
1177 /* do not allow one to mark an attributeSchema as RODC filtered if it
1178 * is system-critical */
1179 if (check_rodc_critical_attribute(ac->msg)) {
1180 ldb_asprintf_errstring(ldb,
1181 "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
1182 ldb_dn_get_linearized(ac->msg->dn));
1183 return LDB_ERR_UNWILLING_TO_PERFORM;
1186 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1187 "isSingleValued", "FALSE");
1188 if (ret != LDB_SUCCESS) return ret;
1190 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1191 struct GUID guid;
1192 /* a new GUID */
1193 guid = GUID_random();
1194 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1195 if (ret != LDB_SUCCESS) {
1196 ldb_oom(ldb);
1197 return ret;
1201 el = ldb_msg_find_element(ac->msg, "attributeSyntax");
1202 if (el) {
1204 * No need to scream if there isn't as we have code later on
1205 * that will take care of it.
1207 const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
1208 if (!syntax) {
1209 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
1210 (const char *)el->values[0].data));
1211 } else {
1212 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
1213 const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
1215 if (v == 0) {
1216 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
1217 if (ret != LDB_SUCCESS) {
1218 return ret;
1221 if (!val) {
1222 struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
1223 if (val2.length > 0) {
1224 ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
1225 if (ret != LDB_SUCCESS) {
1226 return ret;
1233 /* handle msDS-IntID attribute */
1234 ret = samldb_add_handle_msDS_IntId(ac);
1235 if (ret != LDB_SUCCESS) return ret;
1237 ret = samldb_add_step(ac, samldb_add_entry);
1238 if (ret != LDB_SUCCESS) return ret;
1239 break;
1242 default:
1243 ldb_asprintf_errstring(ldb, "Invalid entry type!");
1244 return LDB_ERR_OPERATIONS_ERROR;
1245 break;
1248 return samldb_first_step(ac);
1251 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1253 struct ldb_context *ldb;
1254 const struct ldb_val *rdn_value;
1255 struct dom_sid *sid;
1256 int ret;
1258 ldb = ldb_module_get_ctx(ac->module);
1260 sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1261 if (sid == NULL) {
1262 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1263 if (rdn_value == NULL) {
1264 return ldb_operr(ldb);
1266 sid = dom_sid_parse_talloc(ac->msg,
1267 (const char *)rdn_value->data);
1268 if (sid == NULL) {
1269 ldb_set_errstring(ldb,
1270 "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
1271 return LDB_ERR_CONSTRAINT_VIOLATION;
1273 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
1274 return ldb_operr(ldb);
1278 /* finally proceed with adding the entry */
1279 ret = samldb_add_step(ac, samldb_add_entry);
1280 if (ret != LDB_SUCCESS) return ret;
1282 return samldb_first_step(ac);
1285 static int samldb_schema_info_update(struct samldb_ctx *ac)
1287 int ret;
1288 struct ldb_context *ldb;
1289 struct dsdb_schema *schema;
1291 /* replicated update should always go through */
1292 if (ldb_request_get_control(ac->req,
1293 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1294 return LDB_SUCCESS;
1297 /* do not update schemaInfo during provisioning */
1298 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1299 return LDB_SUCCESS;
1302 ldb = ldb_module_get_ctx(ac->module);
1303 schema = dsdb_get_schema(ldb, NULL);
1304 if (!schema) {
1305 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1306 "samldb_schema_info_update: no dsdb_schema loaded");
1307 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1308 return ldb_operr(ldb);
1311 ret = dsdb_module_schema_info_update(ac->module, schema,
1312 DSDB_FLAG_NEXT_MODULE|
1313 DSDB_FLAG_AS_SYSTEM,
1314 ac->req);
1315 if (ret != LDB_SUCCESS) {
1316 ldb_asprintf_errstring(ldb,
1317 "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
1318 ldb_errstring(ldb));
1319 return ret;
1322 return LDB_SUCCESS;
1325 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
1326 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
1327 struct dom_sid *sid,
1328 uint32_t req_uac,
1329 uint32_t user_account_control,
1330 uint32_t user_account_control_old);
1333 * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
1335 * Has to be invoked on "add" and "modify" operations on "user", "computer" and
1336 * "group" objects.
1337 * ac->msg contains the "add"/"modify" message
1338 * ac->type contains the object type (main objectclass)
1340 static int samldb_objectclass_trigger(struct samldb_ctx *ac)
1342 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1343 void *skip_allocate_sids = ldb_get_opaque(ldb,
1344 "skip_allocate_sids");
1345 struct ldb_message_element *el, *el2;
1346 struct dom_sid *sid;
1347 int ret;
1349 /* make sure that "sAMAccountType" is not specified */
1350 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1351 if (el != NULL) {
1352 ldb_set_errstring(ldb,
1353 "samldb: sAMAccountType must not be specified!");
1354 return LDB_ERR_UNWILLING_TO_PERFORM;
1357 /* Step 1: objectSid assignment */
1359 /* Don't allow the objectSid to be changed. But beside the RELAX
1360 * control we have also to guarantee that it can always be set with
1361 * SYSTEM permissions. This is needed for the "samba3sam" backend. */
1362 sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1363 if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
1364 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
1365 ldb_set_errstring(ldb,
1366 "samldb: objectSid must not be specified!");
1367 return LDB_ERR_UNWILLING_TO_PERFORM;
1370 /* but generate a new SID when we do have an add operations */
1371 if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
1372 ret = samldb_add_step(ac, samldb_allocate_sid);
1373 if (ret != LDB_SUCCESS) return ret;
1376 switch(ac->type) {
1377 case SAMLDB_TYPE_USER: {
1378 bool uac_generated = false, uac_add_flags = false;
1380 /* Step 1.2: Default values */
1381 ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
1382 if (ret != LDB_SUCCESS) return ret;
1384 /* On add operations we might need to generate a
1385 * "userAccountControl" (if it isn't specified). */
1386 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1387 if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
1388 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1389 "userAccountControl",
1390 UF_NORMAL_ACCOUNT);
1391 if (ret != LDB_SUCCESS) {
1392 return ret;
1394 uac_generated = true;
1395 uac_add_flags = true;
1398 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1399 if (el != NULL) {
1400 uint32_t raw_uac;
1401 uint32_t user_account_control;
1402 /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
1403 user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
1404 "userAccountControl",
1406 raw_uac = user_account_control;
1408 * "userAccountControl" = 0 or missing one of
1409 * the types means "UF_NORMAL_ACCOUNT". See
1410 * MS-SAMR 3.1.1.8.10 point 8
1412 if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
1413 user_account_control = UF_NORMAL_ACCOUNT | user_account_control;
1414 uac_generated = true;
1418 * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
1420 if ((user_account_control & UF_LOCKOUT) != 0) {
1421 user_account_control &= ~UF_LOCKOUT;
1422 uac_generated = true;
1424 if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
1425 user_account_control &= ~UF_PASSWORD_EXPIRED;
1426 uac_generated = true;
1429 ret = samldb_check_user_account_control_rules(ac, NULL,
1430 raw_uac,
1431 user_account_control,
1433 if (ret != LDB_SUCCESS) {
1434 return ret;
1437 /* Workstation and (read-only) DC objects do need objectclass "computer" */
1438 if ((samdb_find_attribute(ldb, ac->msg,
1439 "objectclass", "computer") == NULL) &&
1440 (user_account_control &
1441 (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
1442 ldb_set_errstring(ldb,
1443 "samldb: Requested account type does need objectclass 'computer'!");
1444 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1447 /* add "sAMAccountType" attribute */
1448 ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
1449 if (ret != LDB_SUCCESS) {
1450 return ret;
1453 /* "isCriticalSystemObject" might be set */
1454 if (user_account_control &
1455 (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1456 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1457 "TRUE");
1458 if (ret != LDB_SUCCESS) {
1459 return ret;
1461 el2 = ldb_msg_find_element(ac->msg,
1462 "isCriticalSystemObject");
1463 el2->flags = LDB_FLAG_MOD_REPLACE;
1464 } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1465 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1466 "FALSE");
1467 if (ret != LDB_SUCCESS) {
1468 return ret;
1470 el2 = ldb_msg_find_element(ac->msg,
1471 "isCriticalSystemObject");
1472 el2->flags = LDB_FLAG_MOD_REPLACE;
1475 /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
1476 if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1477 uint32_t rid;
1479 ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
1480 if (ret != LDB_SUCCESS) {
1481 return ret;
1484 * Older AD deployments don't know about the
1485 * RODC group
1487 if (rid == DOMAIN_RID_READONLY_DCS) {
1488 ret = samldb_prim_group_tester(ac, rid);
1489 if (ret != LDB_SUCCESS) {
1490 return ret;
1495 /* Step 1.5: Add additional flags when needed */
1496 /* Obviously this is done when the "userAccountControl"
1497 * has been generated here (tested against Windows
1498 * Server) */
1499 if (uac_generated) {
1500 if (uac_add_flags) {
1501 user_account_control |= UF_ACCOUNTDISABLE;
1502 user_account_control |= UF_PASSWD_NOTREQD;
1505 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1506 "userAccountControl",
1507 user_account_control);
1508 if (ret != LDB_SUCCESS) {
1509 return ret;
1514 break;
1517 case SAMLDB_TYPE_GROUP: {
1518 const char *tempstr;
1520 /* Step 2.2: Default values */
1521 tempstr = talloc_asprintf(ac->msg, "%d",
1522 GTYPE_SECURITY_GLOBAL_GROUP);
1523 if (tempstr == NULL) return ldb_operr(ldb);
1524 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1525 "groupType", tempstr);
1526 if (ret != LDB_SUCCESS) return ret;
1528 /* Step 2.3: "groupType" -> "sAMAccountType" */
1529 el = ldb_msg_find_element(ac->msg, "groupType");
1530 if (el != NULL) {
1531 uint32_t group_type, account_type;
1533 group_type = ldb_msg_find_attr_as_uint(ac->msg,
1534 "groupType", 0);
1536 /* The creation of builtin groups requires the
1537 * RELAX control */
1538 if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
1539 if (ldb_request_get_control(ac->req,
1540 LDB_CONTROL_RELAX_OID) == NULL) {
1541 return LDB_ERR_UNWILLING_TO_PERFORM;
1545 account_type = ds_gtype2atype(group_type);
1546 if (account_type == 0) {
1547 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1548 return LDB_ERR_UNWILLING_TO_PERFORM;
1550 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1551 "sAMAccountType",
1552 account_type);
1553 if (ret != LDB_SUCCESS) {
1554 return ret;
1556 el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1557 el2->flags = LDB_FLAG_MOD_REPLACE;
1559 break;
1562 default:
1563 ldb_asprintf_errstring(ldb,
1564 "Invalid entry type!");
1565 return LDB_ERR_OPERATIONS_ERROR;
1566 break;
1569 return LDB_SUCCESS;
1573 * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
1575 * Has to be invoked on "add" and "modify" operations on "user" and "computer"
1576 * objects.
1577 * ac->msg contains the "add"/"modify" message
1580 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
1582 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1583 struct dom_sid *sid;
1584 struct ldb_result *res;
1585 int ret;
1586 const char * const noattrs[] = { NULL };
1588 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1589 if (sid == NULL) {
1590 return ldb_operr(ldb);
1593 ret = dsdb_module_search(ac->module, ac, &res,
1594 ldb_get_default_basedn(ldb),
1595 LDB_SCOPE_SUBTREE,
1596 noattrs, DSDB_FLAG_NEXT_MODULE,
1597 ac->req,
1598 "(objectSid=%s)",
1599 ldap_encode_ndr_dom_sid(ac, sid));
1600 if (ret != LDB_SUCCESS) {
1601 return ret;
1603 if (res->count != 1) {
1604 talloc_free(res);
1605 ldb_asprintf_errstring(ldb,
1606 "Failed to find primary group with RID %u!",
1607 rid);
1608 return LDB_ERR_UNWILLING_TO_PERFORM;
1610 talloc_free(res);
1612 return LDB_SUCCESS;
1615 static int samldb_prim_group_set(struct samldb_ctx *ac)
1617 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1618 uint32_t rid;
1620 rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
1621 if (rid == (uint32_t) -1) {
1622 /* we aren't affected of any primary group set */
1623 return LDB_SUCCESS;
1625 } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1626 ldb_set_errstring(ldb,
1627 "The primary group isn't settable on add operations!");
1628 return LDB_ERR_UNWILLING_TO_PERFORM;
1631 return samldb_prim_group_tester(ac, rid);
1634 static int samldb_prim_group_change(struct samldb_ctx *ac)
1636 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1637 const char * const attrs[] = {
1638 "primaryGroupID",
1639 "memberOf",
1640 "userAccountControl",
1641 NULL };
1642 struct ldb_result *res, *group_res;
1643 struct ldb_message_element *el;
1644 struct ldb_message *msg;
1645 uint32_t prev_rid, new_rid, uac;
1646 struct dom_sid *prev_sid, *new_sid;
1647 struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1648 int ret;
1649 const char * const noattrs[] = { NULL };
1651 el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1652 ac->req->operation);
1653 if (el == NULL) {
1654 /* we are not affected */
1655 return LDB_SUCCESS;
1658 /* Fetch information from the existing object */
1660 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1661 DSDB_FLAG_NEXT_MODULE, ac->req);
1662 if (ret != LDB_SUCCESS) {
1663 return ret;
1666 uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1668 /* Finds out the DN of the old primary group */
1670 prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1671 (uint32_t) -1);
1672 if (prev_rid == (uint32_t) -1) {
1673 /* User objects do always have a mandatory "primaryGroupID"
1674 * attribute. If this doesn't exist then the object is of the
1675 * wrong type. This is the exact Windows error code */
1676 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1679 prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1680 if (prev_sid == NULL) {
1681 return ldb_operr(ldb);
1684 /* Finds out the DN of the new primary group
1685 * Notice: in order to parse the primary group ID correctly we create
1686 * a temporary message here. */
1688 msg = ldb_msg_new(ac->msg);
1689 if (msg == NULL) {
1690 return ldb_module_oom(ac->module);
1692 ret = ldb_msg_add(msg, el, 0);
1693 if (ret != LDB_SUCCESS) {
1694 return ret;
1696 new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1697 talloc_free(msg);
1698 if (new_rid == (uint32_t) -1) {
1699 /* we aren't affected of any primary group change */
1700 return LDB_SUCCESS;
1703 if (prev_rid == new_rid) {
1704 return LDB_SUCCESS;
1707 if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
1708 ldb_asprintf_errstring(ldb,
1709 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
1710 "primaryGroupID=%u!",
1711 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1712 DOMAIN_RID_DCS);
1713 return LDB_ERR_UNWILLING_TO_PERFORM;
1716 if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
1717 ldb_asprintf_errstring(ldb,
1718 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
1719 "primaryGroupID=%u!",
1720 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1721 DOMAIN_RID_READONLY_DCS);
1722 return LDB_ERR_UNWILLING_TO_PERFORM;
1725 ret = dsdb_module_search(ac->module, ac, &group_res,
1726 ldb_get_default_basedn(ldb),
1727 LDB_SCOPE_SUBTREE,
1728 noattrs, DSDB_FLAG_NEXT_MODULE,
1729 ac->req,
1730 "(objectSid=%s)",
1731 ldap_encode_ndr_dom_sid(ac, prev_sid));
1732 if (ret != LDB_SUCCESS) {
1733 return ret;
1735 if (group_res->count != 1) {
1736 return ldb_operr(ldb);
1738 prev_prim_group_dn = group_res->msgs[0]->dn;
1740 new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1741 if (new_sid == NULL) {
1742 return ldb_operr(ldb);
1745 ret = dsdb_module_search(ac->module, ac, &group_res,
1746 ldb_get_default_basedn(ldb),
1747 LDB_SCOPE_SUBTREE,
1748 noattrs, DSDB_FLAG_NEXT_MODULE,
1749 ac->req,
1750 "(objectSid=%s)",
1751 ldap_encode_ndr_dom_sid(ac, new_sid));
1752 if (ret != LDB_SUCCESS) {
1753 return ret;
1755 if (group_res->count != 1) {
1756 /* Here we know if the specified new primary group candidate is
1757 * valid or not. */
1758 return LDB_ERR_UNWILLING_TO_PERFORM;
1760 new_prim_group_dn = group_res->msgs[0]->dn;
1762 /* We need to be already a normal member of the new primary
1763 * group in order to be successful. */
1764 el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1765 ldb_dn_get_linearized(new_prim_group_dn));
1766 if (el == NULL) {
1767 return LDB_ERR_UNWILLING_TO_PERFORM;
1770 /* Remove the "member" attribute on the new primary group */
1771 msg = ldb_msg_new(ac->msg);
1772 if (msg == NULL) {
1773 return ldb_module_oom(ac->module);
1775 msg->dn = new_prim_group_dn;
1777 ret = samdb_msg_add_delval(ldb, msg, msg, "member",
1778 ldb_dn_get_linearized(ac->msg->dn));
1779 if (ret != LDB_SUCCESS) {
1780 return ret;
1783 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1784 if (ret != LDB_SUCCESS) {
1785 return ret;
1787 talloc_free(msg);
1789 /* Add a "member" attribute for the previous primary group */
1790 msg = ldb_msg_new(ac->msg);
1791 if (msg == NULL) {
1792 return ldb_module_oom(ac->module);
1794 msg->dn = prev_prim_group_dn;
1796 ret = samdb_msg_add_addval(ldb, msg, msg, "member",
1797 ldb_dn_get_linearized(ac->msg->dn));
1798 if (ret != LDB_SUCCESS) {
1799 return ret;
1802 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1803 if (ret != LDB_SUCCESS) {
1804 return ret;
1806 talloc_free(msg);
1808 return LDB_SUCCESS;
1811 static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1813 int ret;
1815 if (ac->req->operation == LDB_ADD) {
1816 ret = samldb_prim_group_set(ac);
1817 } else {
1818 ret = samldb_prim_group_change(ac);
1821 return ret;
1824 static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
1825 uint32_t user_account_control)
1827 int i, ret = 0;
1828 bool need_check = false;
1829 const struct uac_to_guid {
1830 uint32_t uac;
1831 bool never;
1832 uint32_t needs;
1833 uint32_t not_with;
1834 const char *error_string;
1835 } map[] = {
1837 .uac = UF_TEMP_DUPLICATE_ACCOUNT,
1838 .never = true,
1839 .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
1842 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1843 .needs = UF_WORKSTATION_TRUST_ACCOUNT,
1844 .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
1847 .uac = UF_TRUSTED_FOR_DELEGATION,
1848 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1849 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1852 .uac = UF_NORMAL_ACCOUNT,
1853 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
1854 .error_string = "Setting more than one account type not permitted"
1857 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1858 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
1859 .error_string = "Setting more than one account type not permitted"
1862 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1863 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
1864 .error_string = "Setting more than one account type not permitted"
1867 .uac = UF_SERVER_TRUST_ACCOUNT,
1868 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
1869 .error_string = "Setting more than one account type not permitted"
1872 .uac = UF_TRUSTED_FOR_DELEGATION,
1873 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1874 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1878 for (i = 0; i < ARRAY_SIZE(map); i++) {
1879 if (user_account_control & map[i].uac) {
1880 need_check = true;
1881 break;
1884 if (need_check == false) {
1885 return LDB_SUCCESS;
1888 for (i = 0; i < ARRAY_SIZE(map); i++) {
1889 uint32_t this_uac = user_account_control & map[i].uac;
1890 if (this_uac != 0) {
1891 if (map[i].never) {
1892 ret = LDB_ERR_OTHER;
1893 break;
1894 } else if (map[i].needs != 0) {
1895 if ((map[i].needs & user_account_control) == 0) {
1896 ret = LDB_ERR_OTHER;
1897 break;
1899 } else if (map[i].not_with != 0) {
1900 if ((map[i].not_with & user_account_control) != 0) {
1901 ret = LDB_ERR_OTHER;
1902 break;
1907 if (ret != LDB_SUCCESS) {
1908 switch (ac->req->operation) {
1909 case LDB_ADD:
1910 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1911 "Failed to add %s: %s",
1912 ldb_dn_get_linearized(ac->msg->dn),
1913 map[i].error_string);
1914 break;
1915 case LDB_MODIFY:
1916 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1917 "Failed to modify %s: %s",
1918 ldb_dn_get_linearized(ac->msg->dn),
1919 map[i].error_string);
1920 break;
1921 default:
1922 return ldb_module_operr(ac->module);
1925 return ret;
1929 * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
1932 static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
1933 struct dom_sid *sid,
1934 uint32_t user_account_control,
1935 uint32_t user_account_control_old)
1937 int i, ret = 0;
1938 bool need_acl_check = false;
1939 struct ldb_result *res;
1940 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
1941 struct security_token *user_token;
1942 struct security_descriptor *domain_sd;
1943 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
1944 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1945 const struct uac_to_guid {
1946 uint32_t uac;
1947 uint32_t priv_to_change_from;
1948 const char *oid;
1949 const char *guid;
1950 enum sec_privilege privilege;
1951 bool delete_is_privileged;
1952 bool admin_required;
1953 const char *error_string;
1954 } map[] = {
1956 .uac = UF_PASSWD_NOTREQD,
1957 .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
1958 .error_string = "Adding the UF_PASSWD_NOTREQD bit in userAccountControl requires the Update-Password-Not-Required-Bit right that was not given on the Domain object"
1961 .uac = UF_DONT_EXPIRE_PASSWD,
1962 .guid = GUID_DRS_UNEXPIRE_PASSWORD,
1963 .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
1966 .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
1967 .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
1968 .error_string = "Adding the UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED bit in userAccountControl requires the Enable-Per-User-Reversibly-Encrypted-Password right that was not given on the Domain object"
1971 .uac = UF_SERVER_TRUST_ACCOUNT,
1972 .guid = GUID_DRS_DS_INSTALL_REPLICA,
1973 .error_string = "Adding the UF_SERVER_TRUST_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
1976 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1977 .guid = GUID_DRS_DS_INSTALL_REPLICA,
1978 .error_string = "Adding the UF_PARTIAL_SECRETS_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
1981 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1982 .priv_to_change_from = UF_NORMAL_ACCOUNT,
1983 .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
1986 .uac = UF_NORMAL_ACCOUNT,
1987 .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
1988 .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
1991 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1992 .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
1993 .error_string = "Updating the UF_INTERDOMAIN_TRUST_ACCOUNT bit in userAccountControl is not permitted over LDAP. This bit is restricted to the LSA CreateTrustedDomain interface",
1994 .delete_is_privileged = true
1997 .uac = UF_TRUSTED_FOR_DELEGATION,
1998 .privilege = SEC_PRIV_ENABLE_DELEGATION,
1999 .delete_is_privileged = true,
2000 .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2003 .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
2004 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2005 .delete_is_privileged = true,
2006 .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2011 if (dsdb_module_am_system(ac->module)) {
2012 return LDB_SUCCESS;
2015 for (i = 0; i < ARRAY_SIZE(map); i++) {
2016 if (user_account_control & map[i].uac) {
2017 need_acl_check = true;
2018 break;
2021 if (need_acl_check == false) {
2022 return LDB_SUCCESS;
2025 user_token = acl_user_token(ac->module);
2026 if (user_token == NULL) {
2027 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2030 ret = dsdb_module_search_dn(ac->module, ac, &res,
2031 domain_dn,
2032 sd_attrs,
2033 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2034 ac->req);
2035 if (ret != LDB_SUCCESS) {
2036 return ret;
2038 if (res->count != 1) {
2039 return ldb_module_operr(ac->module);
2042 ret = dsdb_get_sd_from_ldb_message(ldb,
2043 ac, res->msgs[0], &domain_sd);
2045 if (ret != LDB_SUCCESS) {
2046 return ret;
2049 for (i = 0; i < ARRAY_SIZE(map); i++) {
2050 uint32_t this_uac_new = user_account_control & map[i].uac;
2051 uint32_t this_uac_old = user_account_control_old & map[i].uac;
2052 if (this_uac_new != this_uac_old) {
2053 if (this_uac_old != 0) {
2054 if (map[i].delete_is_privileged == false) {
2055 continue;
2058 if (map[i].oid) {
2059 struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
2060 if (control == NULL) {
2061 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2063 } else if (map[i].privilege != SEC_PRIV_INVALID) {
2064 bool have_priv = security_token_has_privilege(user_token,
2065 map[i].privilege);
2066 if (have_priv == false) {
2067 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2069 } else if (map[i].priv_to_change_from & user_account_control_old) {
2070 bool is_admin = security_token_has_builtin_administrators(user_token);
2071 if (is_admin == false) {
2072 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2074 } else if (map[i].guid) {
2075 ret = acl_check_extended_right(ac, domain_sd,
2076 user_token,
2077 map[i].guid,
2078 SEC_ADS_CONTROL_ACCESS,
2079 sid);
2080 } else {
2081 ret = LDB_SUCCESS;
2083 if (ret != LDB_SUCCESS) {
2084 break;
2088 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2089 switch (ac->req->operation) {
2090 case LDB_ADD:
2091 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2092 "Failed to add %s: %s",
2093 ldb_dn_get_linearized(ac->msg->dn),
2094 map[i].error_string);
2095 break;
2096 case LDB_MODIFY:
2097 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2098 "Failed to modify %s: %s",
2099 ldb_dn_get_linearized(ac->msg->dn),
2100 map[i].error_string);
2101 break;
2102 default:
2103 return ldb_module_operr(ac->module);
2105 if (map[i].guid) {
2106 dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
2107 domain_dn,
2108 true,
2109 10);
2112 return ret;
2115 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
2116 struct dom_sid *sid,
2117 uint32_t req_uac,
2118 uint32_t user_account_control,
2119 uint32_t user_account_control_old)
2121 int ret;
2122 struct dsdb_control_password_user_account_control *uac = NULL;
2124 ret = samldb_check_user_account_control_invariants(ac, user_account_control);
2125 if (ret != LDB_SUCCESS) {
2126 return ret;
2128 ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
2129 if (ret != LDB_SUCCESS) {
2130 return ret;
2133 uac = talloc_zero(ac->req,
2134 struct dsdb_control_password_user_account_control);
2135 if (uac == NULL) {
2136 return ldb_module_oom(ac->module);
2139 uac->req_flags = req_uac;
2140 uac->old_flags = user_account_control_old;
2141 uac->new_flags = user_account_control;
2143 ret = ldb_request_add_control(ac->req,
2144 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
2145 false, uac);
2146 if (ret != LDB_SUCCESS) {
2147 return ret;
2150 return ret;
2155 * This function is called on LDB modify operations. It performs some additions/
2156 * replaces on the current LDB message when "userAccountControl" changes.
2158 static int samldb_user_account_control_change(struct samldb_ctx *ac)
2160 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2161 uint32_t old_uac;
2162 uint32_t new_uac;
2163 uint32_t raw_uac;
2164 uint32_t old_ufa;
2165 uint32_t new_ufa;
2166 uint32_t old_uac_computed;
2167 uint32_t clear_uac;
2168 uint32_t old_atype;
2169 uint32_t new_atype;
2170 uint32_t old_pgrid;
2171 uint32_t new_pgrid;
2172 NTTIME old_lockoutTime;
2173 struct ldb_message_element *el;
2174 struct ldb_val *val;
2175 struct ldb_val computer_val;
2176 struct ldb_message *tmp_msg;
2177 struct dom_sid *sid;
2178 int ret;
2179 struct ldb_result *res;
2180 const char * const attrs[] = {
2181 "objectClass",
2182 "isCriticalSystemObject",
2183 "userAccountControl",
2184 "msDS-User-Account-Control-Computed",
2185 "lockoutTime",
2186 "objectSid",
2187 NULL
2189 bool is_computer = false;
2190 bool old_is_critical = false;
2191 bool new_is_critical = false;
2193 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2194 ac->req->operation);
2195 if (el == NULL || el->num_values == 0) {
2196 ldb_asprintf_errstring(ldb,
2197 "%08X: samldb: 'userAccountControl' can't be deleted!",
2198 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2199 return LDB_ERR_UNWILLING_TO_PERFORM;
2202 /* Create a temporary message for fetching the "userAccountControl" */
2203 tmp_msg = ldb_msg_new(ac->msg);
2204 if (tmp_msg == NULL) {
2205 return ldb_module_oom(ac->module);
2207 ret = ldb_msg_add(tmp_msg, el, 0);
2208 if (ret != LDB_SUCCESS) {
2209 return ret;
2211 raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
2212 "userAccountControl",
2214 talloc_free(tmp_msg);
2216 * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2217 * are only generated and not stored. We ignore them almost
2218 * completely, along with unknown bits and UF_SCRIPT.
2220 * The only exception is ACB_AUTOLOCK, which features in
2221 * clear_acb when the bit is cleared in this modify operation.
2223 * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2224 * ignored by clients and servers
2226 new_uac = raw_uac & UF_SETTABLE_BITS;
2228 /* Fetch the old "userAccountControl" and "objectClass" */
2229 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2230 DSDB_FLAG_NEXT_MODULE, ac->req);
2231 if (ret != LDB_SUCCESS) {
2232 return ret;
2234 old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
2235 if (old_uac == 0) {
2236 return ldb_operr(ldb);
2238 old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
2239 "msDS-User-Account-Control-Computed", 0);
2240 old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
2241 "lockoutTime", 0);
2242 old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
2243 "isCriticalSystemObject", 0);
2244 /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
2245 el = ldb_msg_find_element(res->msgs[0], "objectClass");
2246 if (el == NULL) {
2247 return ldb_operr(ldb);
2249 computer_val = data_blob_string_const("computer");
2250 val = ldb_msg_find_val(el, &computer_val);
2251 if (val != NULL) {
2252 is_computer = true;
2255 old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
2256 old_atype = ds_uf2atype(old_ufa);
2257 old_pgrid = ds_uf2prim_group_rid(old_uac);
2259 new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
2260 if (new_ufa == 0) {
2262 * "userAccountControl" = 0 or missing one of the
2263 * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2264 * 3.1.1.8.10 point 8
2266 new_ufa = UF_NORMAL_ACCOUNT;
2267 new_uac |= new_ufa;
2269 sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2270 if (sid == NULL) {
2271 return ldb_module_operr(ac->module);
2274 ret = samldb_check_user_account_control_rules(ac, sid,
2275 raw_uac,
2276 new_uac,
2277 old_uac);
2278 if (ret != LDB_SUCCESS) {
2279 return ret;
2282 new_atype = ds_uf2atype(new_ufa);
2283 new_pgrid = ds_uf2prim_group_rid(new_uac);
2285 clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
2287 switch (new_ufa) {
2288 case UF_NORMAL_ACCOUNT:
2289 new_is_critical = old_is_critical;
2290 break;
2292 case UF_INTERDOMAIN_TRUST_ACCOUNT:
2293 new_is_critical = true;
2294 break;
2296 case UF_WORKSTATION_TRUST_ACCOUNT:
2297 new_is_critical = false;
2298 if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
2299 if (!is_computer) {
2300 ldb_asprintf_errstring(ldb,
2301 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
2302 "requires objectclass 'computer'!",
2303 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2304 return LDB_ERR_UNWILLING_TO_PERFORM;
2306 new_is_critical = true;
2308 break;
2310 case UF_SERVER_TRUST_ACCOUNT:
2311 if (!is_computer) {
2312 ldb_asprintf_errstring(ldb,
2313 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2314 "requires objectclass 'computer'!",
2315 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2316 return LDB_ERR_UNWILLING_TO_PERFORM;
2318 new_is_critical = true;
2319 break;
2321 default:
2322 ldb_asprintf_errstring(ldb,
2323 "%08X: samldb: invalid userAccountControl[0x%08X]",
2324 W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
2325 return LDB_ERR_OTHER;
2328 if (old_atype != new_atype) {
2329 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2330 "sAMAccountType", new_atype);
2331 if (ret != LDB_SUCCESS) {
2332 return ret;
2334 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2335 el->flags = LDB_FLAG_MOD_REPLACE;
2338 /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
2339 if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
2340 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
2341 ldb_msg_remove_attr(ac->msg, "lockoutTime");
2342 ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
2343 (NTTIME)0);
2344 if (ret != LDB_SUCCESS) {
2345 return ret;
2347 el = ldb_msg_find_element(ac->msg, "lockoutTime");
2348 el->flags = LDB_FLAG_MOD_REPLACE;
2351 /* "isCriticalSystemObject" might be set/changed */
2352 if (old_is_critical != new_is_critical) {
2353 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
2354 new_is_critical ? "TRUE": "FALSE");
2355 if (ret != LDB_SUCCESS) {
2356 return ret;
2358 el = ldb_msg_find_element(ac->msg,
2359 "isCriticalSystemObject");
2360 el->flags = LDB_FLAG_MOD_REPLACE;
2363 if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
2364 (old_pgrid != new_pgrid)) {
2365 /* Older AD deployments don't know about the RODC group */
2366 if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
2367 ret = samldb_prim_group_tester(ac, new_pgrid);
2368 if (ret != LDB_SUCCESS) {
2369 return ret;
2373 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2374 "primaryGroupID", new_pgrid);
2375 if (ret != LDB_SUCCESS) {
2376 return ret;
2378 el = ldb_msg_find_element(ac->msg,
2379 "primaryGroupID");
2380 el->flags = LDB_FLAG_MOD_REPLACE;
2383 /* Propagate eventual "userAccountControl" attribute changes */
2384 if (old_uac != new_uac) {
2385 char *tempstr = talloc_asprintf(ac->msg, "%d",
2386 new_uac);
2387 if (tempstr == NULL) {
2388 return ldb_module_oom(ac->module);
2391 /* Overwrite "userAccountControl" correctly */
2392 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2393 ac->req->operation);
2394 el->values[0].data = (uint8_t *) tempstr;
2395 el->values[0].length = strlen(tempstr);
2396 } else {
2397 ldb_msg_remove_attr(ac->msg, "userAccountControl");
2400 return LDB_SUCCESS;
2403 static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
2404 struct dom_sid *sid)
2406 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2407 int ret = 0;
2408 struct ldb_result *res = NULL;
2409 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
2410 struct security_token *user_token = NULL;
2411 struct security_descriptor *domain_sd = NULL;
2412 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2413 const char *operation = "";
2415 if (dsdb_module_am_system(ac->module)) {
2416 return LDB_SUCCESS;
2419 switch (ac->req->operation) {
2420 case LDB_ADD:
2421 operation = "add";
2422 break;
2423 case LDB_MODIFY:
2424 operation = "modify";
2425 break;
2426 default:
2427 return ldb_module_operr(ac->module);
2430 user_token = acl_user_token(ac->module);
2431 if (user_token == NULL) {
2432 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2435 ret = dsdb_module_search_dn(ac->module, ac, &res,
2436 domain_dn,
2437 sd_attrs,
2438 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2439 ac->req);
2440 if (ret != LDB_SUCCESS) {
2441 return ret;
2443 if (res->count != 1) {
2444 return ldb_module_operr(ac->module);
2447 ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
2448 if (ret != LDB_SUCCESS) {
2449 return ret;
2452 ret = acl_check_extended_right(ac, domain_sd,
2453 user_token,
2454 GUID_DRS_UNEXPIRE_PASSWORD,
2455 SEC_ADS_CONTROL_ACCESS,
2456 sid);
2457 if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2458 return ret;
2461 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
2462 "Failed to %s %s: "
2463 "Setting pwdLastSet to -1 requires the "
2464 "Unexpire-Password right that was not given "
2465 "on the Domain object",
2466 operation,
2467 ldb_dn_get_linearized(ac->msg->dn));
2468 dsdb_acl_debug(domain_sd, user_token,
2469 domain_dn, true, 10);
2471 return ret;
2475 * This function is called on LDB modify operations. It performs some additions/
2476 * replaces on the current LDB message when "pwdLastSet" changes.
2478 static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
2480 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2481 NTTIME last_set = 0;
2482 struct ldb_message_element *el = NULL;
2483 struct ldb_message *tmp_msg = NULL;
2484 struct dom_sid *self_sid = NULL;
2485 int ret;
2486 struct ldb_result *res = NULL;
2487 const char * const attrs[] = {
2488 "objectSid",
2489 NULL
2492 el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
2493 ac->req->operation);
2494 if (el == NULL || el->num_values == 0) {
2495 ldb_asprintf_errstring(ldb,
2496 "%08X: samldb: 'pwdLastSet' can't be deleted!",
2497 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2498 return LDB_ERR_UNWILLING_TO_PERFORM;
2501 /* Create a temporary message for fetching the "userAccountControl" */
2502 tmp_msg = ldb_msg_new(ac->msg);
2503 if (tmp_msg == NULL) {
2504 return ldb_module_oom(ac->module);
2506 ret = ldb_msg_add(tmp_msg, el, 0);
2507 if (ret != LDB_SUCCESS) {
2508 return ret;
2510 last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
2511 talloc_free(tmp_msg);
2514 * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
2516 if (last_set != UINT64_MAX) {
2517 return LDB_SUCCESS;
2520 /* Fetch the "objectSid" */
2521 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2522 DSDB_FLAG_NEXT_MODULE, ac->req);
2523 if (ret != LDB_SUCCESS) {
2524 return ret;
2526 self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2527 if (self_sid == NULL) {
2528 return ldb_module_operr(ac->module);
2531 ret = samldb_check_pwd_last_set_acl(ac, self_sid);
2532 if (ret != LDB_SUCCESS) {
2533 return ret;
2536 return LDB_SUCCESS;
2539 static int samldb_lockout_time(struct samldb_ctx *ac)
2541 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2542 NTTIME lockoutTime;
2543 struct ldb_message_element *el;
2544 struct ldb_message *tmp_msg;
2545 int ret;
2547 el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
2548 ac->req->operation);
2549 if (el == NULL || el->num_values == 0) {
2550 ldb_asprintf_errstring(ldb,
2551 "%08X: samldb: 'lockoutTime' can't be deleted!",
2552 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2553 return LDB_ERR_UNWILLING_TO_PERFORM;
2556 /* Create a temporary message for fetching the "lockoutTime" */
2557 tmp_msg = ldb_msg_new(ac->msg);
2558 if (tmp_msg == NULL) {
2559 return ldb_module_oom(ac->module);
2561 ret = ldb_msg_add(tmp_msg, el, 0);
2562 if (ret != LDB_SUCCESS) {
2563 return ret;
2565 lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
2566 "lockoutTime",
2568 talloc_free(tmp_msg);
2570 if (lockoutTime != 0) {
2571 return LDB_SUCCESS;
2574 /* lockoutTime == 0 resets badPwdCount */
2575 ldb_msg_remove_attr(ac->msg, "badPwdCount");
2576 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
2577 "badPwdCount", 0);
2578 if (ret != LDB_SUCCESS) {
2579 return ret;
2581 el = ldb_msg_find_element(ac->msg, "badPwdCount");
2582 el->flags = LDB_FLAG_MOD_REPLACE;
2584 return LDB_SUCCESS;
2587 static int samldb_group_type_change(struct samldb_ctx *ac)
2589 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2590 uint32_t group_type, old_group_type, account_type;
2591 struct ldb_message_element *el;
2592 struct ldb_message *tmp_msg;
2593 int ret;
2594 struct ldb_result *res;
2595 const char * const attrs[] = { "groupType", NULL };
2597 el = dsdb_get_single_valued_attr(ac->msg, "groupType",
2598 ac->req->operation);
2599 if (el == NULL) {
2600 /* we are not affected */
2601 return LDB_SUCCESS;
2604 /* Create a temporary message for fetching the "groupType" */
2605 tmp_msg = ldb_msg_new(ac->msg);
2606 if (tmp_msg == NULL) {
2607 return ldb_module_oom(ac->module);
2609 ret = ldb_msg_add(tmp_msg, el, 0);
2610 if (ret != LDB_SUCCESS) {
2611 return ret;
2613 group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
2614 talloc_free(tmp_msg);
2616 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2617 DSDB_FLAG_NEXT_MODULE |
2618 DSDB_SEARCH_SHOW_DELETED, ac->req);
2619 if (ret != LDB_SUCCESS) {
2620 return ret;
2622 old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
2623 if (old_group_type == 0) {
2624 return ldb_operr(ldb);
2627 /* Group type switching isn't so easy as it seems: We can only
2628 * change in this directions: global <-> universal <-> local
2629 * On each step also the group type itself
2630 * (security/distribution) is variable. */
2632 if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
2633 switch (group_type) {
2634 case GTYPE_SECURITY_GLOBAL_GROUP:
2635 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
2636 /* change to "universal" allowed */
2637 if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
2638 (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
2639 ldb_set_errstring(ldb,
2640 "samldb: Change from security/distribution local group forbidden!");
2641 return LDB_ERR_UNWILLING_TO_PERFORM;
2643 break;
2645 case GTYPE_SECURITY_UNIVERSAL_GROUP:
2646 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
2647 /* each change allowed */
2648 break;
2649 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
2650 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
2651 /* change to "universal" allowed */
2652 if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
2653 (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
2654 ldb_set_errstring(ldb,
2655 "samldb: Change from security/distribution global group forbidden!");
2656 return LDB_ERR_UNWILLING_TO_PERFORM;
2658 break;
2660 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
2661 default:
2662 /* we don't allow this "groupType" values */
2663 return LDB_ERR_UNWILLING_TO_PERFORM;
2664 break;
2668 account_type = ds_gtype2atype(group_type);
2669 if (account_type == 0) {
2670 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
2671 return LDB_ERR_UNWILLING_TO_PERFORM;
2673 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
2674 account_type);
2675 if (ret != LDB_SUCCESS) {
2676 return ret;
2678 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2679 el->flags = LDB_FLAG_MOD_REPLACE;
2681 return LDB_SUCCESS;
2684 static int samldb_member_check(struct samldb_ctx *ac)
2686 const char * const attrs[] = { "objectSid", NULL };
2687 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2688 struct ldb_message_element *el;
2689 struct ldb_dn *member_dn;
2690 struct dom_sid *sid;
2691 struct ldb_result *res;
2692 struct dom_sid *group_sid;
2693 unsigned int i, j;
2694 int ret;
2696 /* Fetch information from the existing object */
2698 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2699 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
2700 if (ret != LDB_SUCCESS) {
2701 return ret;
2703 if (res->count != 1) {
2704 return ldb_operr(ldb);
2707 group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2708 if (group_sid == NULL) {
2709 return ldb_operr(ldb);
2712 /* We've to walk over all modification entries and consider the "member"
2713 * ones. */
2714 for (i = 0; i < ac->msg->num_elements; i++) {
2715 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
2716 continue;
2719 el = &ac->msg->elements[i];
2720 for (j = 0; j < el->num_values; j++) {
2721 struct ldb_result *group_res;
2722 const char *group_attrs[] = { "primaryGroupID" , NULL };
2723 uint32_t prim_group_rid;
2725 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2726 /* Deletes will be handled in
2727 * repl_meta_data, and deletes not
2728 * matching a member will return
2729 * LDB_ERR_UNWILLING_TO_PERFORM
2730 * there */
2731 continue;
2734 member_dn = ldb_dn_from_ldb_val(ac, ldb,
2735 &el->values[j]);
2736 if (!ldb_dn_validate(member_dn)) {
2737 return ldb_operr(ldb);
2740 /* Denies to add "member"s to groups which are primary
2741 * ones for them - in this case return
2742 * ERR_ENTRY_ALREADY_EXISTS. */
2744 ret = dsdb_module_search_dn(ac->module, ac, &group_res,
2745 member_dn, group_attrs,
2746 DSDB_FLAG_NEXT_MODULE, ac->req);
2747 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2748 /* member DN doesn't exist yet */
2749 continue;
2751 if (ret != LDB_SUCCESS) {
2752 return ret;
2754 prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
2755 if (prim_group_rid == (uint32_t) -1) {
2756 /* the member hasn't to be a user account ->
2757 * therefore no check needed in this case. */
2758 continue;
2761 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
2762 prim_group_rid);
2763 if (sid == NULL) {
2764 return ldb_operr(ldb);
2767 if (dom_sid_equal(group_sid, sid)) {
2768 ldb_asprintf_errstring(ldb,
2769 "samldb: member %s already set via primaryGroupID %u",
2770 ldb_dn_get_linearized(member_dn), prim_group_rid);
2771 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2776 talloc_free(res);
2778 return LDB_SUCCESS;
2781 /* SAM objects have special rules regarding the "description" attribute on
2782 * modify operations. */
2783 static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
2785 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2786 const char * const attrs[] = { "objectClass", "description", NULL };
2787 struct ldb_result *res;
2788 unsigned int i;
2789 int ret;
2791 /* Fetch information from the existing object */
2792 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2793 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
2794 "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
2795 if (ret != LDB_SUCCESS) {
2796 /* don't treat it specially ... let normal error codes
2797 happen from other places */
2798 ldb_reset_err_string(ldb);
2799 return LDB_SUCCESS;
2801 if (res->count == 0) {
2802 /* we didn't match the filter */
2803 talloc_free(res);
2804 return LDB_SUCCESS;
2807 /* We've to walk over all modification entries and consider the
2808 * "description" ones. */
2809 for (i = 0; i < ac->msg->num_elements; i++) {
2810 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
2811 ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
2812 *modified = true;
2816 talloc_free(res);
2818 return LDB_SUCCESS;
2821 /* This trigger adapts the "servicePrincipalName" attributes if the
2822 * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
2823 static int samldb_service_principal_names_change(struct samldb_ctx *ac)
2825 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2826 struct ldb_message_element *el = NULL, *el2 = NULL;
2827 struct ldb_message *msg;
2828 const char * const attrs[] = { "servicePrincipalName", NULL };
2829 struct ldb_result *res;
2830 const char *dns_hostname = NULL, *old_dns_hostname = NULL,
2831 *sam_accountname = NULL, *old_sam_accountname = NULL;
2832 unsigned int i, j;
2833 int ret;
2835 el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
2836 ac->req->operation);
2837 el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
2838 ac->req->operation);
2839 if ((el == NULL) && (el2 == NULL)) {
2840 /* we are not affected */
2841 return LDB_SUCCESS;
2844 /* Create a temporary message for fetching the "dNSHostName" */
2845 if (el != NULL) {
2846 const char *dns_attrs[] = { "dNSHostName", NULL };
2847 msg = ldb_msg_new(ac->msg);
2848 if (msg == NULL) {
2849 return ldb_module_oom(ac->module);
2851 ret = ldb_msg_add(msg, el, 0);
2852 if (ret != LDB_SUCCESS) {
2853 return ret;
2855 dns_hostname = talloc_strdup(ac,
2856 ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
2857 if (dns_hostname == NULL) {
2858 return ldb_module_oom(ac->module);
2861 talloc_free(msg);
2863 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
2864 dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
2865 if (ret == LDB_SUCCESS) {
2866 old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
2870 /* Create a temporary message for fetching the "sAMAccountName" */
2871 if (el2 != NULL) {
2872 char *tempstr, *tempstr2 = NULL;
2873 const char *acct_attrs[] = { "sAMAccountName", NULL };
2875 msg = ldb_msg_new(ac->msg);
2876 if (msg == NULL) {
2877 return ldb_module_oom(ac->module);
2879 ret = ldb_msg_add(msg, el2, 0);
2880 if (ret != LDB_SUCCESS) {
2881 return ret;
2883 tempstr = talloc_strdup(ac,
2884 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
2885 talloc_free(msg);
2887 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
2888 DSDB_FLAG_NEXT_MODULE, ac->req);
2889 if (ret == LDB_SUCCESS) {
2890 tempstr2 = talloc_strdup(ac,
2891 ldb_msg_find_attr_as_string(res->msgs[0],
2892 "sAMAccountName", NULL));
2896 /* The "sAMAccountName" needs some additional trimming: we need
2897 * to remove the trailing "$"s if they exist. */
2898 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
2899 (tempstr[strlen(tempstr) - 1] == '$')) {
2900 tempstr[strlen(tempstr) - 1] = '\0';
2902 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
2903 (tempstr2[strlen(tempstr2) - 1] == '$')) {
2904 tempstr2[strlen(tempstr2) - 1] = '\0';
2906 sam_accountname = tempstr;
2907 old_sam_accountname = tempstr2;
2910 if (old_dns_hostname == NULL) {
2911 /* we cannot change when the old name is unknown */
2912 dns_hostname = NULL;
2914 if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
2915 (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
2916 /* The "dNSHostName" didn't change */
2917 dns_hostname = NULL;
2920 if (old_sam_accountname == NULL) {
2921 /* we cannot change when the old name is unknown */
2922 sam_accountname = NULL;
2924 if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
2925 (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
2926 /* The "sAMAccountName" didn't change */
2927 sam_accountname = NULL;
2930 if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
2931 /* Well, there are information missing (old name(s)) or the
2932 * names didn't change. We've nothing to do and can exit here */
2933 return LDB_SUCCESS;
2936 /* Potential "servicePrincipalName" changes in the same request have to
2937 * be handled before the update (Windows behaviour). */
2938 el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
2939 if (el != NULL) {
2940 msg = ldb_msg_new(ac->msg);
2941 if (msg == NULL) {
2942 return ldb_module_oom(ac->module);
2944 msg->dn = ac->msg->dn;
2946 do {
2947 ret = ldb_msg_add(msg, el, el->flags);
2948 if (ret != LDB_SUCCESS) {
2949 return ret;
2952 ldb_msg_remove_element(ac->msg, el);
2954 el = ldb_msg_find_element(ac->msg,
2955 "servicePrincipalName");
2956 } while (el != NULL);
2958 ret = dsdb_module_modify(ac->module, msg,
2959 DSDB_FLAG_NEXT_MODULE, ac->req);
2960 if (ret != LDB_SUCCESS) {
2961 return ret;
2963 talloc_free(msg);
2966 /* Fetch the "servicePrincipalName"s if any */
2967 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2968 DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
2969 if (ret != LDB_SUCCESS) {
2970 return ret;
2972 if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
2973 return ldb_operr(ldb);
2976 if (res->msgs[0]->num_elements == 1) {
2978 * Yes, we do have "servicePrincipalName"s. First we update them
2979 * locally, that means we do always substitute the current
2980 * "dNSHostName" with the new one and/or "sAMAccountName"
2981 * without "$" with the new one and then we append the
2982 * modified "servicePrincipalName"s as a message element
2983 * replace to the modification request (Windows behaviour). We
2984 * need also to make sure that the values remain case-
2985 * insensitively unique.
2988 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
2989 LDB_FLAG_MOD_REPLACE, &el);
2990 if (ret != LDB_SUCCESS) {
2991 return ret;
2994 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
2995 char *old_str, *new_str;
2996 char *pos = NULL;
2997 const char *tok;
2998 struct ldb_val *vals;
2999 bool found = false;
3001 old_str = (char *)
3002 res->msgs[0]->elements[0].values[i].data;
3004 new_str = talloc_strdup(ac->msg,
3005 strtok_r(old_str, "/", &pos));
3006 if (new_str == NULL) {
3007 return ldb_module_oom(ac->module);
3010 while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
3011 if ((dns_hostname != NULL) &&
3012 (strcasecmp_m(tok, old_dns_hostname) == 0)) {
3013 tok = dns_hostname;
3015 if ((sam_accountname != NULL) &&
3016 (strcasecmp_m(tok, old_sam_accountname) == 0)) {
3017 tok = sam_accountname;
3020 new_str = talloc_asprintf(ac->msg, "%s/%s",
3021 new_str, tok);
3022 if (new_str == NULL) {
3023 return ldb_module_oom(ac->module);
3027 /* Uniqueness check */
3028 for (j = 0; (!found) && (j < el->num_values); j++) {
3029 if (strcasecmp_m((char *)el->values[j].data,
3030 new_str) == 0) {
3031 found = true;
3034 if (found) {
3035 continue;
3039 * append the new "servicePrincipalName" -
3040 * code derived from ldb_msg_add_value().
3042 * Open coded to make it clear that we must
3043 * append to the MOD_REPLACE el created above.
3045 vals = talloc_realloc(ac->msg, el->values,
3046 struct ldb_val,
3047 el->num_values + 1);
3048 if (vals == NULL) {
3049 return ldb_module_oom(ac->module);
3051 el->values = vals;
3052 el->values[el->num_values] = data_blob_string_const(new_str);
3053 ++(el->num_values);
3057 talloc_free(res);
3059 return LDB_SUCCESS;
3062 /* This checks the "fSMORoleOwner" attributes */
3063 static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
3065 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3066 const char * const no_attrs[] = { NULL };
3067 struct ldb_message_element *el;
3068 struct ldb_message *tmp_msg;
3069 struct ldb_dn *res_dn;
3070 struct ldb_result *res;
3071 int ret;
3073 el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
3074 ac->req->operation);
3075 if (el == NULL) {
3076 /* we are not affected */
3077 return LDB_SUCCESS;
3080 /* Create a temporary message for fetching the "fSMORoleOwner" */
3081 tmp_msg = ldb_msg_new(ac->msg);
3082 if (tmp_msg == NULL) {
3083 return ldb_module_oom(ac->module);
3085 ret = ldb_msg_add(tmp_msg, el, 0);
3086 if (ret != LDB_SUCCESS) {
3087 return ret;
3089 res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
3090 talloc_free(tmp_msg);
3092 if (res_dn == NULL) {
3093 ldb_set_errstring(ldb,
3094 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3095 if (ac->req->operation == LDB_ADD) {
3096 return LDB_ERR_CONSTRAINT_VIOLATION;
3097 } else {
3098 return LDB_ERR_UNWILLING_TO_PERFORM;
3102 /* Fetched DN has to reference a "nTDSDSA" entry */
3103 ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
3104 no_attrs,
3105 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3106 ac->req, "(objectClass=nTDSDSA)");
3107 if (ret != LDB_SUCCESS) {
3108 return ret;
3110 if (res->count != 1) {
3111 ldb_set_errstring(ldb,
3112 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3113 return LDB_ERR_UNWILLING_TO_PERFORM;
3116 talloc_free(res);
3118 return LDB_SUCCESS;
3122 * Return zero if the number of zero bits in the address (looking from low to
3123 * high) is equal to or greater than the length minus the mask. Otherwise it
3124 * returns -1.
3126 static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
3127 unsigned int mask)
3129 /* <address> is an integer in big-endian form, <len> bits long. All
3130 bits between <mask> and <len> must be zero. */
3131 int i;
3132 unsigned int byte_len;
3133 unsigned int byte_mask;
3134 unsigned int bit_mask;
3135 if (len == 32) {
3136 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
3137 address[0], address[1], address[2], address[3],
3138 mask);
3139 } else if (len == 128){
3140 DBG_INFO("Looking at address "
3141 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
3142 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
3143 address[0], address[1], address[2], address[3],
3144 address[4], address[5], address[6], address[7],
3145 address[8], address[9], address[10], address[11],
3146 address[12], address[13], address[14], address[15],
3147 mask);
3150 if (mask > len){
3151 DBG_INFO("mask %u is too big (> %u)\n", mask, len);
3152 return -1;
3154 if (mask == len){
3155 /* single address subnet.
3156 * In IPv4 all 255s is invalid by the bitmask != address rule
3157 * in MS-ADTS. IPv6 does not suffer.
3159 if (len == 32){
3160 if (address[0] == 255 &&
3161 address[1] == 255 &&
3162 address[2] == 255 &&
3163 address[3] == 255){
3164 return -1;
3167 return 0;
3170 byte_len = len / 8;
3171 byte_mask = mask / 8;
3173 for (i = byte_len - 1; i > byte_mask; i--){
3174 DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
3175 if (address[i] != 0){
3176 return -1;
3179 bit_mask = (1 << (8 - (mask & 7))) - 1;
3180 DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
3181 bit_mask & address[byte_mask]);
3182 if (address[byte_mask] & bit_mask){
3183 return -1;
3186 /* According to MS-ADTS, the mask can't exactly equal the bitmask for
3187 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
3188 * because the bitmask implied by "/17" is 255.255.80.0.
3190 * The bit_mask used in the previous check is the complement of what
3191 * we want here.
3193 if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
3194 bool ok = false;
3195 for (i = 0; i < byte_mask; i++){
3196 if (address[i] != 255){
3197 ok = true;
3198 break;
3201 if (ok == false){
3202 return -1;
3205 return 0;
3210 static int check_address_roundtrip(const char *address, int family,
3211 const uint8_t *address_bytes,
3212 char *buffer, int buffer_len)
3215 * Check that the address is in the canonical RFC5952 format for IPv6,
3216 * and lacks extra leading zeros for each dotted decimal for IPv4.
3217 * Handily this is what inet_ntop() gives you.
3219 const char *address_redux = inet_ntop(family, address_bytes,
3220 buffer, buffer_len);
3221 if (address_redux == NULL){
3222 DBG_INFO("Address round trip %s failed unexpectedly"
3223 " with errno %d\n", address, errno);
3224 return -1;
3226 if (strcasecmp(address, address_redux) != 0){
3227 DBG_INFO("Address %s round trips to %s; fail!\n",
3228 address, address_redux);
3229 /* If the address family is IPv6, and the address is in a
3230 certain range
3233 if (strchr(address_redux, '.') != NULL){
3234 DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
3235 "lying in a range that was once used for "
3236 "IPv4 embedding (that is, it might also be "
3237 "represented as '%s').\n", address,
3238 address_redux));
3240 return -1;
3242 return 0;
3248 * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
3249 * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
3250 * CIDR address range without saying so explicitly. Here we follow the CIDR
3251 * spec.
3253 * Return 0 on success, -1 on error.
3255 static int verify_cidr(const char *cidr)
3257 char *address = NULL, *slash = NULL, *endptr = NULL;
3258 bool has_colon, has_dot;
3259 int res, ret;
3260 unsigned long mask;
3261 uint8_t *address_bytes = NULL;
3262 char *address_redux = NULL;
3263 unsigned int address_len;
3264 TALLOC_CTX *frame = NULL;
3266 DBG_DEBUG("CIDR is %s\n", cidr);
3267 frame = talloc_stackframe();
3268 address = talloc_strdup(frame, cidr);
3269 if (address == NULL){
3270 goto error;
3273 /* there must be a '/' */
3274 slash = strchr(address, '/');
3275 if (slash == NULL){
3276 goto error;
3278 /* terminate the address for strchr, inet_pton */
3279 *slash = '\0';
3281 mask = strtoul(slash + 1, &endptr, 10);
3282 if (mask == 0){
3283 DBG_INFO("Windows does not like the zero mask, "
3284 "so nor do we: %s\n", cidr);
3285 goto error;
3288 if (*endptr != '\0' || endptr == slash + 1){
3289 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
3290 goto error;
3293 address_bytes = talloc_size(frame, sizeof(struct in6_addr));
3294 if (address_bytes == NULL){
3295 goto error;
3298 address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
3299 if (address_redux == NULL){
3300 goto error;
3303 DBG_INFO("found address %s, mask %lu\n", address, mask);
3304 has_colon = (strchr(address, ':') == NULL) ? false : true;
3305 has_dot = (strchr(address, '.') == NULL) ? false : true;
3306 if (has_dot && has_colon){
3307 /* This seems to be an IPv4 address embedded in IPv6, which is
3308 icky. We don't support it. */
3309 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
3310 cidr);
3311 goto error;
3312 } else if (has_colon){ /* looks like IPv6 */
3313 res = inet_pton(AF_INET6, address, address_bytes);
3314 if (res != 1) {
3315 DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
3316 goto error;
3318 address_len = 128;
3319 if (check_address_roundtrip(address, AF_INET6, address_bytes,
3320 address_redux, INET6_ADDRSTRLEN)){
3321 goto error;
3323 } else if (has_dot) {
3324 /* looks like IPv4 */
3325 if (strcmp(address, "0.0.0.0") == 0){
3326 DBG_INFO("Windows does not like the zero IPv4 address, "
3327 "so nor do we.\n");
3328 goto error;
3330 res = inet_pton(AF_INET, address, address_bytes);
3331 if (res != 1) {
3332 DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
3333 goto error;
3335 address_len = 32;
3337 if (check_address_roundtrip(address, AF_INET, address_bytes,
3338 address_redux, INET_ADDRSTRLEN)){
3339 goto error;
3341 } else {
3342 /* This doesn't look like an IP address at all. */
3343 goto error;
3346 ret = check_cidr_zero_bits(address_bytes, address_len, mask);
3347 talloc_free(frame);
3348 return ret;
3349 error:
3350 talloc_free(frame);
3351 return -1;
3355 static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
3357 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3358 const char *cidr = NULL;
3359 const struct ldb_val *rdn_value = NULL;
3361 rdn_value = ldb_dn_get_rdn_val(dn);
3362 if (rdn_value == NULL) {
3363 ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
3364 "failed");
3365 return LDB_ERR_UNWILLING_TO_PERFORM;
3368 cidr = ldb_dn_escape_value(ac, *rdn_value);
3369 DBG_INFO("looking at cidr '%s'\n", cidr);
3370 if (cidr == NULL) {
3371 ldb_set_errstring(ldb,
3372 "samldb: adding an empty subnet cidr seems wrong");
3373 return LDB_ERR_UNWILLING_TO_PERFORM;
3376 if (verify_cidr(cidr)){
3377 ldb_set_errstring(ldb,
3378 "samldb: subnet value is invalid");
3379 return LDB_ERR_INVALID_DN_SYNTAX;
3382 return LDB_SUCCESS;
3385 static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
3386 struct ldb_dn *dn)
3388 bool rodc = false;
3389 struct loadparm_context *lp_ctx;
3390 char *referral;
3391 int ret;
3392 WERROR err;
3394 if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
3395 ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
3396 return NULL;
3399 ret = samdb_rodc(ldb, &rodc);
3400 if (ret != LDB_SUCCESS) {
3401 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
3402 return NULL;
3405 if (rodc) {
3406 const char *domain = NULL;
3407 struct ldb_dn *fsmo_role_dn;
3408 struct ldb_dn *role_owner_dn;
3409 ldb_set_errstring(ldb, "RODC modify is forbidden!");
3410 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3411 struct loadparm_context);
3413 err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3414 &fsmo_role_dn, &role_owner_dn);
3415 if (W_ERROR_IS_OK(err)) {
3416 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3417 if (server_dn != NULL) {
3418 ldb_dn_remove_child_components(server_dn, 1);
3420 domain = samdb_dn_to_dnshostname(ldb, req,
3421 server_dn);
3424 if (domain == NULL) {
3425 domain = lpcfg_dnsdomain(lp_ctx);
3427 referral = talloc_asprintf(req,
3428 "ldap://%s/%s",
3429 domain,
3430 ldb_dn_get_linearized(dn));
3431 return referral;
3434 return NULL;
3438 /* add */
3439 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
3441 struct ldb_context *ldb;
3442 struct samldb_ctx *ac;
3443 struct ldb_message_element *el;
3444 int ret;
3445 char *referral = NULL;
3447 ldb = ldb_module_get_ctx(module);
3448 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
3450 /* do not manipulate our control entries */
3451 if (ldb_dn_is_special(req->op.add.message->dn)) {
3452 return ldb_next_request(module, req);
3455 referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
3456 if (referral != NULL) {
3457 ret = ldb_module_send_referral(req, referral);
3458 return ret;
3461 el = ldb_msg_find_element(req->op.add.message, "userParameters");
3462 if (el != NULL && ldb_req_is_untrusted(req)) {
3463 const char *reason = "samldb_add: "
3464 "setting userParameters is not supported over LDAP, "
3465 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3466 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3467 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3470 ac = samldb_ctx_init(module, req);
3471 if (ac == NULL) {
3472 return ldb_operr(ldb);
3475 /* build the new msg */
3476 ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
3477 if (ac->msg == NULL) {
3478 talloc_free(ac);
3479 ldb_debug(ldb, LDB_DEBUG_FATAL,
3480 "samldb_add: ldb_msg_copy_shallow failed!\n");
3481 return ldb_operr(ldb);
3484 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3485 if (el != NULL) {
3486 ret = samldb_fsmo_role_owner_check(ac);
3487 if (ret != LDB_SUCCESS) {
3488 return ret;
3492 if (samdb_find_attribute(ldb, ac->msg,
3493 "objectclass", "user") != NULL) {
3494 ac->type = SAMLDB_TYPE_USER;
3496 ret = samldb_prim_group_trigger(ac);
3497 if (ret != LDB_SUCCESS) {
3498 return ret;
3501 ret = samldb_objectclass_trigger(ac);
3502 if (ret != LDB_SUCCESS) {
3503 return ret;
3506 return samldb_fill_object(ac);
3509 if (samdb_find_attribute(ldb, ac->msg,
3510 "objectclass", "group") != NULL) {
3511 ac->type = SAMLDB_TYPE_GROUP;
3513 ret = samldb_objectclass_trigger(ac);
3514 if (ret != LDB_SUCCESS) {
3515 return ret;
3518 return samldb_fill_object(ac);
3521 /* perhaps a foreignSecurityPrincipal? */
3522 if (samdb_find_attribute(ldb, ac->msg,
3523 "objectclass",
3524 "foreignSecurityPrincipal") != NULL) {
3525 return samldb_fill_foreignSecurityPrincipal_object(ac);
3528 if (samdb_find_attribute(ldb, ac->msg,
3529 "objectclass", "classSchema") != NULL) {
3530 ac->type = SAMLDB_TYPE_CLASS;
3532 /* If in provision, these checks are too slow to do */
3533 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3534 ret = samldb_schema_governsid_valid_check(ac);
3535 if (ret != LDB_SUCCESS) {
3536 return ret;
3540 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3541 if (ret != LDB_SUCCESS) {
3542 return ret;
3545 ret = samldb_schema_info_update(ac);
3546 if (ret != LDB_SUCCESS) {
3547 talloc_free(ac);
3548 return ret;
3551 return samldb_fill_object(ac);
3554 if (samdb_find_attribute(ldb, ac->msg,
3555 "objectclass", "attributeSchema") != NULL) {
3556 ac->type = SAMLDB_TYPE_ATTRIBUTE;
3558 /* If in provision, these checks are too slow to do */
3559 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3560 ret = samldb_schema_attributeid_valid_check(ac);
3561 if (ret != LDB_SUCCESS) {
3562 return ret;
3565 ret = samldb_schema_add_handle_linkid(ac);
3566 if (ret != LDB_SUCCESS) {
3567 return ret;
3570 ret = samldb_schema_add_handle_mapiid(ac);
3571 if (ret != LDB_SUCCESS) {
3572 return ret;
3576 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3577 if (ret != LDB_SUCCESS) {
3578 return ret;
3581 ret = samldb_schema_info_update(ac);
3582 if (ret != LDB_SUCCESS) {
3583 talloc_free(ac);
3584 return ret;
3587 return samldb_fill_object(ac);
3590 if (samdb_find_attribute(ldb, ac->msg,
3591 "objectclass", "subnet") != NULL) {
3592 ret = samldb_verify_subnet(ac, ac->msg->dn);
3593 if (ret != LDB_SUCCESS) {
3594 talloc_free(ac);
3595 return ret;
3597 /* We are just checking the value is valid, and there are no
3598 values to fill in. */
3601 talloc_free(ac);
3603 /* nothing matched, go on */
3604 return ldb_next_request(module, req);
3607 /* modify */
3608 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
3610 struct ldb_context *ldb;
3611 struct samldb_ctx *ac;
3612 struct ldb_message_element *el, *el2;
3613 struct ldb_control *is_undelete;
3614 bool modified = false;
3615 int ret;
3617 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3618 /* do not manipulate our control entries */
3619 return ldb_next_request(module, req);
3622 ldb = ldb_module_get_ctx(module);
3625 * we are going to need some special handling if in Undelete call.
3626 * Since tombstone_reanimate module will restore certain attributes,
3627 * we need to relax checks for: sAMAccountType, primaryGroupID
3629 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3631 /* make sure that "objectSid" is not specified */
3632 el = ldb_msg_find_element(req->op.mod.message, "objectSid");
3633 if (el != NULL) {
3634 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
3635 ldb_set_errstring(ldb,
3636 "samldb: objectSid must not be specified!");
3637 return LDB_ERR_UNWILLING_TO_PERFORM;
3640 if (is_undelete == NULL) {
3641 /* make sure that "sAMAccountType" is not specified */
3642 el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
3643 if (el != NULL) {
3644 ldb_set_errstring(ldb,
3645 "samldb: sAMAccountType must not be specified!");
3646 return LDB_ERR_UNWILLING_TO_PERFORM;
3649 /* make sure that "isCriticalSystemObject" is not specified */
3650 el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
3651 if (el != NULL) {
3652 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
3653 ldb_set_errstring(ldb,
3654 "samldb: isCriticalSystemObject must not be specified!");
3655 return LDB_ERR_UNWILLING_TO_PERFORM;
3659 /* msDS-IntId is not allowed to be modified
3660 * except when modification comes from replication */
3661 if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
3662 if (!ldb_request_get_control(req,
3663 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
3664 return LDB_ERR_CONSTRAINT_VIOLATION;
3668 el = ldb_msg_find_element(req->op.mod.message, "userParameters");
3669 if (el != NULL && ldb_req_is_untrusted(req)) {
3670 const char *reason = "samldb: "
3671 "setting userParameters is not supported over LDAP, "
3672 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3673 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3674 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3677 ac = samldb_ctx_init(module, req);
3678 if (ac == NULL) {
3679 return ldb_operr(ldb);
3682 /* build the new msg */
3683 ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3684 if (ac->msg == NULL) {
3685 talloc_free(ac);
3686 ldb_debug(ldb, LDB_DEBUG_FATAL,
3687 "samldb_modify: ldb_msg_copy_shallow failed!\n");
3688 return ldb_operr(ldb);
3691 if (is_undelete == NULL) {
3692 el = ldb_msg_find_element(ac->msg, "primaryGroupID");
3693 if (el != NULL) {
3694 ret = samldb_prim_group_trigger(ac);
3695 if (ret != LDB_SUCCESS) {
3696 return ret;
3701 el = ldb_msg_find_element(ac->msg, "userAccountControl");
3702 if (el != NULL) {
3703 modified = true;
3704 ret = samldb_user_account_control_change(ac);
3705 if (ret != LDB_SUCCESS) {
3706 return ret;
3710 el = ldb_msg_find_element(ac->msg, "pwdLastSet");
3711 if (el != NULL) {
3712 modified = true;
3713 ret = samldb_pwd_last_set_change(ac);
3714 if (ret != LDB_SUCCESS) {
3715 return ret;
3719 el = ldb_msg_find_element(ac->msg, "lockoutTime");
3720 if (el != NULL) {
3721 modified = true;
3722 ret = samldb_lockout_time(ac);
3723 if (ret != LDB_SUCCESS) {
3724 return ret;
3728 el = ldb_msg_find_element(ac->msg, "groupType");
3729 if (el != NULL) {
3730 modified = true;
3731 ret = samldb_group_type_change(ac);
3732 if (ret != LDB_SUCCESS) {
3733 return ret;
3737 el = ldb_msg_find_element(ac->msg, "sAMAccountName");
3738 if (el != NULL) {
3739 ret = samldb_sam_accountname_valid_check(ac);
3741 * Other errors are checked for elsewhere, we just
3742 * want to prevent duplicates
3744 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
3745 return ret;
3749 el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
3750 if (el != NULL) {
3751 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3752 if (ret != LDB_SUCCESS) {
3753 return ret;
3757 el = ldb_msg_find_element(ac->msg, "attributeID");
3758 if (el != NULL) {
3759 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3760 "Once set, attributeID values may not be modified");
3761 return LDB_ERR_CONSTRAINT_VIOLATION;
3764 el = ldb_msg_find_element(ac->msg, "governsID");
3765 if (el != NULL) {
3766 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3767 "Once set, governsID values may not be modified");
3768 return LDB_ERR_CONSTRAINT_VIOLATION;
3771 el = ldb_msg_find_element(ac->msg, "member");
3772 if (el != NULL) {
3773 struct ldb_control *fix_link_sid_ctrl = NULL;
3775 fix_link_sid_ctrl = ldb_request_get_control(ac->req,
3776 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
3777 if (fix_link_sid_ctrl == NULL) {
3778 ret = samldb_member_check(ac);
3779 if (ret != LDB_SUCCESS) {
3780 return ret;
3785 el = ldb_msg_find_element(ac->msg, "description");
3786 if (el != NULL) {
3787 ret = samldb_description_check(ac, &modified);
3788 if (ret != LDB_SUCCESS) {
3789 return ret;
3793 el = ldb_msg_find_element(ac->msg, "dNSHostName");
3794 el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
3795 if ((el != NULL) || (el2 != NULL)) {
3796 modified = true;
3797 ret = samldb_service_principal_names_change(ac);
3798 if (ret != LDB_SUCCESS) {
3799 return ret;
3803 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3804 if (el != NULL) {
3805 ret = samldb_fsmo_role_owner_check(ac);
3806 if (ret != LDB_SUCCESS) {
3807 return ret;
3811 if (modified) {
3812 struct ldb_request *child_req;
3814 /* Now perform the real modifications as a child request */
3815 ret = ldb_build_mod_req(&child_req, ldb, ac,
3816 ac->msg,
3817 req->controls,
3818 req, dsdb_next_callback,
3819 req);
3820 LDB_REQ_SET_LOCATION(child_req);
3821 if (ret != LDB_SUCCESS) {
3822 return ret;
3825 return ldb_next_request(module, child_req);
3828 talloc_free(ac);
3830 /* no change which interests us, go on */
3831 return ldb_next_request(module, req);
3834 /* delete */
3836 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
3838 struct ldb_context *ldb;
3839 struct dom_sid *sid;
3840 uint32_t rid;
3841 NTSTATUS status;
3842 int ret;
3843 struct ldb_result *res;
3844 const char * const attrs[] = { "objectSid", "isDeleted", NULL };
3845 const char * const noattrs[] = { NULL };
3847 ldb = ldb_module_get_ctx(ac->module);
3849 /* Finds out the SID/RID of the SAM object */
3850 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
3851 attrs,
3852 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3853 ac->req);
3854 if (ret != LDB_SUCCESS) {
3855 return ret;
3858 if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
3859 return LDB_SUCCESS;
3862 sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
3863 if (sid == NULL) {
3864 /* No SID - it might not be a SAM object - therefore ok */
3865 return LDB_SUCCESS;
3867 status = dom_sid_split_rid(ac, sid, NULL, &rid);
3868 if (!NT_STATUS_IS_OK(status)) {
3869 return ldb_operr(ldb);
3871 if (rid == 0) {
3872 /* Special object (security principal?) */
3873 return LDB_SUCCESS;
3875 /* do not allow deletion of well-known sids */
3876 if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
3877 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
3878 return LDB_ERR_OTHER;
3881 /* Deny delete requests from groups which are primary ones */
3882 ret = dsdb_module_search(ac->module, ac, &res,
3883 ldb_get_default_basedn(ldb),
3884 LDB_SCOPE_SUBTREE, noattrs,
3885 DSDB_FLAG_NEXT_MODULE,
3886 ac->req,
3887 "(&(primaryGroupID=%u)(objectClass=user))", rid);
3888 if (ret != LDB_SUCCESS) {
3889 return ret;
3891 if (res->count > 0) {
3892 return LDB_ERR_ENTRY_ALREADY_EXISTS;
3895 return LDB_SUCCESS;
3898 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
3900 struct samldb_ctx *ac;
3901 char *referral = NULL;
3902 int ret;
3903 struct ldb_context *ldb;
3905 if (ldb_dn_is_special(req->op.del.dn)) {
3906 /* do not manipulate our control entries */
3907 return ldb_next_request(module, req);
3910 ldb = ldb_module_get_ctx(module);
3912 referral = refer_if_rodc(ldb, req, req->op.del.dn);
3913 if (referral != NULL) {
3914 ret = ldb_module_send_referral(req, referral);
3915 return ret;
3918 ac = samldb_ctx_init(module, req);
3919 if (ac == NULL) {
3920 return ldb_operr(ldb_module_get_ctx(module));
3923 ret = samldb_prim_group_users_check(ac);
3924 if (ret != LDB_SUCCESS) {
3925 return ret;
3928 talloc_free(ac);
3930 return ldb_next_request(module, req);
3933 /* rename */
3935 static int check_rename_constraints(struct ldb_message *msg,
3936 struct samldb_ctx *ac,
3937 struct ldb_dn *olddn, struct ldb_dn *newdn)
3939 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3940 struct ldb_dn *dn1, *dn2, *nc_root;
3941 int32_t systemFlags;
3942 bool move_op = false;
3943 bool rename_op = false;
3944 int ret;
3946 /* Skip the checks if old and new DN are the same, or if we have the
3947 * relax control specified or if the returned objects is already
3948 * deleted and needs only to be moved for consistency. */
3950 if (ldb_dn_compare(olddn, newdn) == 0) {
3951 return LDB_SUCCESS;
3953 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
3954 return LDB_SUCCESS;
3957 if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
3959 * check originating request if we are supposed
3960 * to "see" this record in first place.
3962 if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
3963 return LDB_ERR_NO_SUCH_OBJECT;
3965 return LDB_ERR_UNWILLING_TO_PERFORM;
3968 /* Objects under CN=System */
3970 dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
3971 if (dn1 == NULL) return ldb_oom(ldb);
3973 if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
3974 talloc_free(dn1);
3975 return LDB_ERR_OPERATIONS_ERROR;
3978 if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
3979 (ldb_dn_compare_base(dn1, newdn) != 0)) {
3980 talloc_free(dn1);
3981 ldb_asprintf_errstring(ldb,
3982 "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
3983 ldb_dn_get_linearized(olddn));
3984 return LDB_ERR_OTHER;
3987 talloc_free(dn1);
3989 /* LSA objects */
3991 if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
3992 (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
3993 ldb_asprintf_errstring(ldb,
3994 "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
3995 ldb_dn_get_linearized(olddn));
3996 return LDB_ERR_UNWILLING_TO_PERFORM;
3999 /* subnet objects */
4000 if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
4001 ret = samldb_verify_subnet(ac, newdn);
4002 if (ret != LDB_SUCCESS) {
4003 talloc_free(ac);
4004 return ret;
4008 /* systemFlags */
4010 dn1 = ldb_dn_get_parent(ac, olddn);
4011 if (dn1 == NULL) return ldb_oom(ldb);
4012 dn2 = ldb_dn_get_parent(ac, newdn);
4013 if (dn2 == NULL) return ldb_oom(ldb);
4015 if (ldb_dn_compare(dn1, dn2) == 0) {
4016 rename_op = true;
4017 } else {
4018 move_op = true;
4021 talloc_free(dn1);
4022 talloc_free(dn2);
4024 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
4026 /* Fetch name context */
4028 ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
4029 if (ret != LDB_SUCCESS) {
4030 return ret;
4033 if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
4034 if (move_op) {
4035 ldb_asprintf_errstring(ldb,
4036 "subtree_rename: Cannot move %s within schema partition",
4037 ldb_dn_get_linearized(olddn));
4038 return LDB_ERR_UNWILLING_TO_PERFORM;
4040 if (rename_op &&
4041 (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
4042 ldb_asprintf_errstring(ldb,
4043 "subtree_rename: Cannot rename %s within schema partition",
4044 ldb_dn_get_linearized(olddn));
4045 return LDB_ERR_UNWILLING_TO_PERFORM;
4047 } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
4048 if (move_op &&
4049 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
4050 /* Here we have to do more: control the
4051 * "ALLOW_LIMITED_MOVE" flag. This means that the
4052 * grand-grand-parents of two objects have to be equal
4053 * in order to perform the move (this is used for
4054 * moving "server" objects in the "sites" container). */
4055 bool limited_move =
4056 systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
4058 if (limited_move) {
4059 dn1 = ldb_dn_copy(ac, olddn);
4060 if (dn1 == NULL) return ldb_oom(ldb);
4061 dn2 = ldb_dn_copy(ac, newdn);
4062 if (dn2 == NULL) return ldb_oom(ldb);
4064 limited_move &= ldb_dn_remove_child_components(dn1, 3);
4065 limited_move &= ldb_dn_remove_child_components(dn2, 3);
4066 limited_move &= ldb_dn_compare(dn1, dn2) == 0;
4068 talloc_free(dn1);
4069 talloc_free(dn2);
4072 if (!limited_move
4073 && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
4074 ldb_asprintf_errstring(ldb,
4075 "subtree_rename: Cannot move %s to %s in config partition",
4076 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4077 return LDB_ERR_UNWILLING_TO_PERFORM;
4080 if (rename_op &&
4081 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
4082 ldb_asprintf_errstring(ldb,
4083 "subtree_rename: Cannot rename %s to %s within config partition",
4084 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4085 return LDB_ERR_UNWILLING_TO_PERFORM;
4087 } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
4088 if (move_op &&
4089 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
4090 ldb_asprintf_errstring(ldb,
4091 "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
4092 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4093 return LDB_ERR_UNWILLING_TO_PERFORM;
4095 if (rename_op &&
4096 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
4097 ldb_asprintf_errstring(ldb,
4098 "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
4099 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4100 return LDB_ERR_UNWILLING_TO_PERFORM;
4104 talloc_free(nc_root);
4106 return LDB_SUCCESS;
4110 static int samldb_rename_search_base_callback(struct ldb_request *req,
4111 struct ldb_reply *ares)
4113 struct samldb_ctx *ac;
4114 int ret;
4116 ac = talloc_get_type(req->context, struct samldb_ctx);
4118 if (!ares) {
4119 return ldb_module_done(ac->req, NULL, NULL,
4120 LDB_ERR_OPERATIONS_ERROR);
4122 if (ares->error != LDB_SUCCESS) {
4123 return ldb_module_done(ac->req, ares->controls,
4124 ares->response, ares->error);
4127 switch (ares->type) {
4128 case LDB_REPLY_ENTRY:
4130 * This is the root entry of the originating move
4131 * respectively rename request. It has been already
4132 * stored in the list using "subtree_rename_search()".
4133 * Only this one is subject to constraint checking.
4135 ret = check_rename_constraints(ares->message, ac,
4136 ac->req->op.rename.olddn,
4137 ac->req->op.rename.newdn);
4138 if (ret != LDB_SUCCESS) {
4139 return ldb_module_done(ac->req, NULL, NULL,
4140 ret);
4142 break;
4144 case LDB_REPLY_REFERRAL:
4145 /* ignore */
4146 break;
4148 case LDB_REPLY_DONE:
4151 * Great, no problem with the rename, so go ahead as
4152 * if we never were here
4154 ret = ldb_next_request(ac->module, ac->req);
4155 talloc_free(ares);
4156 return ret;
4159 talloc_free(ares);
4160 return LDB_SUCCESS;
4164 /* rename */
4165 static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
4167 struct ldb_context *ldb;
4168 static const char * const attrs[] = { "objectClass", "systemFlags",
4169 "isDeleted", NULL };
4170 struct ldb_request *search_req;
4171 struct samldb_ctx *ac;
4172 int ret;
4174 if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
4175 return ldb_next_request(module, req);
4178 ldb = ldb_module_get_ctx(module);
4180 ac = samldb_ctx_init(module, req);
4181 if (!ac) {
4182 return ldb_oom(ldb);
4185 ret = ldb_build_search_req(&search_req, ldb, ac,
4186 req->op.rename.olddn,
4187 LDB_SCOPE_BASE,
4188 "(objectClass=*)",
4189 attrs,
4190 NULL,
4192 samldb_rename_search_base_callback,
4193 req);
4194 LDB_REQ_SET_LOCATION(search_req);
4195 if (ret != LDB_SUCCESS) {
4196 return ret;
4199 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4200 true, NULL);
4201 if (ret != LDB_SUCCESS) {
4202 return ret;
4205 return ldb_next_request(ac->module, search_req);
4208 /* extended */
4210 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
4212 struct ldb_context *ldb = ldb_module_get_ctx(module);
4213 struct dsdb_fsmo_extended_op *exop;
4214 int ret;
4216 exop = talloc_get_type(req->op.extended.data,
4217 struct dsdb_fsmo_extended_op);
4218 if (!exop) {
4219 ldb_set_errstring(ldb,
4220 "samldb_extended_allocate_rid_pool: invalid extended data");
4221 return LDB_ERR_PROTOCOL_ERROR;
4224 ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
4225 if (ret != LDB_SUCCESS) {
4226 return ret;
4229 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4232 static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
4234 struct ldb_context *ldb = ldb_module_get_ctx(module);
4235 struct dsdb_extended_allocate_rid *exop;
4236 int ret;
4238 exop = talloc_get_type(req->op.extended.data,
4239 struct dsdb_extended_allocate_rid);
4240 if (!exop) {
4241 ldb_set_errstring(ldb,
4242 "samldb_extended_allocate_rid: invalid extended data");
4243 return LDB_ERR_PROTOCOL_ERROR;
4246 ret = ridalloc_allocate_rid(module, &exop->rid, req);
4247 if (ret != LDB_SUCCESS) {
4248 return ret;
4251 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4254 static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
4256 struct ldb_context *ldb = ldb_module_get_ctx(module);
4257 int ret;
4258 struct ldb_dn *dn;
4260 if (req->op.extended.data != NULL) {
4261 ldb_set_errstring(ldb,
4262 "samldb_extended_allocate_rid_pool_for_us: invalid extended data (should be NULL)");
4263 return LDB_ERR_PROTOCOL_ERROR;
4266 ret = ridalloc_create_own_rid_set(module, req,
4267 &dn, req);
4268 if (ret != LDB_SUCCESS) {
4269 return ret;
4272 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4275 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
4277 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
4278 return samldb_extended_allocate_rid_pool(module, req);
4281 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
4282 return samldb_extended_allocate_rid(module, req);
4285 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
4286 return samldb_extended_create_own_rid_set(module, req);
4289 return ldb_next_request(module, req);
4293 static const struct ldb_module_ops ldb_samldb_module_ops = {
4294 .name = "samldb",
4295 .add = samldb_add,
4296 .modify = samldb_modify,
4297 .del = samldb_delete,
4298 .rename = samldb_rename,
4299 .extended = samldb_extended
4303 int ldb_samldb_module_init(const char *version)
4305 LDB_MODULE_CHECK_VERSION(version);
4306 return ldb_register_module(&ldb_samldb_module_ops);