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/>.
27 * Component: ldb samldb module
29 * Description: various internal DSDB triggers - most for SAM specific objects
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"
44 #include "param/param.h"
45 #include "libds/common/flag_mapping.h"
46 #include "system/network.h"
47 #include "librpc/gen_ndr/irpc.h"
50 enum samldb_add_type {
57 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
60 struct samldb_step *next;
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);
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);
111 return ldb_oom(ldb_module_get_ctx(ac->module));
116 if (ac->steps == NULL) {
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;
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. */
150 return ldb_module_done(ac->req, ac->ares->controls,
151 ac->ares->response, LDB_SUCCESS);
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;
165 struct ldb_message_element *el;
168 el = dsdb_get_single_valued_attr(ac->msg, attr,
171 /* we are not affected */
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!",
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!",
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,
203 LDB_SCOPE_SUBTREE, no_attrs,
204 DSDB_FLAG_NEXT_MODULE, ac->req,
207 attr_conflict, enc_str);
209 ret = dsdb_module_search(ac->module, ac, &res,
211 LDB_SCOPE_SUBTREE, no_attrs,
212 DSDB_FLAG_NEXT_MODULE, ac->req,
213 "(%s=%s)", attr, enc_str);
215 if (ret != LDB_SUCCESS) {
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!",
225 return LDB_ERR_ENTRY_ALREADY_EXISTS;
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;
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;
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;
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;
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,
285 struct ldb_result *ldb_res;
287 if (dsdb_attribute_by_linkID(schema, linkID)) {
292 ret = dsdb_module_search(ac->module, ac,
294 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
295 DSDB_FLAG_NEXT_MODULE,
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",
303 return ldb_operr(ldb);
306 *found = (ldb_res->count != 0);
307 talloc_free(ldb_res);
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)
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) {
334 ret = samldb_check_linkid_used(ac, schema,
336 *next_linkID, &linkID_used);
337 if (ret != LDB_SUCCESS) {
345 static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
349 struct ldb_message_element *el;
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",
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);
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);
384 ret = samldb_generate_next_linkid(ac, schema, &new_linkID);
385 if (ret != LDB_SUCCESS) {
389 ldb_msg_remove_element(ac->msg, el);
390 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
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);
402 attr = dsdb_attribute_by_lDAPDisplayName(schema, enc_str);
407 * The attribute we're adding this as a backlink of must
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,
420 if (ret != LDB_SUCCESS) {
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",
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;
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,
451 struct ldb_result *ldb_res;
453 ret = dsdb_module_search(ac->module, ac,
455 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
456 DSDB_FLAG_NEXT_MODULE,
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",
464 return ldb_operr(ldb);
467 *found = (ldb_res->count != 0);
468 talloc_free(ldb_res);
473 static int samldb_generate_next_mapiid(struct samldb_ctx *ac,
474 struct dsdb_schema *schema,
475 int32_t *next_mapiid)
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) {
490 ret = samldb_check_mapiid_used(ac, schema,
492 *next_mapiid, &mapiid_used);
493 if (ret != LDB_SUCCESS) {
501 static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
505 struct ldb_message_element *el;
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",
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);
535 ret = samldb_generate_next_mapiid(ac, schema,
537 if (ret != LDB_SUCCESS) {
541 ldb_msg_remove_element(ac->msg, el);
542 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
543 "mAPIID", new_mapiid);
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;
556 /* sAMAccountName handling */
557 static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
558 struct ldb_message *msg)
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());
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);
579 if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
580 ret = samldb_generate_sAMAccountName(ldb, ac->msg);
581 if (ret != LDB_SUCCESS) {
586 ret = samldb_sam_accountname_valid_check(ac);
587 if (ret != LDB_SUCCESS) {
591 return samldb_next_step(ac);
595 static bool samldb_msg_add_sid(struct ldb_message *msg,
597 const struct dom_sid *sid)
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)) {
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)
616 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
619 ret = ridalloc_allocate_rid(ac->module, &rid, ac->req);
620 if (ret != LDB_SUCCESS) {
624 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
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 };
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,
652 "(msDC-SecondaryKrbTgtNumber=%u)",
654 if (ret == LDB_SUCCESS && res->count == 0) {
655 talloc_free(tmp_ctx);
658 talloc_free(tmp_ctx);
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;
668 struct ldb_val newpass_utf16;
670 /* find a unused msDC-SecondaryKrbTgtNumber */
671 i_start = generate_random() & 0xFFFF;
676 for (i=i_start; i<=0xFFFF; i++) {
677 if (samldb_krbtgtnumber_available(ac, i)) {
682 for (i=1; i<i_start; i++) {
683 if (samldb_krbtgtnumber_available(ac, i)) {
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;
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",
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) {
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()
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 };
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,
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)) {
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);
770 if (ldb_msg_add_string(m, "defaultObjectCategory",
771 ldb_dn_get_extended_linearized(m, res->msgs[0]->dn, 1)) !=
775 m->elements[0].flags = LDB_FLAG_MOD_REPLACE;
777 ret = dsdb_module_modify(ac->module, m,
778 DSDB_FLAG_NEXT_MODULE,
780 if (ret != LDB_SUCCESS) {
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)
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)) {
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)) {
827 /* check Functional Level */
828 if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
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) {
837 schema = dsdb_get_schema(ldb, NULL);
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"));
855 msds_intid = msds_intid_struct->msds_intid;
858 /* probe id values until unique one is found */
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
877 if (dsdb_attribute_by_attributeID_id(schema, msds_intid)) {
878 msds_intid = generate_random() % 0X3FFFFFFF;
879 msds_intid += 0x80000000;
884 ret = dsdb_module_search(ac->module, ac,
886 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
887 DSDB_FLAG_NEXT_MODULE,
889 "(msDS-IntId=%d)", msds_intid);
890 if (ret != LDB_SUCCESS) {
891 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
892 __location__": Searching for msDS-IntId=%d failed - %s\n",
895 return ldb_operr(ldb);
897 id_exists = (ldb_res->count > 0);
898 talloc_free(ldb_res);
901 msds_intid_struct->msds_intid = msds_intid;
902 ldb_set_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE, msds_intid_struct);
904 return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
910 * samldb_add_entry (async)
913 static int samldb_add_entry_callback(struct ldb_request *req,
914 struct ldb_reply *ares)
916 struct ldb_context *ldb;
917 struct samldb_ctx *ac;
920 ac = talloc_get_type(req->context, struct samldb_ctx);
921 ldb = ldb_module_get_ctx(ac->module);
924 return ldb_module_done(ac->req, NULL, NULL,
925 LDB_ERR_OPERATIONS_ERROR);
928 if (ares->type == LDB_REPLY_REFERRAL) {
929 return ldb_module_send_referral(ac->req, ares->referral);
932 if (ares->error != LDB_SUCCESS) {
933 return ldb_module_done(ac->req, ares->controls,
934 ares->response, ares->error);
936 if (ares->type != LDB_REPLY_DONE) {
937 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
938 return ldb_module_done(ac->req, NULL, NULL,
939 LDB_ERR_OPERATIONS_ERROR);
942 /* The caller may wish to get controls back from the add */
943 ac->ares = talloc_steal(ac, ares);
945 ret = samldb_next_step(ac);
946 if (ret != LDB_SUCCESS) {
947 return ldb_module_done(ac->req, NULL, NULL, ret);
952 static int samldb_add_entry(struct samldb_ctx *ac)
954 struct ldb_context *ldb;
955 struct ldb_request *req;
958 ldb = ldb_module_get_ctx(ac->module);
960 ret = ldb_build_add_req(&req, ldb, ac,
963 ac, samldb_add_entry_callback,
965 LDB_REQ_SET_LOCATION(req);
966 if (ret != LDB_SUCCESS) {
970 return ldb_next_request(ac->module, req);
974 * return true if msg carries an attributeSchema that is intended to be RODC
975 * filtered but is also a system-critical attribute.
977 static bool check_rodc_critical_attribute(struct ldb_message *msg)
979 uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
981 schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
982 searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
983 rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
984 | SEARCH_FLAG_CONFIDENTIAL);
986 if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
987 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
995 static int samldb_fill_object(struct samldb_ctx *ac)
997 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1000 /* Add information for the different account types */
1002 case SAMLDB_TYPE_USER: {
1003 struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
1004 LDB_CONTROL_RODC_DCPROMO_OID);
1005 if (rodc_control != NULL) {
1006 /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
1007 rodc_control->critical = false;
1008 ret = samldb_add_step(ac, samldb_rodc_add);
1009 if (ret != LDB_SUCCESS) return ret;
1012 /* check if we have a valid sAMAccountName */
1013 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1014 if (ret != LDB_SUCCESS) return ret;
1016 ret = samldb_add_step(ac, samldb_add_entry);
1017 if (ret != LDB_SUCCESS) return ret;
1021 case SAMLDB_TYPE_GROUP: {
1022 /* check if we have a valid sAMAccountName */
1023 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1024 if (ret != LDB_SUCCESS) return ret;
1026 ret = samldb_add_step(ac, samldb_add_entry);
1027 if (ret != LDB_SUCCESS) return ret;
1031 case SAMLDB_TYPE_CLASS: {
1032 const char *lDAPDisplayName = NULL;
1033 const struct ldb_val *rdn_value, *def_obj_cat_val;
1034 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
1036 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
1037 if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
1038 ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
1039 if (ret != LDB_SUCCESS) return ret;
1042 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1044 if (ret != LDB_SUCCESS) return ret;
1046 /* do not allow one to mark an attributeSchema as RODC filtered if it
1047 * is system-critical */
1048 if (check_rodc_critical_attribute(ac->msg)) {
1049 ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
1050 ldb_dn_get_linearized(ac->msg->dn));
1051 return LDB_ERR_UNWILLING_TO_PERFORM;
1054 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1055 if (rdn_value == NULL) {
1056 return ldb_operr(ldb);
1058 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1059 /* the RDN has prefix "CN" */
1060 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1061 samdb_cn_to_lDAPDisplayName(ac->msg,
1062 (const char *) rdn_value->data));
1063 if (ret != LDB_SUCCESS) {
1069 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1072 ret = ldb_valid_attr_name(lDAPDisplayName);
1074 lDAPDisplayName[0] == '*' ||
1075 lDAPDisplayName[0] == '@')
1077 return dsdb_module_werror(ac->module,
1078 LDB_ERR_UNWILLING_TO_PERFORM,
1079 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1080 "lDAPDisplayName is invalid");
1083 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1086 guid = GUID_random();
1087 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1088 if (ret != LDB_SUCCESS) {
1094 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
1095 "defaultObjectCategory");
1096 if (def_obj_cat_val != NULL) {
1097 /* "defaultObjectCategory" has been set by the caller.
1098 * Do some checks for consistency.
1099 * NOTE: The real constraint check (that
1100 * 'defaultObjectCategory' is the DN of the new
1101 * objectclass or any parent of it) is still incomplete.
1102 * For now we say that 'defaultObjectCategory' is valid
1103 * if it exists and it is of objectclass "classSchema".
1105 ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
1106 if (ac->dn == NULL) {
1107 ldb_set_errstring(ldb,
1108 "Invalid DN for 'defaultObjectCategory'!");
1109 return LDB_ERR_CONSTRAINT_VIOLATION;
1112 /* "defaultObjectCategory" has not been set by the
1113 * caller. Use the entry DN for it. */
1114 ac->dn = ac->msg->dn;
1116 ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
1117 ldb_dn_alloc_linearized(ac->msg, ac->dn));
1118 if (ret != LDB_SUCCESS) {
1124 ret = samldb_add_step(ac, samldb_add_entry);
1125 if (ret != LDB_SUCCESS) return ret;
1127 /* Now perform the checks for the 'defaultObjectCategory'. The
1128 * lookup DN was already saved in "ac->dn" */
1129 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
1130 if (ret != LDB_SUCCESS) return ret;
1132 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
1134 /* Windows 2003 does this*/
1135 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
1136 if (ret != LDB_SUCCESS) {
1143 case SAMLDB_TYPE_ATTRIBUTE: {
1144 const char *lDAPDisplayName = NULL;
1145 const struct ldb_val *rdn_value;
1146 struct ldb_message_element *el;
1147 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1148 if (rdn_value == NULL) {
1149 return ldb_operr(ldb);
1151 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1152 /* the RDN has prefix "CN" */
1153 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1154 samdb_cn_to_lDAPDisplayName(ac->msg,
1155 (const char *) rdn_value->data));
1156 if (ret != LDB_SUCCESS) {
1162 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1165 ret = ldb_valid_attr_name(lDAPDisplayName);
1167 lDAPDisplayName[0] == '*' ||
1168 lDAPDisplayName[0] == '@')
1170 return dsdb_module_werror(ac->module,
1171 LDB_ERR_UNWILLING_TO_PERFORM,
1172 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1173 "lDAPDisplayName is invalid");
1176 /* do not allow one to mark an attributeSchema as RODC filtered if it
1177 * is system-critical */
1178 if (check_rodc_critical_attribute(ac->msg)) {
1179 ldb_asprintf_errstring(ldb,
1180 "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
1181 ldb_dn_get_linearized(ac->msg->dn));
1182 return LDB_ERR_UNWILLING_TO_PERFORM;
1185 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1186 "isSingleValued", "FALSE");
1187 if (ret != LDB_SUCCESS) return ret;
1189 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1192 guid = GUID_random();
1193 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1194 if (ret != LDB_SUCCESS) {
1200 el = ldb_msg_find_element(ac->msg, "attributeSyntax");
1203 * No need to scream if there isn't as we have code later on
1204 * that will take care of it.
1206 const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
1208 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
1209 (const char *)el->values[0].data));
1211 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
1212 const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
1215 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
1216 if (ret != LDB_SUCCESS) {
1221 struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
1222 if (val2.length > 0) {
1223 ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
1224 if (ret != LDB_SUCCESS) {
1232 /* handle msDS-IntID attribute */
1233 ret = samldb_add_handle_msDS_IntId(ac);
1234 if (ret != LDB_SUCCESS) return ret;
1236 ret = samldb_add_step(ac, samldb_add_entry);
1237 if (ret != LDB_SUCCESS) return ret;
1242 ldb_asprintf_errstring(ldb, "Invalid entry type!");
1243 return LDB_ERR_OPERATIONS_ERROR;
1247 return samldb_first_step(ac);
1250 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1252 struct ldb_context *ldb = NULL;
1253 const struct ldb_val *rdn_value = NULL;
1254 struct ldb_message_element *sid_el = NULL;
1255 struct dom_sid *sid = NULL;
1256 struct ldb_control *as_system = NULL;
1257 struct ldb_control *provision = NULL;
1258 bool allowed = false;
1261 ldb = ldb_module_get_ctx(ac->module);
1263 as_system = ldb_request_get_control(ac->req, LDB_CONTROL_AS_SYSTEM_OID);
1264 if (as_system != NULL) {
1268 provision = ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID);
1269 if (provision != NULL) {
1273 sid_el = ldb_msg_find_element(ac->msg, "objectSid");
1275 if (!allowed && sid_el == NULL) {
1276 return dsdb_module_werror(ac->module,
1277 LDB_ERR_OBJECT_CLASS_VIOLATION,
1278 WERR_DS_MISSING_REQUIRED_ATT,
1279 "objectSid missing on foreignSecurityPrincipal");
1283 return dsdb_module_werror(ac->module,
1284 LDB_ERR_UNWILLING_TO_PERFORM,
1285 WERR_DS_ILLEGAL_MOD_OPERATION,
1286 "foreignSecurityPrincipal object not allowed");
1289 if (sid_el != NULL) {
1290 sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1292 ldb_set_errstring(ldb,
1293 "samldb: invalid objectSid!");
1294 return LDB_ERR_CONSTRAINT_VIOLATION;
1299 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1300 if (rdn_value == NULL) {
1301 return ldb_operr(ldb);
1303 sid = dom_sid_parse_talloc(ac->msg,
1304 (const char *)rdn_value->data);
1306 ldb_set_errstring(ldb,
1307 "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
1308 return LDB_ERR_CONSTRAINT_VIOLATION;
1310 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
1311 return ldb_operr(ldb);
1315 /* finally proceed with adding the entry */
1316 ret = samldb_add_step(ac, samldb_add_entry);
1317 if (ret != LDB_SUCCESS) return ret;
1319 return samldb_first_step(ac);
1322 static int samldb_schema_info_update(struct samldb_ctx *ac)
1325 struct ldb_context *ldb;
1326 struct dsdb_schema *schema;
1328 /* replicated update should always go through */
1329 if (ldb_request_get_control(ac->req,
1330 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1334 /* do not update schemaInfo during provisioning */
1335 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1339 ldb = ldb_module_get_ctx(ac->module);
1340 schema = dsdb_get_schema(ldb, NULL);
1342 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1343 "samldb_schema_info_update: no dsdb_schema loaded");
1344 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1345 return ldb_operr(ldb);
1348 ret = dsdb_module_schema_info_update(ac->module, schema,
1349 DSDB_FLAG_NEXT_MODULE|
1350 DSDB_FLAG_AS_SYSTEM,
1352 if (ret != LDB_SUCCESS) {
1353 ldb_asprintf_errstring(ldb,
1354 "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
1355 ldb_errstring(ldb));
1362 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
1363 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
1364 struct dom_sid *sid,
1366 uint32_t user_account_control,
1367 uint32_t user_account_control_old);
1370 * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
1372 * Has to be invoked on "add" and "modify" operations on "user", "computer" and
1374 * ac->msg contains the "add"/"modify" message
1375 * ac->type contains the object type (main objectclass)
1377 static int samldb_objectclass_trigger(struct samldb_ctx *ac)
1379 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1380 void *skip_allocate_sids = ldb_get_opaque(ldb,
1381 "skip_allocate_sids");
1382 struct ldb_message_element *el, *el2;
1383 struct dom_sid *sid;
1386 /* make sure that "sAMAccountType" is not specified */
1387 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1389 ldb_set_errstring(ldb,
1390 "samldb: sAMAccountType must not be specified!");
1391 return LDB_ERR_UNWILLING_TO_PERFORM;
1394 /* Step 1: objectSid assignment */
1396 /* Don't allow the objectSid to be changed. But beside the RELAX
1397 * control we have also to guarantee that it can always be set with
1398 * SYSTEM permissions. This is needed for the "samba3sam" backend. */
1399 sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1400 if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
1401 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
1402 ldb_set_errstring(ldb,
1403 "samldb: objectSid must not be specified!");
1404 return LDB_ERR_UNWILLING_TO_PERFORM;
1407 /* but generate a new SID when we do have an add operations */
1408 if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
1409 ret = samldb_add_step(ac, samldb_allocate_sid);
1410 if (ret != LDB_SUCCESS) return ret;
1414 case SAMLDB_TYPE_USER: {
1415 bool uac_generated = false, uac_add_flags = false;
1417 /* Step 1.2: Default values */
1418 ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
1419 if (ret != LDB_SUCCESS) return ret;
1421 /* On add operations we might need to generate a
1422 * "userAccountControl" (if it isn't specified). */
1423 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1424 if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
1425 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1426 "userAccountControl",
1428 if (ret != LDB_SUCCESS) {
1431 uac_generated = true;
1432 uac_add_flags = true;
1435 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1438 uint32_t user_account_control;
1439 /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
1440 user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
1441 "userAccountControl",
1443 raw_uac = user_account_control;
1445 * "userAccountControl" = 0 or missing one of
1446 * the types means "UF_NORMAL_ACCOUNT". See
1447 * MS-SAMR 3.1.1.8.10 point 8
1449 if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
1450 user_account_control = UF_NORMAL_ACCOUNT | user_account_control;
1451 uac_generated = true;
1455 * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
1457 if ((user_account_control & UF_LOCKOUT) != 0) {
1458 user_account_control &= ~UF_LOCKOUT;
1459 uac_generated = true;
1461 if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
1462 user_account_control &= ~UF_PASSWORD_EXPIRED;
1463 uac_generated = true;
1466 ret = samldb_check_user_account_control_rules(ac, NULL,
1468 user_account_control,
1470 if (ret != LDB_SUCCESS) {
1474 /* Workstation and (read-only) DC objects do need objectclass "computer" */
1475 if ((samdb_find_attribute(ldb, ac->msg,
1476 "objectclass", "computer") == NULL) &&
1477 (user_account_control &
1478 (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
1479 ldb_set_errstring(ldb,
1480 "samldb: Requested account type does need objectclass 'computer'!");
1481 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1484 /* add "sAMAccountType" attribute */
1485 ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
1486 if (ret != LDB_SUCCESS) {
1490 /* "isCriticalSystemObject" might be set */
1491 if (user_account_control &
1492 (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1493 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1495 if (ret != LDB_SUCCESS) {
1498 el2 = ldb_msg_find_element(ac->msg,
1499 "isCriticalSystemObject");
1500 el2->flags = LDB_FLAG_MOD_REPLACE;
1501 } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1502 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1504 if (ret != LDB_SUCCESS) {
1507 el2 = ldb_msg_find_element(ac->msg,
1508 "isCriticalSystemObject");
1509 el2->flags = LDB_FLAG_MOD_REPLACE;
1512 /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
1513 if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1516 ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
1517 if (ret != LDB_SUCCESS) {
1521 * Older AD deployments don't know about the
1524 if (rid == DOMAIN_RID_READONLY_DCS) {
1525 ret = samldb_prim_group_tester(ac, rid);
1526 if (ret != LDB_SUCCESS) {
1532 /* Step 1.5: Add additional flags when needed */
1533 /* Obviously this is done when the "userAccountControl"
1534 * has been generated here (tested against Windows
1536 if (uac_generated) {
1537 if (uac_add_flags) {
1538 user_account_control |= UF_ACCOUNTDISABLE;
1539 user_account_control |= UF_PASSWD_NOTREQD;
1542 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1543 "userAccountControl",
1544 user_account_control);
1545 if (ret != LDB_SUCCESS) {
1554 case SAMLDB_TYPE_GROUP: {
1555 const char *tempstr;
1557 /* Step 2.2: Default values */
1558 tempstr = talloc_asprintf(ac->msg, "%d",
1559 GTYPE_SECURITY_GLOBAL_GROUP);
1560 if (tempstr == NULL) return ldb_operr(ldb);
1561 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1562 "groupType", tempstr);
1563 if (ret != LDB_SUCCESS) return ret;
1565 /* Step 2.3: "groupType" -> "sAMAccountType" */
1566 el = ldb_msg_find_element(ac->msg, "groupType");
1568 uint32_t group_type, account_type;
1570 group_type = ldb_msg_find_attr_as_uint(ac->msg,
1573 /* The creation of builtin groups requires the
1575 if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
1576 if (ldb_request_get_control(ac->req,
1577 LDB_CONTROL_RELAX_OID) == NULL) {
1578 return LDB_ERR_UNWILLING_TO_PERFORM;
1582 account_type = ds_gtype2atype(group_type);
1583 if (account_type == 0) {
1584 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1585 return LDB_ERR_UNWILLING_TO_PERFORM;
1587 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1590 if (ret != LDB_SUCCESS) {
1593 el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1594 el2->flags = LDB_FLAG_MOD_REPLACE;
1600 ldb_asprintf_errstring(ldb,
1601 "Invalid entry type!");
1602 return LDB_ERR_OPERATIONS_ERROR;
1610 * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
1612 * Has to be invoked on "add" and "modify" operations on "user" and "computer"
1614 * ac->msg contains the "add"/"modify" message
1617 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
1619 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1620 struct dom_sid *sid;
1621 struct ldb_result *res;
1623 const char * const noattrs[] = { NULL };
1625 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1627 return ldb_operr(ldb);
1630 ret = dsdb_module_search(ac->module, ac, &res,
1631 ldb_get_default_basedn(ldb),
1633 noattrs, DSDB_FLAG_NEXT_MODULE,
1636 ldap_encode_ndr_dom_sid(ac, sid));
1637 if (ret != LDB_SUCCESS) {
1640 if (res->count != 1) {
1642 ldb_asprintf_errstring(ldb,
1643 "Failed to find primary group with RID %u!",
1645 return LDB_ERR_UNWILLING_TO_PERFORM;
1652 static int samldb_prim_group_set(struct samldb_ctx *ac)
1654 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1657 rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
1658 if (rid == (uint32_t) -1) {
1659 /* we aren't affected of any primary group set */
1662 } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1663 ldb_set_errstring(ldb,
1664 "The primary group isn't settable on add operations!");
1665 return LDB_ERR_UNWILLING_TO_PERFORM;
1668 return samldb_prim_group_tester(ac, rid);
1671 static int samldb_prim_group_change(struct samldb_ctx *ac)
1673 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1674 const char * const attrs[] = {
1677 "userAccountControl",
1679 struct ldb_result *res, *group_res;
1680 struct ldb_message_element *el;
1681 struct ldb_message *msg;
1682 uint32_t prev_rid, new_rid, uac;
1683 struct dom_sid *prev_sid, *new_sid;
1684 struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1686 const char * const noattrs[] = { NULL };
1688 el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1689 ac->req->operation);
1691 /* we are not affected */
1695 /* Fetch information from the existing object */
1697 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1698 DSDB_FLAG_NEXT_MODULE, ac->req);
1699 if (ret != LDB_SUCCESS) {
1703 uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1705 /* Finds out the DN of the old primary group */
1707 prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1709 if (prev_rid == (uint32_t) -1) {
1710 /* User objects do always have a mandatory "primaryGroupID"
1711 * attribute. If this doesn't exist then the object is of the
1712 * wrong type. This is the exact Windows error code */
1713 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1716 prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1717 if (prev_sid == NULL) {
1718 return ldb_operr(ldb);
1721 /* Finds out the DN of the new primary group
1722 * Notice: in order to parse the primary group ID correctly we create
1723 * a temporary message here. */
1725 msg = ldb_msg_new(ac->msg);
1727 return ldb_module_oom(ac->module);
1729 ret = ldb_msg_add(msg, el, 0);
1730 if (ret != LDB_SUCCESS) {
1733 new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1735 if (new_rid == (uint32_t) -1) {
1736 /* we aren't affected of any primary group change */
1740 if (prev_rid == new_rid) {
1744 if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
1745 ldb_asprintf_errstring(ldb,
1746 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
1747 "primaryGroupID=%u!",
1748 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1750 return LDB_ERR_UNWILLING_TO_PERFORM;
1753 if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
1754 ldb_asprintf_errstring(ldb,
1755 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
1756 "primaryGroupID=%u!",
1757 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1758 DOMAIN_RID_READONLY_DCS);
1759 return LDB_ERR_UNWILLING_TO_PERFORM;
1762 ret = dsdb_module_search(ac->module, ac, &group_res,
1763 ldb_get_default_basedn(ldb),
1765 noattrs, DSDB_FLAG_NEXT_MODULE,
1768 ldap_encode_ndr_dom_sid(ac, prev_sid));
1769 if (ret != LDB_SUCCESS) {
1772 if (group_res->count != 1) {
1773 return ldb_operr(ldb);
1775 prev_prim_group_dn = group_res->msgs[0]->dn;
1777 new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1778 if (new_sid == NULL) {
1779 return ldb_operr(ldb);
1782 ret = dsdb_module_search(ac->module, ac, &group_res,
1783 ldb_get_default_basedn(ldb),
1785 noattrs, DSDB_FLAG_NEXT_MODULE,
1788 ldap_encode_ndr_dom_sid(ac, new_sid));
1789 if (ret != LDB_SUCCESS) {
1792 if (group_res->count != 1) {
1793 /* Here we know if the specified new primary group candidate is
1795 return LDB_ERR_UNWILLING_TO_PERFORM;
1797 new_prim_group_dn = group_res->msgs[0]->dn;
1799 /* We need to be already a normal member of the new primary
1800 * group in order to be successful. */
1801 el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1802 ldb_dn_get_linearized(new_prim_group_dn));
1804 return LDB_ERR_UNWILLING_TO_PERFORM;
1807 /* Remove the "member" attribute on the new primary group */
1808 msg = ldb_msg_new(ac->msg);
1810 return ldb_module_oom(ac->module);
1812 msg->dn = new_prim_group_dn;
1814 ret = samdb_msg_add_delval(ldb, msg, msg, "member",
1815 ldb_dn_get_linearized(ac->msg->dn));
1816 if (ret != LDB_SUCCESS) {
1820 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1821 if (ret != LDB_SUCCESS) {
1826 /* Add a "member" attribute for the previous primary group */
1827 msg = ldb_msg_new(ac->msg);
1829 return ldb_module_oom(ac->module);
1831 msg->dn = prev_prim_group_dn;
1833 ret = samdb_msg_add_addval(ldb, msg, msg, "member",
1834 ldb_dn_get_linearized(ac->msg->dn));
1835 if (ret != LDB_SUCCESS) {
1839 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1840 if (ret != LDB_SUCCESS) {
1848 static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1852 if (ac->req->operation == LDB_ADD) {
1853 ret = samldb_prim_group_set(ac);
1855 ret = samldb_prim_group_change(ac);
1861 static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
1862 uint32_t user_account_control)
1865 bool need_check = false;
1866 const struct uac_to_guid {
1871 const char *error_string;
1874 .uac = UF_TEMP_DUPLICATE_ACCOUNT,
1876 .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
1879 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1880 .needs = UF_WORKSTATION_TRUST_ACCOUNT,
1881 .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
1884 .uac = UF_TRUSTED_FOR_DELEGATION,
1885 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1886 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1889 .uac = UF_NORMAL_ACCOUNT,
1890 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
1891 .error_string = "Setting more than one account type not permitted"
1894 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1895 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
1896 .error_string = "Setting more than one account type not permitted"
1899 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1900 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
1901 .error_string = "Setting more than one account type not permitted"
1904 .uac = UF_SERVER_TRUST_ACCOUNT,
1905 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
1906 .error_string = "Setting more than one account type not permitted"
1909 .uac = UF_TRUSTED_FOR_DELEGATION,
1910 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1911 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1915 for (i = 0; i < ARRAY_SIZE(map); i++) {
1916 if (user_account_control & map[i].uac) {
1921 if (need_check == false) {
1925 for (i = 0; i < ARRAY_SIZE(map); i++) {
1926 uint32_t this_uac = user_account_control & map[i].uac;
1927 if (this_uac != 0) {
1929 ret = LDB_ERR_OTHER;
1931 } else if (map[i].needs != 0) {
1932 if ((map[i].needs & user_account_control) == 0) {
1933 ret = LDB_ERR_OTHER;
1936 } else if (map[i].not_with != 0) {
1937 if ((map[i].not_with & user_account_control) != 0) {
1938 ret = LDB_ERR_OTHER;
1944 if (ret != LDB_SUCCESS) {
1945 switch (ac->req->operation) {
1947 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1948 "Failed to add %s: %s",
1949 ldb_dn_get_linearized(ac->msg->dn),
1950 map[i].error_string);
1953 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1954 "Failed to modify %s: %s",
1955 ldb_dn_get_linearized(ac->msg->dn),
1956 map[i].error_string);
1959 return ldb_module_operr(ac->module);
1966 * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
1969 static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
1970 struct dom_sid *sid,
1971 uint32_t user_account_control,
1972 uint32_t user_account_control_old)
1975 bool need_acl_check = false;
1976 struct ldb_result *res;
1977 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
1978 struct security_token *user_token;
1979 struct security_descriptor *domain_sd;
1980 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
1981 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1982 const struct uac_to_guid {
1984 uint32_t priv_to_change_from;
1987 enum sec_privilege privilege;
1988 bool delete_is_privileged;
1989 bool admin_required;
1990 const char *error_string;
1993 .uac = UF_PASSWD_NOTREQD,
1994 .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
1995 .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"
1998 .uac = UF_DONT_EXPIRE_PASSWD,
1999 .guid = GUID_DRS_UNEXPIRE_PASSWORD,
2000 .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
2003 .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
2004 .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
2005 .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"
2008 .uac = UF_SERVER_TRUST_ACCOUNT,
2009 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2010 .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"
2013 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
2014 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2015 .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"
2018 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
2019 .priv_to_change_from = UF_NORMAL_ACCOUNT,
2020 .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
2023 .uac = UF_NORMAL_ACCOUNT,
2024 .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
2025 .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
2028 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
2029 .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2030 .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",
2031 .delete_is_privileged = true
2034 .uac = UF_TRUSTED_FOR_DELEGATION,
2035 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2036 .delete_is_privileged = true,
2037 .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2040 .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
2041 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2042 .delete_is_privileged = true,
2043 .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2048 if (dsdb_module_am_system(ac->module)) {
2052 for (i = 0; i < ARRAY_SIZE(map); i++) {
2053 if (user_account_control & map[i].uac) {
2054 need_acl_check = true;
2058 if (need_acl_check == false) {
2062 user_token = acl_user_token(ac->module);
2063 if (user_token == NULL) {
2064 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2067 ret = dsdb_module_search_dn(ac->module, ac, &res,
2070 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2072 if (ret != LDB_SUCCESS) {
2075 if (res->count != 1) {
2076 return ldb_module_operr(ac->module);
2079 ret = dsdb_get_sd_from_ldb_message(ldb,
2080 ac, res->msgs[0], &domain_sd);
2082 if (ret != LDB_SUCCESS) {
2086 for (i = 0; i < ARRAY_SIZE(map); i++) {
2087 uint32_t this_uac_new = user_account_control & map[i].uac;
2088 uint32_t this_uac_old = user_account_control_old & map[i].uac;
2089 if (this_uac_new != this_uac_old) {
2090 if (this_uac_old != 0) {
2091 if (map[i].delete_is_privileged == false) {
2096 struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
2097 if (control == NULL) {
2098 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2100 } else if (map[i].privilege != SEC_PRIV_INVALID) {
2101 bool have_priv = security_token_has_privilege(user_token,
2103 if (have_priv == false) {
2104 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2106 } else if (map[i].priv_to_change_from & user_account_control_old) {
2107 bool is_admin = security_token_has_builtin_administrators(user_token);
2108 if (is_admin == false) {
2109 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2111 } else if (map[i].guid) {
2112 ret = acl_check_extended_right(ac, domain_sd,
2115 SEC_ADS_CONTROL_ACCESS,
2120 if (ret != LDB_SUCCESS) {
2125 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2126 switch (ac->req->operation) {
2128 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2129 "Failed to add %s: %s",
2130 ldb_dn_get_linearized(ac->msg->dn),
2131 map[i].error_string);
2134 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2135 "Failed to modify %s: %s",
2136 ldb_dn_get_linearized(ac->msg->dn),
2137 map[i].error_string);
2140 return ldb_module_operr(ac->module);
2143 dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
2152 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
2153 struct dom_sid *sid,
2155 uint32_t user_account_control,
2156 uint32_t user_account_control_old)
2159 struct dsdb_control_password_user_account_control *uac = NULL;
2161 ret = samldb_check_user_account_control_invariants(ac, user_account_control);
2162 if (ret != LDB_SUCCESS) {
2165 ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
2166 if (ret != LDB_SUCCESS) {
2170 uac = talloc_zero(ac->req,
2171 struct dsdb_control_password_user_account_control);
2173 return ldb_module_oom(ac->module);
2176 uac->req_flags = req_uac;
2177 uac->old_flags = user_account_control_old;
2178 uac->new_flags = user_account_control;
2180 ret = ldb_request_add_control(ac->req,
2181 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
2183 if (ret != LDB_SUCCESS) {
2192 * This function is called on LDB modify operations. It performs some additions/
2193 * replaces on the current LDB message when "userAccountControl" changes.
2195 static int samldb_user_account_control_change(struct samldb_ctx *ac)
2197 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2203 uint32_t old_uac_computed;
2209 NTTIME old_lockoutTime;
2210 struct ldb_message_element *el;
2211 struct ldb_val *val;
2212 struct ldb_val computer_val;
2213 struct ldb_message *tmp_msg;
2214 struct dom_sid *sid;
2216 struct ldb_result *res;
2217 const char * const attrs[] = {
2219 "isCriticalSystemObject",
2220 "userAccountControl",
2221 "msDS-User-Account-Control-Computed",
2226 bool is_computer = false;
2227 bool old_is_critical = false;
2228 bool new_is_critical = false;
2230 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2231 ac->req->operation);
2232 if (el == NULL || el->num_values == 0) {
2233 ldb_asprintf_errstring(ldb,
2234 "%08X: samldb: 'userAccountControl' can't be deleted!",
2235 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2236 return LDB_ERR_UNWILLING_TO_PERFORM;
2239 /* Create a temporary message for fetching the "userAccountControl" */
2240 tmp_msg = ldb_msg_new(ac->msg);
2241 if (tmp_msg == NULL) {
2242 return ldb_module_oom(ac->module);
2244 ret = ldb_msg_add(tmp_msg, el, 0);
2245 if (ret != LDB_SUCCESS) {
2248 raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
2249 "userAccountControl",
2251 talloc_free(tmp_msg);
2253 * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2254 * are only generated and not stored. We ignore them almost
2255 * completely, along with unknown bits and UF_SCRIPT.
2257 * The only exception is ACB_AUTOLOCK, which features in
2258 * clear_acb when the bit is cleared in this modify operation.
2260 * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2261 * ignored by clients and servers
2263 new_uac = raw_uac & UF_SETTABLE_BITS;
2265 /* Fetch the old "userAccountControl" and "objectClass" */
2266 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2267 DSDB_FLAG_NEXT_MODULE, ac->req);
2268 if (ret != LDB_SUCCESS) {
2271 old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
2273 return ldb_operr(ldb);
2275 old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
2276 "msDS-User-Account-Control-Computed", 0);
2277 old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
2279 old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
2280 "isCriticalSystemObject", 0);
2281 /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
2282 el = ldb_msg_find_element(res->msgs[0], "objectClass");
2284 return ldb_operr(ldb);
2286 computer_val = data_blob_string_const("computer");
2287 val = ldb_msg_find_val(el, &computer_val);
2292 old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
2293 old_atype = ds_uf2atype(old_ufa);
2294 old_pgrid = ds_uf2prim_group_rid(old_uac);
2296 new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
2299 * "userAccountControl" = 0 or missing one of the
2300 * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2301 * 3.1.1.8.10 point 8
2303 new_ufa = UF_NORMAL_ACCOUNT;
2306 sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2308 return ldb_module_operr(ac->module);
2311 ret = samldb_check_user_account_control_rules(ac, sid,
2315 if (ret != LDB_SUCCESS) {
2319 new_atype = ds_uf2atype(new_ufa);
2320 new_pgrid = ds_uf2prim_group_rid(new_uac);
2322 clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
2325 case UF_NORMAL_ACCOUNT:
2326 new_is_critical = old_is_critical;
2329 case UF_INTERDOMAIN_TRUST_ACCOUNT:
2330 new_is_critical = true;
2333 case UF_WORKSTATION_TRUST_ACCOUNT:
2334 new_is_critical = false;
2335 if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
2337 ldb_asprintf_errstring(ldb,
2338 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
2339 "requires objectclass 'computer'!",
2340 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2341 return LDB_ERR_UNWILLING_TO_PERFORM;
2343 new_is_critical = true;
2347 case UF_SERVER_TRUST_ACCOUNT:
2349 ldb_asprintf_errstring(ldb,
2350 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2351 "requires objectclass 'computer'!",
2352 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2353 return LDB_ERR_UNWILLING_TO_PERFORM;
2355 new_is_critical = true;
2359 ldb_asprintf_errstring(ldb,
2360 "%08X: samldb: invalid userAccountControl[0x%08X]",
2361 W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
2362 return LDB_ERR_OTHER;
2365 if (old_atype != new_atype) {
2366 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2367 "sAMAccountType", new_atype);
2368 if (ret != LDB_SUCCESS) {
2371 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2372 el->flags = LDB_FLAG_MOD_REPLACE;
2375 /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
2376 if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
2377 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
2378 ldb_msg_remove_attr(ac->msg, "lockoutTime");
2379 ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
2381 if (ret != LDB_SUCCESS) {
2384 el = ldb_msg_find_element(ac->msg, "lockoutTime");
2385 el->flags = LDB_FLAG_MOD_REPLACE;
2388 /* "isCriticalSystemObject" might be set/changed */
2389 if (old_is_critical != new_is_critical) {
2390 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
2391 new_is_critical ? "TRUE": "FALSE");
2392 if (ret != LDB_SUCCESS) {
2395 el = ldb_msg_find_element(ac->msg,
2396 "isCriticalSystemObject");
2397 el->flags = LDB_FLAG_MOD_REPLACE;
2400 if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
2401 (old_pgrid != new_pgrid)) {
2402 /* Older AD deployments don't know about the RODC group */
2403 if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
2404 ret = samldb_prim_group_tester(ac, new_pgrid);
2405 if (ret != LDB_SUCCESS) {
2410 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2411 "primaryGroupID", new_pgrid);
2412 if (ret != LDB_SUCCESS) {
2415 el = ldb_msg_find_element(ac->msg,
2417 el->flags = LDB_FLAG_MOD_REPLACE;
2420 /* Propagate eventual "userAccountControl" attribute changes */
2421 if (old_uac != new_uac) {
2422 char *tempstr = talloc_asprintf(ac->msg, "%d",
2424 if (tempstr == NULL) {
2425 return ldb_module_oom(ac->module);
2428 /* Overwrite "userAccountControl" correctly */
2429 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2430 ac->req->operation);
2431 el->values[0].data = (uint8_t *) tempstr;
2432 el->values[0].length = strlen(tempstr);
2434 ldb_msg_remove_attr(ac->msg, "userAccountControl");
2440 static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
2441 struct dom_sid *sid)
2443 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2445 struct ldb_result *res = NULL;
2446 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
2447 struct security_token *user_token = NULL;
2448 struct security_descriptor *domain_sd = NULL;
2449 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2450 const char *operation = "";
2452 if (dsdb_module_am_system(ac->module)) {
2456 switch (ac->req->operation) {
2461 operation = "modify";
2464 return ldb_module_operr(ac->module);
2467 user_token = acl_user_token(ac->module);
2468 if (user_token == NULL) {
2469 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2472 ret = dsdb_module_search_dn(ac->module, ac, &res,
2475 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2477 if (ret != LDB_SUCCESS) {
2480 if (res->count != 1) {
2481 return ldb_module_operr(ac->module);
2484 ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
2485 if (ret != LDB_SUCCESS) {
2489 ret = acl_check_extended_right(ac, domain_sd,
2491 GUID_DRS_UNEXPIRE_PASSWORD,
2492 SEC_ADS_CONTROL_ACCESS,
2494 if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2498 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
2500 "Setting pwdLastSet to -1 requires the "
2501 "Unexpire-Password right that was not given "
2502 "on the Domain object",
2504 ldb_dn_get_linearized(ac->msg->dn));
2505 dsdb_acl_debug(domain_sd, user_token,
2506 domain_dn, true, 10);
2512 * This function is called on LDB modify operations. It performs some additions/
2513 * replaces on the current LDB message when "pwdLastSet" changes.
2515 static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
2517 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2518 NTTIME last_set = 0;
2519 struct ldb_message_element *el = NULL;
2520 struct ldb_message *tmp_msg = NULL;
2521 struct dom_sid *self_sid = NULL;
2523 struct ldb_result *res = NULL;
2524 const char * const attrs[] = {
2529 el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
2530 ac->req->operation);
2531 if (el == NULL || el->num_values == 0) {
2532 ldb_asprintf_errstring(ldb,
2533 "%08X: samldb: 'pwdLastSet' can't be deleted!",
2534 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2535 return LDB_ERR_UNWILLING_TO_PERFORM;
2538 /* Create a temporary message for fetching the "userAccountControl" */
2539 tmp_msg = ldb_msg_new(ac->msg);
2540 if (tmp_msg == NULL) {
2541 return ldb_module_oom(ac->module);
2543 ret = ldb_msg_add(tmp_msg, el, 0);
2544 if (ret != LDB_SUCCESS) {
2547 last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
2548 talloc_free(tmp_msg);
2551 * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
2553 if (last_set != UINT64_MAX) {
2557 /* Fetch the "objectSid" */
2558 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2559 DSDB_FLAG_NEXT_MODULE, ac->req);
2560 if (ret != LDB_SUCCESS) {
2563 self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2564 if (self_sid == NULL) {
2565 return ldb_module_operr(ac->module);
2568 ret = samldb_check_pwd_last_set_acl(ac, self_sid);
2569 if (ret != LDB_SUCCESS) {
2576 static int samldb_lockout_time(struct samldb_ctx *ac)
2578 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2580 struct ldb_message_element *el;
2581 struct ldb_message *tmp_msg;
2584 el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
2585 ac->req->operation);
2586 if (el == NULL || el->num_values == 0) {
2587 ldb_asprintf_errstring(ldb,
2588 "%08X: samldb: 'lockoutTime' can't be deleted!",
2589 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2590 return LDB_ERR_UNWILLING_TO_PERFORM;
2593 /* Create a temporary message for fetching the "lockoutTime" */
2594 tmp_msg = ldb_msg_new(ac->msg);
2595 if (tmp_msg == NULL) {
2596 return ldb_module_oom(ac->module);
2598 ret = ldb_msg_add(tmp_msg, el, 0);
2599 if (ret != LDB_SUCCESS) {
2602 lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
2605 talloc_free(tmp_msg);
2607 if (lockoutTime != 0) {
2611 /* lockoutTime == 0 resets badPwdCount */
2612 ldb_msg_remove_attr(ac->msg, "badPwdCount");
2613 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
2615 if (ret != LDB_SUCCESS) {
2618 el = ldb_msg_find_element(ac->msg, "badPwdCount");
2619 el->flags = LDB_FLAG_MOD_REPLACE;
2624 static int samldb_group_type_change(struct samldb_ctx *ac)
2626 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2627 uint32_t group_type, old_group_type, account_type;
2628 struct ldb_message_element *el;
2629 struct ldb_message *tmp_msg;
2631 struct ldb_result *res;
2632 const char * const attrs[] = { "groupType", NULL };
2634 el = dsdb_get_single_valued_attr(ac->msg, "groupType",
2635 ac->req->operation);
2637 /* we are not affected */
2641 /* Create a temporary message for fetching the "groupType" */
2642 tmp_msg = ldb_msg_new(ac->msg);
2643 if (tmp_msg == NULL) {
2644 return ldb_module_oom(ac->module);
2646 ret = ldb_msg_add(tmp_msg, el, 0);
2647 if (ret != LDB_SUCCESS) {
2650 group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
2651 talloc_free(tmp_msg);
2653 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2654 DSDB_FLAG_NEXT_MODULE |
2655 DSDB_SEARCH_SHOW_DELETED, ac->req);
2656 if (ret != LDB_SUCCESS) {
2659 old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
2660 if (old_group_type == 0) {
2661 return ldb_operr(ldb);
2664 /* Group type switching isn't so easy as it seems: We can only
2665 * change in this directions: global <-> universal <-> local
2666 * On each step also the group type itself
2667 * (security/distribution) is variable. */
2669 if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
2670 switch (group_type) {
2671 case GTYPE_SECURITY_GLOBAL_GROUP:
2672 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
2673 /* change to "universal" allowed */
2674 if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
2675 (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
2676 ldb_set_errstring(ldb,
2677 "samldb: Change from security/distribution local group forbidden!");
2678 return LDB_ERR_UNWILLING_TO_PERFORM;
2682 case GTYPE_SECURITY_UNIVERSAL_GROUP:
2683 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
2684 /* each change allowed */
2686 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
2687 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
2688 /* change to "universal" allowed */
2689 if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
2690 (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
2691 ldb_set_errstring(ldb,
2692 "samldb: Change from security/distribution global group forbidden!");
2693 return LDB_ERR_UNWILLING_TO_PERFORM;
2697 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
2699 /* we don't allow this "groupType" values */
2700 return LDB_ERR_UNWILLING_TO_PERFORM;
2705 account_type = ds_gtype2atype(group_type);
2706 if (account_type == 0) {
2707 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
2708 return LDB_ERR_UNWILLING_TO_PERFORM;
2710 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
2712 if (ret != LDB_SUCCESS) {
2715 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2716 el->flags = LDB_FLAG_MOD_REPLACE;
2721 static int samldb_member_check(struct samldb_ctx *ac)
2723 const char * const attrs[] = { "objectSid", NULL };
2724 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2725 struct ldb_message_element *el;
2726 struct ldb_dn *member_dn;
2727 struct dom_sid *sid;
2728 struct ldb_result *res;
2729 struct dom_sid *group_sid;
2733 /* Fetch information from the existing object */
2735 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2736 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
2737 if (ret != LDB_SUCCESS) {
2740 if (res->count != 1) {
2741 return ldb_operr(ldb);
2744 group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2745 if (group_sid == NULL) {
2746 return ldb_operr(ldb);
2749 /* We've to walk over all modification entries and consider the "member"
2751 for (i = 0; i < ac->msg->num_elements; i++) {
2752 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
2756 el = &ac->msg->elements[i];
2757 for (j = 0; j < el->num_values; j++) {
2758 struct ldb_result *group_res;
2759 const char *group_attrs[] = { "primaryGroupID" , NULL };
2760 uint32_t prim_group_rid;
2762 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2763 /* Deletes will be handled in
2764 * repl_meta_data, and deletes not
2765 * matching a member will return
2766 * LDB_ERR_UNWILLING_TO_PERFORM
2771 member_dn = ldb_dn_from_ldb_val(ac, ldb,
2773 if (!ldb_dn_validate(member_dn)) {
2774 return ldb_operr(ldb);
2777 /* Denies to add "member"s to groups which are primary
2778 * ones for them - in this case return
2779 * ERR_ENTRY_ALREADY_EXISTS. */
2781 ret = dsdb_module_search_dn(ac->module, ac, &group_res,
2782 member_dn, group_attrs,
2783 DSDB_FLAG_NEXT_MODULE, ac->req);
2784 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2785 /* member DN doesn't exist yet */
2788 if (ret != LDB_SUCCESS) {
2791 prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
2792 if (prim_group_rid == (uint32_t) -1) {
2793 /* the member hasn't to be a user account ->
2794 * therefore no check needed in this case. */
2798 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
2801 return ldb_operr(ldb);
2804 if (dom_sid_equal(group_sid, sid)) {
2805 ldb_asprintf_errstring(ldb,
2806 "samldb: member %s already set via primaryGroupID %u",
2807 ldb_dn_get_linearized(member_dn), prim_group_rid);
2808 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2818 /* SAM objects have special rules regarding the "description" attribute on
2819 * modify operations. */
2820 static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
2822 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2823 const char * const attrs[] = { "objectClass", "description", NULL };
2824 struct ldb_result *res;
2828 /* Fetch information from the existing object */
2829 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2830 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
2831 "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
2832 if (ret != LDB_SUCCESS) {
2833 /* don't treat it specially ... let normal error codes
2834 happen from other places */
2835 ldb_reset_err_string(ldb);
2838 if (res->count == 0) {
2839 /* we didn't match the filter */
2844 /* We've to walk over all modification entries and consider the
2845 * "description" ones. */
2846 for (i = 0; i < ac->msg->num_elements; i++) {
2847 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
2848 ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
2858 /* This trigger adapts the "servicePrincipalName" attributes if the
2859 * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
2860 static int samldb_service_principal_names_change(struct samldb_ctx *ac)
2862 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2863 struct ldb_message_element *el = NULL, *el2 = NULL;
2864 struct ldb_message *msg;
2865 const char * const attrs[] = { "servicePrincipalName", NULL };
2866 struct ldb_result *res;
2867 const char *dns_hostname = NULL, *old_dns_hostname = NULL,
2868 *sam_accountname = NULL, *old_sam_accountname = NULL;
2872 el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
2873 ac->req->operation);
2874 el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
2875 ac->req->operation);
2876 if ((el == NULL) && (el2 == NULL)) {
2877 /* we are not affected */
2881 /* Create a temporary message for fetching the "dNSHostName" */
2883 const char *dns_attrs[] = { "dNSHostName", NULL };
2884 msg = ldb_msg_new(ac->msg);
2886 return ldb_module_oom(ac->module);
2888 ret = ldb_msg_add(msg, el, 0);
2889 if (ret != LDB_SUCCESS) {
2892 dns_hostname = talloc_strdup(ac,
2893 ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
2894 if (dns_hostname == NULL) {
2895 return ldb_module_oom(ac->module);
2900 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
2901 dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
2902 if (ret == LDB_SUCCESS) {
2903 old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
2907 /* Create a temporary message for fetching the "sAMAccountName" */
2909 char *tempstr, *tempstr2 = NULL;
2910 const char *acct_attrs[] = { "sAMAccountName", NULL };
2912 msg = ldb_msg_new(ac->msg);
2914 return ldb_module_oom(ac->module);
2916 ret = ldb_msg_add(msg, el2, 0);
2917 if (ret != LDB_SUCCESS) {
2920 tempstr = talloc_strdup(ac,
2921 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
2924 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
2925 DSDB_FLAG_NEXT_MODULE, ac->req);
2926 if (ret == LDB_SUCCESS) {
2927 tempstr2 = talloc_strdup(ac,
2928 ldb_msg_find_attr_as_string(res->msgs[0],
2929 "sAMAccountName", NULL));
2933 /* The "sAMAccountName" needs some additional trimming: we need
2934 * to remove the trailing "$"s if they exist. */
2935 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
2936 (tempstr[strlen(tempstr) - 1] == '$')) {
2937 tempstr[strlen(tempstr) - 1] = '\0';
2939 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
2940 (tempstr2[strlen(tempstr2) - 1] == '$')) {
2941 tempstr2[strlen(tempstr2) - 1] = '\0';
2943 sam_accountname = tempstr;
2944 old_sam_accountname = tempstr2;
2947 if (old_dns_hostname == NULL) {
2948 /* we cannot change when the old name is unknown */
2949 dns_hostname = NULL;
2951 if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
2952 (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
2953 /* The "dNSHostName" didn't change */
2954 dns_hostname = NULL;
2957 if (old_sam_accountname == NULL) {
2958 /* we cannot change when the old name is unknown */
2959 sam_accountname = NULL;
2961 if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
2962 (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
2963 /* The "sAMAccountName" didn't change */
2964 sam_accountname = NULL;
2967 if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
2968 /* Well, there are information missing (old name(s)) or the
2969 * names didn't change. We've nothing to do and can exit here */
2973 /* Potential "servicePrincipalName" changes in the same request have to
2974 * be handled before the update (Windows behaviour). */
2975 el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
2977 msg = ldb_msg_new(ac->msg);
2979 return ldb_module_oom(ac->module);
2981 msg->dn = ac->msg->dn;
2984 ret = ldb_msg_add(msg, el, el->flags);
2985 if (ret != LDB_SUCCESS) {
2989 ldb_msg_remove_element(ac->msg, el);
2991 el = ldb_msg_find_element(ac->msg,
2992 "servicePrincipalName");
2993 } while (el != NULL);
2995 ret = dsdb_module_modify(ac->module, msg,
2996 DSDB_FLAG_NEXT_MODULE, ac->req);
2997 if (ret != LDB_SUCCESS) {
3003 /* Fetch the "servicePrincipalName"s if any */
3004 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
3005 DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
3006 if (ret != LDB_SUCCESS) {
3009 if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
3010 return ldb_operr(ldb);
3013 if (res->msgs[0]->num_elements == 1) {
3015 * Yes, we do have "servicePrincipalName"s. First we update them
3016 * locally, that means we do always substitute the current
3017 * "dNSHostName" with the new one and/or "sAMAccountName"
3018 * without "$" with the new one and then we append the
3019 * modified "servicePrincipalName"s as a message element
3020 * replace to the modification request (Windows behaviour). We
3021 * need also to make sure that the values remain case-
3022 * insensitively unique.
3025 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
3026 LDB_FLAG_MOD_REPLACE, &el);
3027 if (ret != LDB_SUCCESS) {
3031 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
3032 char *old_str, *new_str;
3035 struct ldb_val *vals;
3039 res->msgs[0]->elements[0].values[i].data;
3041 new_str = talloc_strdup(ac->msg,
3042 strtok_r(old_str, "/", &pos));
3043 if (new_str == NULL) {
3044 return ldb_module_oom(ac->module);
3047 while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
3048 if ((dns_hostname != NULL) &&
3049 (strcasecmp_m(tok, old_dns_hostname) == 0)) {
3052 if ((sam_accountname != NULL) &&
3053 (strcasecmp_m(tok, old_sam_accountname) == 0)) {
3054 tok = sam_accountname;
3057 new_str = talloc_asprintf(ac->msg, "%s/%s",
3059 if (new_str == NULL) {
3060 return ldb_module_oom(ac->module);
3064 /* Uniqueness check */
3065 for (j = 0; (!found) && (j < el->num_values); j++) {
3066 if (strcasecmp_m((char *)el->values[j].data,
3076 * append the new "servicePrincipalName" -
3077 * code derived from ldb_msg_add_value().
3079 * Open coded to make it clear that we must
3080 * append to the MOD_REPLACE el created above.
3082 vals = talloc_realloc(ac->msg, el->values,
3084 el->num_values + 1);
3086 return ldb_module_oom(ac->module);
3089 el->values[el->num_values] = data_blob_string_const(new_str);
3099 /* This checks the "fSMORoleOwner" attributes */
3100 static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
3102 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3103 const char * const no_attrs[] = { NULL };
3104 struct ldb_message_element *el;
3105 struct ldb_message *tmp_msg;
3106 struct ldb_dn *res_dn;
3107 struct ldb_result *res;
3110 el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
3111 ac->req->operation);
3113 /* we are not affected */
3117 /* Create a temporary message for fetching the "fSMORoleOwner" */
3118 tmp_msg = ldb_msg_new(ac->msg);
3119 if (tmp_msg == NULL) {
3120 return ldb_module_oom(ac->module);
3122 ret = ldb_msg_add(tmp_msg, el, 0);
3123 if (ret != LDB_SUCCESS) {
3126 res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
3127 talloc_free(tmp_msg);
3129 if (res_dn == NULL) {
3130 ldb_set_errstring(ldb,
3131 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3132 if (ac->req->operation == LDB_ADD) {
3133 return LDB_ERR_CONSTRAINT_VIOLATION;
3135 return LDB_ERR_UNWILLING_TO_PERFORM;
3139 /* Fetched DN has to reference a "nTDSDSA" entry */
3140 ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
3142 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3143 ac->req, "(objectClass=nTDSDSA)");
3144 if (ret != LDB_SUCCESS) {
3147 if (res->count != 1) {
3148 ldb_set_errstring(ldb,
3149 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3150 return LDB_ERR_UNWILLING_TO_PERFORM;
3159 * Return zero if the number of zero bits in the address (looking from low to
3160 * high) is equal to or greater than the length minus the mask. Otherwise it
3163 static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
3166 /* <address> is an integer in big-endian form, <len> bits long. All
3167 bits between <mask> and <len> must be zero. */
3169 unsigned int byte_len;
3170 unsigned int byte_mask;
3171 unsigned int bit_mask;
3173 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
3174 address[0], address[1], address[2], address[3],
3176 } else if (len == 128){
3177 DBG_INFO("Looking at address "
3178 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
3179 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
3180 address[0], address[1], address[2], address[3],
3181 address[4], address[5], address[6], address[7],
3182 address[8], address[9], address[10], address[11],
3183 address[12], address[13], address[14], address[15],
3188 DBG_INFO("mask %u is too big (> %u)\n", mask, len);
3192 /* single address subnet.
3193 * In IPv4 all 255s is invalid by the bitmask != address rule
3194 * in MS-ADTS. IPv6 does not suffer.
3197 if (address[0] == 255 &&
3198 address[1] == 255 &&
3199 address[2] == 255 &&
3208 byte_mask = mask / 8;
3210 for (i = byte_len - 1; i > byte_mask; i--){
3211 DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
3212 if (address[i] != 0){
3216 bit_mask = (1 << (8 - (mask & 7))) - 1;
3217 DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
3218 bit_mask & address[byte_mask]);
3219 if (address[byte_mask] & bit_mask){
3223 /* According to MS-ADTS, the mask can't exactly equal the bitmask for
3224 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
3225 * because the bitmask implied by "/17" is 255.255.80.0.
3227 * The bit_mask used in the previous check is the complement of what
3230 if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
3232 for (i = 0; i < byte_mask; i++){
3233 if (address[i] != 255){
3247 static int check_address_roundtrip(const char *address, int family,
3248 const uint8_t *address_bytes,
3249 char *buffer, int buffer_len)
3252 * Check that the address is in the canonical RFC5952 format for IPv6,
3253 * and lacks extra leading zeros for each dotted decimal for IPv4.
3254 * Handily this is what inet_ntop() gives you.
3256 const char *address_redux = inet_ntop(family, address_bytes,
3257 buffer, buffer_len);
3258 if (address_redux == NULL){
3259 DBG_INFO("Address round trip %s failed unexpectedly"
3260 " with errno %d\n", address, errno);
3263 if (strcasecmp(address, address_redux) != 0){
3264 DBG_INFO("Address %s round trips to %s; fail!\n",
3265 address, address_redux);
3266 /* If the address family is IPv6, and the address is in a
3270 if (strchr(address_redux, '.') != NULL){
3271 DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
3272 "lying in a range that was once used for "
3273 "IPv4 embedding (that is, it might also be "
3274 "represented as '%s').\n", address,
3285 * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
3286 * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
3287 * CIDR address range without saying so explicitly. Here we follow the CIDR
3290 * Return 0 on success, -1 on error.
3292 static int verify_cidr(const char *cidr)
3294 char *address = NULL, *slash = NULL, *endptr = NULL;
3295 bool has_colon, has_dot;
3298 uint8_t *address_bytes = NULL;
3299 char *address_redux = NULL;
3300 unsigned int address_len;
3301 TALLOC_CTX *frame = NULL;
3303 DBG_DEBUG("CIDR is %s\n", cidr);
3304 frame = talloc_stackframe();
3305 address = talloc_strdup(frame, cidr);
3306 if (address == NULL){
3310 /* there must be a '/' */
3311 slash = strchr(address, '/');
3315 /* terminate the address for strchr, inet_pton */
3318 mask = strtoul(slash + 1, &endptr, 10);
3320 DBG_INFO("Windows does not like the zero mask, "
3321 "so nor do we: %s\n", cidr);
3325 if (*endptr != '\0' || endptr == slash + 1){
3326 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
3330 address_bytes = talloc_size(frame, sizeof(struct in6_addr));
3331 if (address_bytes == NULL){
3335 address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
3336 if (address_redux == NULL){
3340 DBG_INFO("found address %s, mask %lu\n", address, mask);
3341 has_colon = (strchr(address, ':') == NULL) ? false : true;
3342 has_dot = (strchr(address, '.') == NULL) ? false : true;
3343 if (has_dot && has_colon){
3344 /* This seems to be an IPv4 address embedded in IPv6, which is
3345 icky. We don't support it. */
3346 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
3349 } else if (has_colon){ /* looks like IPv6 */
3350 res = inet_pton(AF_INET6, address, address_bytes);
3352 DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
3356 if (check_address_roundtrip(address, AF_INET6, address_bytes,
3357 address_redux, INET6_ADDRSTRLEN)){
3360 } else if (has_dot) {
3361 /* looks like IPv4 */
3362 if (strcmp(address, "0.0.0.0") == 0){
3363 DBG_INFO("Windows does not like the zero IPv4 address, "
3367 res = inet_pton(AF_INET, address, address_bytes);
3369 DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
3374 if (check_address_roundtrip(address, AF_INET, address_bytes,
3375 address_redux, INET_ADDRSTRLEN)){
3379 /* This doesn't look like an IP address at all. */
3383 ret = check_cidr_zero_bits(address_bytes, address_len, mask);
3392 static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
3394 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3395 const char *cidr = NULL;
3396 const struct ldb_val *rdn_value = NULL;
3398 rdn_value = ldb_dn_get_rdn_val(dn);
3399 if (rdn_value == NULL) {
3400 ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
3402 return LDB_ERR_UNWILLING_TO_PERFORM;
3405 cidr = ldb_dn_escape_value(ac, *rdn_value);
3406 DBG_INFO("looking at cidr '%s'\n", cidr);
3408 ldb_set_errstring(ldb,
3409 "samldb: adding an empty subnet cidr seems wrong");
3410 return LDB_ERR_UNWILLING_TO_PERFORM;
3413 if (verify_cidr(cidr)){
3414 ldb_set_errstring(ldb,
3415 "samldb: subnet value is invalid");
3416 return LDB_ERR_INVALID_DN_SYNTAX;
3422 static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
3426 struct loadparm_context *lp_ctx;
3431 if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
3432 ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
3436 ret = samdb_rodc(ldb, &rodc);
3437 if (ret != LDB_SUCCESS) {
3438 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
3443 const char *domain = NULL;
3444 struct ldb_dn *fsmo_role_dn;
3445 struct ldb_dn *role_owner_dn;
3446 ldb_set_errstring(ldb, "RODC modify is forbidden!");
3447 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3448 struct loadparm_context);
3450 err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3451 &fsmo_role_dn, &role_owner_dn);
3452 if (W_ERROR_IS_OK(err)) {
3453 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3454 if (server_dn != NULL) {
3455 ldb_dn_remove_child_components(server_dn, 1);
3457 domain = samdb_dn_to_dnshostname(ldb, req,
3461 if (domain == NULL) {
3462 domain = lpcfg_dnsdomain(lp_ctx);
3464 referral = talloc_asprintf(req,
3467 ldb_dn_get_linearized(dn));
3476 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
3478 struct ldb_context *ldb;
3479 struct samldb_ctx *ac;
3480 struct ldb_message_element *el;
3482 char *referral = NULL;
3484 ldb = ldb_module_get_ctx(module);
3485 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
3487 /* do not manipulate our control entries */
3488 if (ldb_dn_is_special(req->op.add.message->dn)) {
3489 return ldb_next_request(module, req);
3492 referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
3493 if (referral != NULL) {
3494 ret = ldb_module_send_referral(req, referral);
3498 el = ldb_msg_find_element(req->op.add.message, "userParameters");
3499 if (el != NULL && ldb_req_is_untrusted(req)) {
3500 const char *reason = "samldb_add: "
3501 "setting userParameters is not supported over LDAP, "
3502 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3503 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3504 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3507 ac = samldb_ctx_init(module, req);
3509 return ldb_operr(ldb);
3512 /* build the new msg */
3513 ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
3514 if (ac->msg == NULL) {
3516 ldb_debug(ldb, LDB_DEBUG_FATAL,
3517 "samldb_add: ldb_msg_copy_shallow failed!\n");
3518 return ldb_operr(ldb);
3521 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3523 ret = samldb_fsmo_role_owner_check(ac);
3524 if (ret != LDB_SUCCESS) {
3529 if (samdb_find_attribute(ldb, ac->msg,
3530 "objectclass", "user") != NULL) {
3531 ac->type = SAMLDB_TYPE_USER;
3533 ret = samldb_prim_group_trigger(ac);
3534 if (ret != LDB_SUCCESS) {
3538 ret = samldb_objectclass_trigger(ac);
3539 if (ret != LDB_SUCCESS) {
3543 return samldb_fill_object(ac);
3546 if (samdb_find_attribute(ldb, ac->msg,
3547 "objectclass", "group") != NULL) {
3548 ac->type = SAMLDB_TYPE_GROUP;
3550 ret = samldb_objectclass_trigger(ac);
3551 if (ret != LDB_SUCCESS) {
3555 return samldb_fill_object(ac);
3558 /* perhaps a foreignSecurityPrincipal? */
3559 if (samdb_find_attribute(ldb, ac->msg,
3561 "foreignSecurityPrincipal") != NULL) {
3562 return samldb_fill_foreignSecurityPrincipal_object(ac);
3565 if (samdb_find_attribute(ldb, ac->msg,
3566 "objectclass", "classSchema") != NULL) {
3567 ac->type = SAMLDB_TYPE_CLASS;
3569 /* If in provision, these checks are too slow to do */
3570 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3571 ret = samldb_schema_governsid_valid_check(ac);
3572 if (ret != LDB_SUCCESS) {
3577 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3578 if (ret != LDB_SUCCESS) {
3582 ret = samldb_schema_info_update(ac);
3583 if (ret != LDB_SUCCESS) {
3588 return samldb_fill_object(ac);
3591 if (samdb_find_attribute(ldb, ac->msg,
3592 "objectclass", "attributeSchema") != NULL) {
3593 ac->type = SAMLDB_TYPE_ATTRIBUTE;
3595 /* If in provision, these checks are too slow to do */
3596 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3597 ret = samldb_schema_attributeid_valid_check(ac);
3598 if (ret != LDB_SUCCESS) {
3602 ret = samldb_schema_add_handle_linkid(ac);
3603 if (ret != LDB_SUCCESS) {
3607 ret = samldb_schema_add_handle_mapiid(ac);
3608 if (ret != LDB_SUCCESS) {
3613 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3614 if (ret != LDB_SUCCESS) {
3618 ret = samldb_schema_info_update(ac);
3619 if (ret != LDB_SUCCESS) {
3624 return samldb_fill_object(ac);
3627 if (samdb_find_attribute(ldb, ac->msg,
3628 "objectclass", "subnet") != NULL) {
3629 ret = samldb_verify_subnet(ac, ac->msg->dn);
3630 if (ret != LDB_SUCCESS) {
3634 /* We are just checking the value is valid, and there are no
3635 values to fill in. */
3640 /* nothing matched, go on */
3641 return ldb_next_request(module, req);
3645 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
3647 struct ldb_context *ldb;
3648 struct samldb_ctx *ac;
3649 struct ldb_message_element *el, *el2;
3650 struct ldb_control *is_undelete;
3651 bool modified = false;
3654 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3655 /* do not manipulate our control entries */
3656 return ldb_next_request(module, req);
3659 ldb = ldb_module_get_ctx(module);
3662 * we are going to need some special handling if in Undelete call.
3663 * Since tombstone_reanimate module will restore certain attributes,
3664 * we need to relax checks for: sAMAccountType, primaryGroupID
3666 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3668 /* make sure that "objectSid" is not specified */
3669 el = ldb_msg_find_element(req->op.mod.message, "objectSid");
3671 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
3672 ldb_set_errstring(ldb,
3673 "samldb: objectSid must not be specified!");
3674 return LDB_ERR_UNWILLING_TO_PERFORM;
3677 if (is_undelete == NULL) {
3678 /* make sure that "sAMAccountType" is not specified */
3679 el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
3681 ldb_set_errstring(ldb,
3682 "samldb: sAMAccountType must not be specified!");
3683 return LDB_ERR_UNWILLING_TO_PERFORM;
3686 /* make sure that "isCriticalSystemObject" is not specified */
3687 el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
3689 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
3690 ldb_set_errstring(ldb,
3691 "samldb: isCriticalSystemObject must not be specified!");
3692 return LDB_ERR_UNWILLING_TO_PERFORM;
3696 /* msDS-IntId is not allowed to be modified
3697 * except when modification comes from replication */
3698 if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
3699 if (!ldb_request_get_control(req,
3700 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
3701 return LDB_ERR_CONSTRAINT_VIOLATION;
3705 el = ldb_msg_find_element(req->op.mod.message, "userParameters");
3706 if (el != NULL && ldb_req_is_untrusted(req)) {
3707 const char *reason = "samldb: "
3708 "setting userParameters is not supported over LDAP, "
3709 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3710 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3711 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3714 ac = samldb_ctx_init(module, req);
3716 return ldb_operr(ldb);
3719 /* build the new msg */
3720 ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3721 if (ac->msg == NULL) {
3723 ldb_debug(ldb, LDB_DEBUG_FATAL,
3724 "samldb_modify: ldb_msg_copy_shallow failed!\n");
3725 return ldb_operr(ldb);
3728 if (is_undelete == NULL) {
3729 el = ldb_msg_find_element(ac->msg, "primaryGroupID");
3731 ret = samldb_prim_group_trigger(ac);
3732 if (ret != LDB_SUCCESS) {
3738 el = ldb_msg_find_element(ac->msg, "userAccountControl");
3741 ret = samldb_user_account_control_change(ac);
3742 if (ret != LDB_SUCCESS) {
3747 el = ldb_msg_find_element(ac->msg, "pwdLastSet");
3750 ret = samldb_pwd_last_set_change(ac);
3751 if (ret != LDB_SUCCESS) {
3756 el = ldb_msg_find_element(ac->msg, "lockoutTime");
3759 ret = samldb_lockout_time(ac);
3760 if (ret != LDB_SUCCESS) {
3765 el = ldb_msg_find_element(ac->msg, "groupType");
3768 ret = samldb_group_type_change(ac);
3769 if (ret != LDB_SUCCESS) {
3774 el = ldb_msg_find_element(ac->msg, "sAMAccountName");
3776 ret = samldb_sam_accountname_valid_check(ac);
3778 * Other errors are checked for elsewhere, we just
3779 * want to prevent duplicates
3781 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
3786 el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
3788 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3789 if (ret != LDB_SUCCESS) {
3794 el = ldb_msg_find_element(ac->msg, "attributeID");
3796 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3797 "Once set, attributeID values may not be modified");
3798 return LDB_ERR_CONSTRAINT_VIOLATION;
3801 el = ldb_msg_find_element(ac->msg, "governsID");
3803 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3804 "Once set, governsID values may not be modified");
3805 return LDB_ERR_CONSTRAINT_VIOLATION;
3808 el = ldb_msg_find_element(ac->msg, "member");
3810 ret = samldb_member_check(ac);
3811 if (ret != LDB_SUCCESS) {
3816 el = ldb_msg_find_element(ac->msg, "description");
3818 ret = samldb_description_check(ac, &modified);
3819 if (ret != LDB_SUCCESS) {
3824 el = ldb_msg_find_element(ac->msg, "dNSHostName");
3825 el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
3826 if ((el != NULL) || (el2 != NULL)) {
3828 ret = samldb_service_principal_names_change(ac);
3829 if (ret != LDB_SUCCESS) {
3834 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3836 ret = samldb_fsmo_role_owner_check(ac);
3837 if (ret != LDB_SUCCESS) {
3843 struct ldb_request *child_req;
3845 /* Now perform the real modifications as a child request */
3846 ret = ldb_build_mod_req(&child_req, ldb, ac,
3849 req, dsdb_next_callback,
3851 LDB_REQ_SET_LOCATION(child_req);
3852 if (ret != LDB_SUCCESS) {
3856 return ldb_next_request(module, child_req);
3861 /* no change which interests us, go on */
3862 return ldb_next_request(module, req);
3867 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
3869 struct ldb_context *ldb;
3870 struct dom_sid *sid;
3874 struct ldb_result *res;
3875 const char * const attrs[] = { "objectSid", "isDeleted", NULL };
3876 const char * const noattrs[] = { NULL };
3878 ldb = ldb_module_get_ctx(ac->module);
3880 /* Finds out the SID/RID of the SAM object */
3881 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
3883 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3885 if (ret != LDB_SUCCESS) {
3889 if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
3893 sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
3895 /* No SID - it might not be a SAM object - therefore ok */
3898 status = dom_sid_split_rid(ac, sid, NULL, &rid);
3899 if (!NT_STATUS_IS_OK(status)) {
3900 return ldb_operr(ldb);
3903 /* Special object (security principal?) */
3906 /* do not allow deletion of well-known sids */
3907 if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
3908 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
3909 return LDB_ERR_OTHER;
3912 /* Deny delete requests from groups which are primary ones */
3913 ret = dsdb_module_search(ac->module, ac, &res,
3914 ldb_get_default_basedn(ldb),
3915 LDB_SCOPE_SUBTREE, noattrs,
3916 DSDB_FLAG_NEXT_MODULE,
3918 "(&(primaryGroupID=%u)(objectClass=user))", rid);
3919 if (ret != LDB_SUCCESS) {
3922 if (res->count > 0) {
3923 return LDB_ERR_ENTRY_ALREADY_EXISTS;
3929 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
3931 struct samldb_ctx *ac;
3932 char *referral = NULL;
3934 struct ldb_context *ldb;
3936 if (ldb_dn_is_special(req->op.del.dn)) {
3937 /* do not manipulate our control entries */
3938 return ldb_next_request(module, req);
3941 ldb = ldb_module_get_ctx(module);
3943 referral = refer_if_rodc(ldb, req, req->op.del.dn);
3944 if (referral != NULL) {
3945 ret = ldb_module_send_referral(req, referral);
3949 ac = samldb_ctx_init(module, req);
3951 return ldb_operr(ldb_module_get_ctx(module));
3954 ret = samldb_prim_group_users_check(ac);
3955 if (ret != LDB_SUCCESS) {
3961 return ldb_next_request(module, req);
3966 static int check_rename_constraints(struct ldb_message *msg,
3967 struct samldb_ctx *ac,
3968 struct ldb_dn *olddn, struct ldb_dn *newdn)
3970 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3971 struct ldb_dn *dn1, *dn2, *nc_root;
3972 int32_t systemFlags;
3973 bool move_op = false;
3974 bool rename_op = false;
3977 /* Skip the checks if old and new DN are the same, or if we have the
3978 * relax control specified or if the returned objects is already
3979 * deleted and needs only to be moved for consistency. */
3981 if (ldb_dn_compare(olddn, newdn) == 0) {
3984 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
3988 if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
3990 * check originating request if we are supposed
3991 * to "see" this record in first place.
3993 if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
3994 return LDB_ERR_NO_SUCH_OBJECT;
3996 return LDB_ERR_UNWILLING_TO_PERFORM;
3999 /* Objects under CN=System */
4001 dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
4002 if (dn1 == NULL) return ldb_oom(ldb);
4004 if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
4006 return LDB_ERR_OPERATIONS_ERROR;
4009 if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
4010 (ldb_dn_compare_base(dn1, newdn) != 0)) {
4012 ldb_asprintf_errstring(ldb,
4013 "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
4014 ldb_dn_get_linearized(olddn));
4015 return LDB_ERR_OTHER;
4022 if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
4023 (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
4024 ldb_asprintf_errstring(ldb,
4025 "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
4026 ldb_dn_get_linearized(olddn));
4027 return LDB_ERR_UNWILLING_TO_PERFORM;
4030 /* subnet objects */
4031 if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
4032 ret = samldb_verify_subnet(ac, newdn);
4033 if (ret != LDB_SUCCESS) {
4041 dn1 = ldb_dn_get_parent(ac, olddn);
4042 if (dn1 == NULL) return ldb_oom(ldb);
4043 dn2 = ldb_dn_get_parent(ac, newdn);
4044 if (dn2 == NULL) return ldb_oom(ldb);
4046 if (ldb_dn_compare(dn1, dn2) == 0) {
4055 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
4057 /* Fetch name context */
4059 ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
4060 if (ret != LDB_SUCCESS) {
4064 if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
4066 ldb_asprintf_errstring(ldb,
4067 "subtree_rename: Cannot move %s within schema partition",
4068 ldb_dn_get_linearized(olddn));
4069 return LDB_ERR_UNWILLING_TO_PERFORM;
4072 (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
4073 ldb_asprintf_errstring(ldb,
4074 "subtree_rename: Cannot rename %s within schema partition",
4075 ldb_dn_get_linearized(olddn));
4076 return LDB_ERR_UNWILLING_TO_PERFORM;
4078 } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
4080 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
4081 /* Here we have to do more: control the
4082 * "ALLOW_LIMITED_MOVE" flag. This means that the
4083 * grand-grand-parents of two objects have to be equal
4084 * in order to perform the move (this is used for
4085 * moving "server" objects in the "sites" container). */
4087 systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
4090 dn1 = ldb_dn_copy(ac, olddn);
4091 if (dn1 == NULL) return ldb_oom(ldb);
4092 dn2 = ldb_dn_copy(ac, newdn);
4093 if (dn2 == NULL) return ldb_oom(ldb);
4095 limited_move &= ldb_dn_remove_child_components(dn1, 3);
4096 limited_move &= ldb_dn_remove_child_components(dn2, 3);
4097 limited_move &= ldb_dn_compare(dn1, dn2) == 0;
4104 && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
4105 ldb_asprintf_errstring(ldb,
4106 "subtree_rename: Cannot move %s to %s in config partition",
4107 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4108 return LDB_ERR_UNWILLING_TO_PERFORM;
4112 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
4113 ldb_asprintf_errstring(ldb,
4114 "subtree_rename: Cannot rename %s to %s within config partition",
4115 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4116 return LDB_ERR_UNWILLING_TO_PERFORM;
4118 } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
4120 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
4121 ldb_asprintf_errstring(ldb,
4122 "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
4123 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4124 return LDB_ERR_UNWILLING_TO_PERFORM;
4127 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
4128 ldb_asprintf_errstring(ldb,
4129 "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
4130 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4131 return LDB_ERR_UNWILLING_TO_PERFORM;
4135 talloc_free(nc_root);
4141 static int samldb_rename_search_base_callback(struct ldb_request *req,
4142 struct ldb_reply *ares)
4144 struct samldb_ctx *ac;
4147 ac = talloc_get_type(req->context, struct samldb_ctx);
4150 return ldb_module_done(ac->req, NULL, NULL,
4151 LDB_ERR_OPERATIONS_ERROR);
4153 if (ares->error != LDB_SUCCESS) {
4154 return ldb_module_done(ac->req, ares->controls,
4155 ares->response, ares->error);
4158 switch (ares->type) {
4159 case LDB_REPLY_ENTRY:
4161 * This is the root entry of the originating move
4162 * respectively rename request. It has been already
4163 * stored in the list using "subtree_rename_search()".
4164 * Only this one is subject to constraint checking.
4166 ret = check_rename_constraints(ares->message, ac,
4167 ac->req->op.rename.olddn,
4168 ac->req->op.rename.newdn);
4169 if (ret != LDB_SUCCESS) {
4170 return ldb_module_done(ac->req, NULL, NULL,
4175 case LDB_REPLY_REFERRAL:
4179 case LDB_REPLY_DONE:
4182 * Great, no problem with the rename, so go ahead as
4183 * if we never were here
4185 ret = ldb_next_request(ac->module, ac->req);
4196 static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
4198 struct ldb_context *ldb;
4199 static const char * const attrs[] = { "objectClass", "systemFlags",
4200 "isDeleted", NULL };
4201 struct ldb_request *search_req;
4202 struct samldb_ctx *ac;
4205 if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
4206 return ldb_next_request(module, req);
4209 ldb = ldb_module_get_ctx(module);
4211 ac = samldb_ctx_init(module, req);
4213 return ldb_oom(ldb);
4216 ret = ldb_build_search_req(&search_req, ldb, ac,
4217 req->op.rename.olddn,
4223 samldb_rename_search_base_callback,
4225 LDB_REQ_SET_LOCATION(search_req);
4226 if (ret != LDB_SUCCESS) {
4230 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4232 if (ret != LDB_SUCCESS) {
4236 return ldb_next_request(ac->module, search_req);
4241 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
4243 struct ldb_context *ldb = ldb_module_get_ctx(module);
4244 struct dsdb_fsmo_extended_op *exop;
4247 exop = talloc_get_type(req->op.extended.data,
4248 struct dsdb_fsmo_extended_op);
4250 ldb_set_errstring(ldb,
4251 "samldb_extended_allocate_rid_pool: invalid extended data");
4252 return LDB_ERR_PROTOCOL_ERROR;
4255 ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
4256 if (ret != LDB_SUCCESS) {
4260 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4263 static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
4265 struct ldb_context *ldb = ldb_module_get_ctx(module);
4266 struct dsdb_extended_allocate_rid *exop;
4269 exop = talloc_get_type(req->op.extended.data,
4270 struct dsdb_extended_allocate_rid);
4272 ldb_set_errstring(ldb,
4273 "samldb_extended_allocate_rid: invalid extended data");
4274 return LDB_ERR_PROTOCOL_ERROR;
4277 ret = ridalloc_allocate_rid(module, &exop->rid, req);
4278 if (ret != LDB_SUCCESS) {
4282 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4285 static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
4287 struct ldb_context *ldb = ldb_module_get_ctx(module);
4291 if (req->op.extended.data != NULL) {
4292 ldb_set_errstring(ldb,
4293 "samldb_extended_allocate_rid_pool_for_us: invalid extended data (should be NULL)");
4294 return LDB_ERR_PROTOCOL_ERROR;
4297 ret = ridalloc_create_own_rid_set(module, req,
4299 if (ret != LDB_SUCCESS) {
4303 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4306 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
4308 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
4309 return samldb_extended_allocate_rid_pool(module, req);
4312 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
4313 return samldb_extended_allocate_rid(module, req);
4316 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
4317 return samldb_extended_create_own_rid_set(module, req);
4320 return ldb_next_request(module, req);
4324 static const struct ldb_module_ops ldb_samldb_module_ops = {
4327 .modify = samldb_modify,
4328 .del = samldb_delete,
4329 .rename = samldb_rename,
4330 .extended = samldb_extended
4334 int ldb_samldb_module_init(const char *version)
4336 LDB_MODULE_CHECK_VERSION(version);
4337 return ldb_register_module(&ldb_samldb_module_ops);