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)
348 bool ok, found = false;
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)) {
879 msds_intid = generate_random() % 0X3FFFFFFF;
880 msds_intid += 0x80000000;
885 ret = dsdb_module_search(ac->module, ac,
887 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
888 DSDB_FLAG_NEXT_MODULE,
890 "(msDS-IntId=%d)", msds_intid);
891 if (ret != LDB_SUCCESS) {
892 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
893 __location__": Searching for msDS-IntId=%d failed - %s\n",
896 return ldb_operr(ldb);
898 id_exists = (ldb_res->count > 0);
899 talloc_free(ldb_res);
902 msds_intid_struct->msds_intid = msds_intid;
903 ldb_set_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE, msds_intid_struct);
905 return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
911 * samldb_add_entry (async)
914 static int samldb_add_entry_callback(struct ldb_request *req,
915 struct ldb_reply *ares)
917 struct ldb_context *ldb;
918 struct samldb_ctx *ac;
921 ac = talloc_get_type(req->context, struct samldb_ctx);
922 ldb = ldb_module_get_ctx(ac->module);
925 return ldb_module_done(ac->req, NULL, NULL,
926 LDB_ERR_OPERATIONS_ERROR);
929 if (ares->type == LDB_REPLY_REFERRAL) {
930 return ldb_module_send_referral(ac->req, ares->referral);
933 if (ares->error != LDB_SUCCESS) {
934 return ldb_module_done(ac->req, ares->controls,
935 ares->response, ares->error);
937 if (ares->type != LDB_REPLY_DONE) {
938 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
939 return ldb_module_done(ac->req, NULL, NULL,
940 LDB_ERR_OPERATIONS_ERROR);
943 /* The caller may wish to get controls back from the add */
944 ac->ares = talloc_steal(ac, ares);
946 ret = samldb_next_step(ac);
947 if (ret != LDB_SUCCESS) {
948 return ldb_module_done(ac->req, NULL, NULL, ret);
953 static int samldb_add_entry(struct samldb_ctx *ac)
955 struct ldb_context *ldb;
956 struct ldb_request *req;
959 ldb = ldb_module_get_ctx(ac->module);
961 ret = ldb_build_add_req(&req, ldb, ac,
964 ac, samldb_add_entry_callback,
966 LDB_REQ_SET_LOCATION(req);
967 if (ret != LDB_SUCCESS) {
971 return ldb_next_request(ac->module, req);
975 * return true if msg carries an attributeSchema that is intended to be RODC
976 * filtered but is also a system-critical attribute.
978 static bool check_rodc_critical_attribute(struct ldb_message *msg)
980 uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
982 schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
983 searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
984 rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
985 | SEARCH_FLAG_CONFIDENTIAL);
987 if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
988 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
996 static int samldb_fill_object(struct samldb_ctx *ac)
998 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1001 /* Add information for the different account types */
1003 case SAMLDB_TYPE_USER: {
1004 struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
1005 LDB_CONTROL_RODC_DCPROMO_OID);
1006 if (rodc_control != NULL) {
1007 /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
1008 rodc_control->critical = false;
1009 ret = samldb_add_step(ac, samldb_rodc_add);
1010 if (ret != LDB_SUCCESS) return ret;
1013 /* check if we have a valid sAMAccountName */
1014 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1015 if (ret != LDB_SUCCESS) return ret;
1017 ret = samldb_add_step(ac, samldb_add_entry);
1018 if (ret != LDB_SUCCESS) return ret;
1022 case SAMLDB_TYPE_GROUP: {
1023 /* check if we have a valid sAMAccountName */
1024 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1025 if (ret != LDB_SUCCESS) return ret;
1027 ret = samldb_add_step(ac, samldb_add_entry);
1028 if (ret != LDB_SUCCESS) return ret;
1032 case SAMLDB_TYPE_CLASS: {
1033 const char *lDAPDisplayName = NULL;
1034 const struct ldb_val *rdn_value, *def_obj_cat_val;
1035 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
1037 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
1038 if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
1039 ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
1040 if (ret != LDB_SUCCESS) return ret;
1043 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1045 if (ret != LDB_SUCCESS) return ret;
1047 /* do not allow one to mark an attributeSchema as RODC filtered if it
1048 * is system-critical */
1049 if (check_rodc_critical_attribute(ac->msg)) {
1050 ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
1051 ldb_dn_get_linearized(ac->msg->dn));
1052 return LDB_ERR_UNWILLING_TO_PERFORM;
1055 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1056 if (rdn_value == NULL) {
1057 return ldb_operr(ldb);
1059 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1060 /* the RDN has prefix "CN" */
1061 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1062 samdb_cn_to_lDAPDisplayName(ac->msg,
1063 (const char *) rdn_value->data));
1064 if (ret != LDB_SUCCESS) {
1070 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1073 ret = ldb_valid_attr_name(lDAPDisplayName);
1075 lDAPDisplayName[0] == '*' ||
1076 lDAPDisplayName[0] == '@')
1078 return dsdb_module_werror(ac->module,
1079 LDB_ERR_UNWILLING_TO_PERFORM,
1080 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1081 "lDAPDisplayName is invalid");
1084 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1087 guid = GUID_random();
1088 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1089 if (ret != LDB_SUCCESS) {
1095 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
1096 "defaultObjectCategory");
1097 if (def_obj_cat_val != NULL) {
1098 /* "defaultObjectCategory" has been set by the caller.
1099 * Do some checks for consistency.
1100 * NOTE: The real constraint check (that
1101 * 'defaultObjectCategory' is the DN of the new
1102 * objectclass or any parent of it) is still incomplete.
1103 * For now we say that 'defaultObjectCategory' is valid
1104 * if it exists and it is of objectclass "classSchema".
1106 ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
1107 if (ac->dn == NULL) {
1108 ldb_set_errstring(ldb,
1109 "Invalid DN for 'defaultObjectCategory'!");
1110 return LDB_ERR_CONSTRAINT_VIOLATION;
1113 /* "defaultObjectCategory" has not been set by the
1114 * caller. Use the entry DN for it. */
1115 ac->dn = ac->msg->dn;
1117 ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
1118 ldb_dn_alloc_linearized(ac->msg, ac->dn));
1119 if (ret != LDB_SUCCESS) {
1125 ret = samldb_add_step(ac, samldb_add_entry);
1126 if (ret != LDB_SUCCESS) return ret;
1128 /* Now perform the checks for the 'defaultObjectCategory'. The
1129 * lookup DN was already saved in "ac->dn" */
1130 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
1131 if (ret != LDB_SUCCESS) return ret;
1133 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
1135 /* Windows 2003 does this*/
1136 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
1137 if (ret != LDB_SUCCESS) {
1144 case SAMLDB_TYPE_ATTRIBUTE: {
1145 const char *lDAPDisplayName = NULL;
1146 const struct ldb_val *rdn_value;
1147 struct ldb_message_element *el;
1148 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1149 if (rdn_value == NULL) {
1150 return ldb_operr(ldb);
1152 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1153 /* the RDN has prefix "CN" */
1154 ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1155 samdb_cn_to_lDAPDisplayName(ac->msg,
1156 (const char *) rdn_value->data));
1157 if (ret != LDB_SUCCESS) {
1163 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1166 ret = ldb_valid_attr_name(lDAPDisplayName);
1168 lDAPDisplayName[0] == '*' ||
1169 lDAPDisplayName[0] == '@')
1171 return dsdb_module_werror(ac->module,
1172 LDB_ERR_UNWILLING_TO_PERFORM,
1173 WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1174 "lDAPDisplayName is invalid");
1177 /* do not allow one to mark an attributeSchema as RODC filtered if it
1178 * is system-critical */
1179 if (check_rodc_critical_attribute(ac->msg)) {
1180 ldb_asprintf_errstring(ldb,
1181 "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
1182 ldb_dn_get_linearized(ac->msg->dn));
1183 return LDB_ERR_UNWILLING_TO_PERFORM;
1186 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1187 "isSingleValued", "FALSE");
1188 if (ret != LDB_SUCCESS) return ret;
1190 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1193 guid = GUID_random();
1194 ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1195 if (ret != LDB_SUCCESS) {
1201 el = ldb_msg_find_element(ac->msg, "attributeSyntax");
1204 * No need to scream if there isn't as we have code later on
1205 * that will take care of it.
1207 const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
1209 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
1210 (const char *)el->values[0].data));
1212 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
1213 const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
1216 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
1217 if (ret != LDB_SUCCESS) {
1222 struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
1223 if (val2.length > 0) {
1224 ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
1225 if (ret != LDB_SUCCESS) {
1233 /* handle msDS-IntID attribute */
1234 ret = samldb_add_handle_msDS_IntId(ac);
1235 if (ret != LDB_SUCCESS) return ret;
1237 ret = samldb_add_step(ac, samldb_add_entry);
1238 if (ret != LDB_SUCCESS) return ret;
1243 ldb_asprintf_errstring(ldb, "Invalid entry type!");
1244 return LDB_ERR_OPERATIONS_ERROR;
1248 return samldb_first_step(ac);
1251 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1253 struct ldb_context *ldb = NULL;
1254 const struct ldb_val *rdn_value = NULL;
1255 struct ldb_message_element *sid_el = NULL;
1256 struct dom_sid *sid = NULL;
1257 struct ldb_control *as_system = NULL;
1258 struct ldb_control *provision = NULL;
1259 bool allowed = false;
1262 ldb = ldb_module_get_ctx(ac->module);
1264 as_system = ldb_request_get_control(ac->req, LDB_CONTROL_AS_SYSTEM_OID);
1265 if (as_system != NULL) {
1269 provision = ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID);
1270 if (provision != NULL) {
1274 sid_el = ldb_msg_find_element(ac->msg, "objectSid");
1276 if (!allowed && sid_el == NULL) {
1277 return dsdb_module_werror(ac->module,
1278 LDB_ERR_OBJECT_CLASS_VIOLATION,
1279 WERR_DS_MISSING_REQUIRED_ATT,
1280 "objectSid missing on foreignSecurityPrincipal");
1284 return dsdb_module_werror(ac->module,
1285 LDB_ERR_UNWILLING_TO_PERFORM,
1286 WERR_DS_ILLEGAL_MOD_OPERATION,
1287 "foreignSecurityPrincipal object not allowed");
1290 if (sid_el != NULL) {
1291 sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1293 ldb_set_errstring(ldb,
1294 "samldb: invalid objectSid!");
1295 return LDB_ERR_CONSTRAINT_VIOLATION;
1300 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1301 if (rdn_value == NULL) {
1302 return ldb_operr(ldb);
1304 sid = dom_sid_parse_talloc(ac->msg,
1305 (const char *)rdn_value->data);
1307 ldb_set_errstring(ldb,
1308 "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
1309 return LDB_ERR_CONSTRAINT_VIOLATION;
1311 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
1312 return ldb_operr(ldb);
1316 /* finally proceed with adding the entry */
1317 ret = samldb_add_step(ac, samldb_add_entry);
1318 if (ret != LDB_SUCCESS) return ret;
1320 return samldb_first_step(ac);
1323 static int samldb_schema_info_update(struct samldb_ctx *ac)
1326 struct ldb_context *ldb;
1327 struct dsdb_schema *schema;
1329 /* replicated update should always go through */
1330 if (ldb_request_get_control(ac->req,
1331 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1335 /* do not update schemaInfo during provisioning */
1336 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1340 ldb = ldb_module_get_ctx(ac->module);
1341 schema = dsdb_get_schema(ldb, NULL);
1343 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1344 "samldb_schema_info_update: no dsdb_schema loaded");
1345 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1346 return ldb_operr(ldb);
1349 ret = dsdb_module_schema_info_update(ac->module, schema,
1350 DSDB_FLAG_NEXT_MODULE|
1351 DSDB_FLAG_AS_SYSTEM,
1353 if (ret != LDB_SUCCESS) {
1354 ldb_asprintf_errstring(ldb,
1355 "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
1356 ldb_errstring(ldb));
1363 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
1364 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
1365 struct dom_sid *sid,
1367 uint32_t user_account_control,
1368 uint32_t user_account_control_old);
1371 * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
1373 * Has to be invoked on "add" and "modify" operations on "user", "computer" and
1375 * ac->msg contains the "add"/"modify" message
1376 * ac->type contains the object type (main objectclass)
1378 static int samldb_objectclass_trigger(struct samldb_ctx *ac)
1380 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1381 void *skip_allocate_sids = ldb_get_opaque(ldb,
1382 "skip_allocate_sids");
1383 struct ldb_message_element *el, *el2;
1384 struct dom_sid *sid;
1387 /* make sure that "sAMAccountType" is not specified */
1388 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1390 ldb_set_errstring(ldb,
1391 "samldb: sAMAccountType must not be specified!");
1392 return LDB_ERR_UNWILLING_TO_PERFORM;
1395 /* Step 1: objectSid assignment */
1397 /* Don't allow the objectSid to be changed. But beside the RELAX
1398 * control we have also to guarantee that it can always be set with
1399 * SYSTEM permissions. This is needed for the "samba3sam" backend. */
1400 sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1401 if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
1402 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
1403 ldb_set_errstring(ldb,
1404 "samldb: objectSid must not be specified!");
1405 return LDB_ERR_UNWILLING_TO_PERFORM;
1408 /* but generate a new SID when we do have an add operations */
1409 if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
1410 ret = samldb_add_step(ac, samldb_allocate_sid);
1411 if (ret != LDB_SUCCESS) return ret;
1415 case SAMLDB_TYPE_USER: {
1416 bool uac_generated = false, uac_add_flags = false;
1418 /* Step 1.2: Default values */
1419 ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
1420 if (ret != LDB_SUCCESS) return ret;
1422 /* On add operations we might need to generate a
1423 * "userAccountControl" (if it isn't specified). */
1424 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1425 if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
1426 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1427 "userAccountControl",
1429 if (ret != LDB_SUCCESS) {
1432 uac_generated = true;
1433 uac_add_flags = true;
1436 el = ldb_msg_find_element(ac->msg, "userAccountControl");
1439 uint32_t user_account_control;
1440 /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
1441 user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
1442 "userAccountControl",
1444 raw_uac = user_account_control;
1446 * "userAccountControl" = 0 or missing one of
1447 * the types means "UF_NORMAL_ACCOUNT". See
1448 * MS-SAMR 3.1.1.8.10 point 8
1450 if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
1451 user_account_control = UF_NORMAL_ACCOUNT | user_account_control;
1452 uac_generated = true;
1456 * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
1458 if ((user_account_control & UF_LOCKOUT) != 0) {
1459 user_account_control &= ~UF_LOCKOUT;
1460 uac_generated = true;
1462 if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
1463 user_account_control &= ~UF_PASSWORD_EXPIRED;
1464 uac_generated = true;
1467 ret = samldb_check_user_account_control_rules(ac, NULL,
1469 user_account_control,
1471 if (ret != LDB_SUCCESS) {
1475 /* Workstation and (read-only) DC objects do need objectclass "computer" */
1476 if ((samdb_find_attribute(ldb, ac->msg,
1477 "objectclass", "computer") == NULL) &&
1478 (user_account_control &
1479 (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
1480 ldb_set_errstring(ldb,
1481 "samldb: Requested account type does need objectclass 'computer'!");
1482 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1485 /* add "sAMAccountType" attribute */
1486 ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
1487 if (ret != LDB_SUCCESS) {
1491 /* "isCriticalSystemObject" might be set */
1492 if (user_account_control &
1493 (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1494 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1496 if (ret != LDB_SUCCESS) {
1499 el2 = ldb_msg_find_element(ac->msg,
1500 "isCriticalSystemObject");
1501 el2->flags = LDB_FLAG_MOD_REPLACE;
1502 } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1503 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1505 if (ret != LDB_SUCCESS) {
1508 el2 = ldb_msg_find_element(ac->msg,
1509 "isCriticalSystemObject");
1510 el2->flags = LDB_FLAG_MOD_REPLACE;
1513 /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
1514 if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1517 ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
1518 if (ret != LDB_SUCCESS) {
1522 * Older AD deployments don't know about the
1525 if (rid == DOMAIN_RID_READONLY_DCS) {
1526 ret = samldb_prim_group_tester(ac, rid);
1527 if (ret != LDB_SUCCESS) {
1533 /* Step 1.5: Add additional flags when needed */
1534 /* Obviously this is done when the "userAccountControl"
1535 * has been generated here (tested against Windows
1537 if (uac_generated) {
1538 if (uac_add_flags) {
1539 user_account_control |= UF_ACCOUNTDISABLE;
1540 user_account_control |= UF_PASSWD_NOTREQD;
1543 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1544 "userAccountControl",
1545 user_account_control);
1546 if (ret != LDB_SUCCESS) {
1555 case SAMLDB_TYPE_GROUP: {
1556 const char *tempstr;
1558 /* Step 2.2: Default values */
1559 tempstr = talloc_asprintf(ac->msg, "%d",
1560 GTYPE_SECURITY_GLOBAL_GROUP);
1561 if (tempstr == NULL) return ldb_operr(ldb);
1562 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1563 "groupType", tempstr);
1564 if (ret != LDB_SUCCESS) return ret;
1566 /* Step 2.3: "groupType" -> "sAMAccountType" */
1567 el = ldb_msg_find_element(ac->msg, "groupType");
1569 uint32_t group_type, account_type;
1571 group_type = ldb_msg_find_attr_as_uint(ac->msg,
1574 /* The creation of builtin groups requires the
1576 if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
1577 if (ldb_request_get_control(ac->req,
1578 LDB_CONTROL_RELAX_OID) == NULL) {
1579 return LDB_ERR_UNWILLING_TO_PERFORM;
1583 account_type = ds_gtype2atype(group_type);
1584 if (account_type == 0) {
1585 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1586 return LDB_ERR_UNWILLING_TO_PERFORM;
1588 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1591 if (ret != LDB_SUCCESS) {
1594 el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1595 el2->flags = LDB_FLAG_MOD_REPLACE;
1601 ldb_asprintf_errstring(ldb,
1602 "Invalid entry type!");
1603 return LDB_ERR_OPERATIONS_ERROR;
1611 * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
1613 * Has to be invoked on "add" and "modify" operations on "user" and "computer"
1615 * ac->msg contains the "add"/"modify" message
1618 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
1620 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1621 struct dom_sid *sid;
1622 struct ldb_result *res;
1624 const char * const noattrs[] = { NULL };
1626 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1628 return ldb_operr(ldb);
1631 ret = dsdb_module_search(ac->module, ac, &res,
1632 ldb_get_default_basedn(ldb),
1634 noattrs, DSDB_FLAG_NEXT_MODULE,
1637 ldap_encode_ndr_dom_sid(ac, sid));
1638 if (ret != LDB_SUCCESS) {
1641 if (res->count != 1) {
1643 ldb_asprintf_errstring(ldb,
1644 "Failed to find primary group with RID %u!",
1646 return LDB_ERR_UNWILLING_TO_PERFORM;
1653 static int samldb_prim_group_set(struct samldb_ctx *ac)
1655 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1658 rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
1659 if (rid == (uint32_t) -1) {
1660 /* we aren't affected of any primary group set */
1663 } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1664 ldb_set_errstring(ldb,
1665 "The primary group isn't settable on add operations!");
1666 return LDB_ERR_UNWILLING_TO_PERFORM;
1669 return samldb_prim_group_tester(ac, rid);
1672 static int samldb_prim_group_change(struct samldb_ctx *ac)
1674 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1675 const char * const attrs[] = {
1678 "userAccountControl",
1680 struct ldb_result *res, *group_res;
1681 struct ldb_message_element *el;
1682 struct ldb_message *msg;
1683 uint32_t prev_rid, new_rid, uac;
1684 struct dom_sid *prev_sid, *new_sid;
1685 struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1687 const char * const noattrs[] = { NULL };
1689 el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1690 ac->req->operation);
1692 /* we are not affected */
1696 /* Fetch information from the existing object */
1698 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1699 DSDB_FLAG_NEXT_MODULE, ac->req);
1700 if (ret != LDB_SUCCESS) {
1704 uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1706 /* Finds out the DN of the old primary group */
1708 prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1710 if (prev_rid == (uint32_t) -1) {
1711 /* User objects do always have a mandatory "primaryGroupID"
1712 * attribute. If this doesn't exist then the object is of the
1713 * wrong type. This is the exact Windows error code */
1714 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1717 prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1718 if (prev_sid == NULL) {
1719 return ldb_operr(ldb);
1722 /* Finds out the DN of the new primary group
1723 * Notice: in order to parse the primary group ID correctly we create
1724 * a temporary message here. */
1726 msg = ldb_msg_new(ac->msg);
1728 return ldb_module_oom(ac->module);
1730 ret = ldb_msg_add(msg, el, 0);
1731 if (ret != LDB_SUCCESS) {
1734 new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1736 if (new_rid == (uint32_t) -1) {
1737 /* we aren't affected of any primary group change */
1741 if (prev_rid == new_rid) {
1745 if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
1746 ldb_asprintf_errstring(ldb,
1747 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
1748 "primaryGroupID=%u!",
1749 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1751 return LDB_ERR_UNWILLING_TO_PERFORM;
1754 if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
1755 ldb_asprintf_errstring(ldb,
1756 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
1757 "primaryGroupID=%u!",
1758 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1759 DOMAIN_RID_READONLY_DCS);
1760 return LDB_ERR_UNWILLING_TO_PERFORM;
1763 ret = dsdb_module_search(ac->module, ac, &group_res,
1764 ldb_get_default_basedn(ldb),
1766 noattrs, DSDB_FLAG_NEXT_MODULE,
1769 ldap_encode_ndr_dom_sid(ac, prev_sid));
1770 if (ret != LDB_SUCCESS) {
1773 if (group_res->count != 1) {
1774 return ldb_operr(ldb);
1776 prev_prim_group_dn = group_res->msgs[0]->dn;
1778 new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1779 if (new_sid == NULL) {
1780 return ldb_operr(ldb);
1783 ret = dsdb_module_search(ac->module, ac, &group_res,
1784 ldb_get_default_basedn(ldb),
1786 noattrs, DSDB_FLAG_NEXT_MODULE,
1789 ldap_encode_ndr_dom_sid(ac, new_sid));
1790 if (ret != LDB_SUCCESS) {
1793 if (group_res->count != 1) {
1794 /* Here we know if the specified new primary group candidate is
1796 return LDB_ERR_UNWILLING_TO_PERFORM;
1798 new_prim_group_dn = group_res->msgs[0]->dn;
1800 /* We need to be already a normal member of the new primary
1801 * group in order to be successful. */
1802 el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1803 ldb_dn_get_linearized(new_prim_group_dn));
1805 return LDB_ERR_UNWILLING_TO_PERFORM;
1808 /* Remove the "member" attribute on the new primary group */
1809 msg = ldb_msg_new(ac->msg);
1811 return ldb_module_oom(ac->module);
1813 msg->dn = new_prim_group_dn;
1815 ret = samdb_msg_add_delval(ldb, msg, msg, "member",
1816 ldb_dn_get_linearized(ac->msg->dn));
1817 if (ret != LDB_SUCCESS) {
1821 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1822 if (ret != LDB_SUCCESS) {
1827 /* Add a "member" attribute for the previous primary group */
1828 msg = ldb_msg_new(ac->msg);
1830 return ldb_module_oom(ac->module);
1832 msg->dn = prev_prim_group_dn;
1834 ret = samdb_msg_add_addval(ldb, msg, msg, "member",
1835 ldb_dn_get_linearized(ac->msg->dn));
1836 if (ret != LDB_SUCCESS) {
1840 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1841 if (ret != LDB_SUCCESS) {
1849 static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1853 if (ac->req->operation == LDB_ADD) {
1854 ret = samldb_prim_group_set(ac);
1856 ret = samldb_prim_group_change(ac);
1862 static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
1863 uint32_t user_account_control)
1866 bool need_check = false;
1867 const struct uac_to_guid {
1872 const char *error_string;
1875 .uac = UF_TEMP_DUPLICATE_ACCOUNT,
1877 .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
1880 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1881 .needs = UF_WORKSTATION_TRUST_ACCOUNT,
1882 .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
1885 .uac = UF_TRUSTED_FOR_DELEGATION,
1886 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1887 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1890 .uac = UF_NORMAL_ACCOUNT,
1891 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
1892 .error_string = "Setting more than one account type not permitted"
1895 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1896 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
1897 .error_string = "Setting more than one account type not permitted"
1900 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1901 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
1902 .error_string = "Setting more than one account type not permitted"
1905 .uac = UF_SERVER_TRUST_ACCOUNT,
1906 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
1907 .error_string = "Setting more than one account type not permitted"
1910 .uac = UF_TRUSTED_FOR_DELEGATION,
1911 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1912 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1916 for (i = 0; i < ARRAY_SIZE(map); i++) {
1917 if (user_account_control & map[i].uac) {
1922 if (need_check == false) {
1926 for (i = 0; i < ARRAY_SIZE(map); i++) {
1927 uint32_t this_uac = user_account_control & map[i].uac;
1928 if (this_uac != 0) {
1930 ret = LDB_ERR_OTHER;
1932 } else if (map[i].needs != 0) {
1933 if ((map[i].needs & user_account_control) == 0) {
1934 ret = LDB_ERR_OTHER;
1937 } else if (map[i].not_with != 0) {
1938 if ((map[i].not_with & user_account_control) != 0) {
1939 ret = LDB_ERR_OTHER;
1945 if (ret != LDB_SUCCESS) {
1946 switch (ac->req->operation) {
1948 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1949 "Failed to add %s: %s",
1950 ldb_dn_get_linearized(ac->msg->dn),
1951 map[i].error_string);
1954 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1955 "Failed to modify %s: %s",
1956 ldb_dn_get_linearized(ac->msg->dn),
1957 map[i].error_string);
1960 return ldb_module_operr(ac->module);
1967 * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
1970 static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
1971 struct dom_sid *sid,
1972 uint32_t user_account_control,
1973 uint32_t user_account_control_old)
1976 bool need_acl_check = false;
1977 struct ldb_result *res;
1978 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
1979 struct security_token *user_token;
1980 struct security_descriptor *domain_sd;
1981 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
1982 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1983 const struct uac_to_guid {
1985 uint32_t priv_to_change_from;
1988 enum sec_privilege privilege;
1989 bool delete_is_privileged;
1990 bool admin_required;
1991 const char *error_string;
1994 .uac = UF_PASSWD_NOTREQD,
1995 .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
1996 .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"
1999 .uac = UF_DONT_EXPIRE_PASSWD,
2000 .guid = GUID_DRS_UNEXPIRE_PASSWORD,
2001 .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
2004 .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
2005 .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
2006 .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"
2009 .uac = UF_SERVER_TRUST_ACCOUNT,
2010 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2011 .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"
2014 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
2015 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2016 .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"
2019 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
2020 .priv_to_change_from = UF_NORMAL_ACCOUNT,
2021 .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
2024 .uac = UF_NORMAL_ACCOUNT,
2025 .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
2026 .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
2029 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
2030 .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2031 .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",
2032 .delete_is_privileged = true
2035 .uac = UF_TRUSTED_FOR_DELEGATION,
2036 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2037 .delete_is_privileged = true,
2038 .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2041 .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
2042 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2043 .delete_is_privileged = true,
2044 .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2049 if (dsdb_module_am_system(ac->module)) {
2053 for (i = 0; i < ARRAY_SIZE(map); i++) {
2054 if (user_account_control & map[i].uac) {
2055 need_acl_check = true;
2059 if (need_acl_check == false) {
2063 user_token = acl_user_token(ac->module);
2064 if (user_token == NULL) {
2065 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2068 ret = dsdb_module_search_dn(ac->module, ac, &res,
2071 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2073 if (ret != LDB_SUCCESS) {
2076 if (res->count != 1) {
2077 return ldb_module_operr(ac->module);
2080 ret = dsdb_get_sd_from_ldb_message(ldb,
2081 ac, res->msgs[0], &domain_sd);
2083 if (ret != LDB_SUCCESS) {
2087 for (i = 0; i < ARRAY_SIZE(map); i++) {
2088 uint32_t this_uac_new = user_account_control & map[i].uac;
2089 uint32_t this_uac_old = user_account_control_old & map[i].uac;
2090 if (this_uac_new != this_uac_old) {
2091 if (this_uac_old != 0) {
2092 if (map[i].delete_is_privileged == false) {
2097 struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
2098 if (control == NULL) {
2099 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2101 } else if (map[i].privilege != SEC_PRIV_INVALID) {
2102 bool have_priv = security_token_has_privilege(user_token,
2104 if (have_priv == false) {
2105 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2107 } else if (map[i].priv_to_change_from & user_account_control_old) {
2108 bool is_admin = security_token_has_builtin_administrators(user_token);
2109 if (is_admin == false) {
2110 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2112 } else if (map[i].guid) {
2113 ret = acl_check_extended_right(ac, domain_sd,
2116 SEC_ADS_CONTROL_ACCESS,
2121 if (ret != LDB_SUCCESS) {
2126 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2127 switch (ac->req->operation) {
2129 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2130 "Failed to add %s: %s",
2131 ldb_dn_get_linearized(ac->msg->dn),
2132 map[i].error_string);
2135 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2136 "Failed to modify %s: %s",
2137 ldb_dn_get_linearized(ac->msg->dn),
2138 map[i].error_string);
2141 return ldb_module_operr(ac->module);
2144 dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
2153 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
2154 struct dom_sid *sid,
2156 uint32_t user_account_control,
2157 uint32_t user_account_control_old)
2160 struct dsdb_control_password_user_account_control *uac = NULL;
2162 ret = samldb_check_user_account_control_invariants(ac, user_account_control);
2163 if (ret != LDB_SUCCESS) {
2166 ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
2167 if (ret != LDB_SUCCESS) {
2171 uac = talloc_zero(ac->req,
2172 struct dsdb_control_password_user_account_control);
2174 return ldb_module_oom(ac->module);
2177 uac->req_flags = req_uac;
2178 uac->old_flags = user_account_control_old;
2179 uac->new_flags = user_account_control;
2181 ret = ldb_request_add_control(ac->req,
2182 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
2184 if (ret != LDB_SUCCESS) {
2193 * This function is called on LDB modify operations. It performs some additions/
2194 * replaces on the current LDB message when "userAccountControl" changes.
2196 static int samldb_user_account_control_change(struct samldb_ctx *ac)
2198 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2204 uint32_t old_uac_computed;
2210 NTTIME old_lockoutTime;
2211 struct ldb_message_element *el;
2212 struct ldb_val *val;
2213 struct ldb_val computer_val;
2214 struct ldb_message *tmp_msg;
2215 struct dom_sid *sid;
2217 struct ldb_result *res;
2218 const char * const attrs[] = {
2220 "isCriticalSystemObject",
2221 "userAccountControl",
2222 "msDS-User-Account-Control-Computed",
2227 bool is_computer = false;
2228 bool old_is_critical = false;
2229 bool new_is_critical = false;
2231 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2232 ac->req->operation);
2233 if (el == NULL || el->num_values == 0) {
2234 ldb_asprintf_errstring(ldb,
2235 "%08X: samldb: 'userAccountControl' can't be deleted!",
2236 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2237 return LDB_ERR_UNWILLING_TO_PERFORM;
2240 /* Create a temporary message for fetching the "userAccountControl" */
2241 tmp_msg = ldb_msg_new(ac->msg);
2242 if (tmp_msg == NULL) {
2243 return ldb_module_oom(ac->module);
2245 ret = ldb_msg_add(tmp_msg, el, 0);
2246 if (ret != LDB_SUCCESS) {
2249 raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
2250 "userAccountControl",
2252 talloc_free(tmp_msg);
2254 * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2255 * are only generated and not stored. We ignore them almost
2256 * completely, along with unknown bits and UF_SCRIPT.
2258 * The only exception is ACB_AUTOLOCK, which features in
2259 * clear_acb when the bit is cleared in this modify operation.
2261 * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2262 * ignored by clients and servers
2264 new_uac = raw_uac & UF_SETTABLE_BITS;
2266 /* Fetch the old "userAccountControl" and "objectClass" */
2267 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2268 DSDB_FLAG_NEXT_MODULE, ac->req);
2269 if (ret != LDB_SUCCESS) {
2272 old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
2274 return ldb_operr(ldb);
2276 old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
2277 "msDS-User-Account-Control-Computed", 0);
2278 old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
2280 old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
2281 "isCriticalSystemObject", 0);
2282 /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
2283 el = ldb_msg_find_element(res->msgs[0], "objectClass");
2285 return ldb_operr(ldb);
2287 computer_val = data_blob_string_const("computer");
2288 val = ldb_msg_find_val(el, &computer_val);
2293 old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
2294 old_atype = ds_uf2atype(old_ufa);
2295 old_pgrid = ds_uf2prim_group_rid(old_uac);
2297 new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
2300 * "userAccountControl" = 0 or missing one of the
2301 * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2302 * 3.1.1.8.10 point 8
2304 new_ufa = UF_NORMAL_ACCOUNT;
2307 sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2309 return ldb_module_operr(ac->module);
2312 ret = samldb_check_user_account_control_rules(ac, sid,
2316 if (ret != LDB_SUCCESS) {
2320 new_atype = ds_uf2atype(new_ufa);
2321 new_pgrid = ds_uf2prim_group_rid(new_uac);
2323 clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
2326 case UF_NORMAL_ACCOUNT:
2327 new_is_critical = old_is_critical;
2330 case UF_INTERDOMAIN_TRUST_ACCOUNT:
2331 new_is_critical = true;
2334 case UF_WORKSTATION_TRUST_ACCOUNT:
2335 new_is_critical = false;
2336 if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
2338 ldb_asprintf_errstring(ldb,
2339 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
2340 "requires objectclass 'computer'!",
2341 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2342 return LDB_ERR_UNWILLING_TO_PERFORM;
2344 new_is_critical = true;
2348 case UF_SERVER_TRUST_ACCOUNT:
2350 ldb_asprintf_errstring(ldb,
2351 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2352 "requires objectclass 'computer'!",
2353 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2354 return LDB_ERR_UNWILLING_TO_PERFORM;
2356 new_is_critical = true;
2360 ldb_asprintf_errstring(ldb,
2361 "%08X: samldb: invalid userAccountControl[0x%08X]",
2362 W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
2363 return LDB_ERR_OTHER;
2366 if (old_atype != new_atype) {
2367 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2368 "sAMAccountType", new_atype);
2369 if (ret != LDB_SUCCESS) {
2372 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2373 el->flags = LDB_FLAG_MOD_REPLACE;
2376 /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
2377 if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
2378 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
2379 ldb_msg_remove_attr(ac->msg, "lockoutTime");
2380 ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
2382 if (ret != LDB_SUCCESS) {
2385 el = ldb_msg_find_element(ac->msg, "lockoutTime");
2386 el->flags = LDB_FLAG_MOD_REPLACE;
2389 /* "isCriticalSystemObject" might be set/changed */
2390 if (old_is_critical != new_is_critical) {
2391 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
2392 new_is_critical ? "TRUE": "FALSE");
2393 if (ret != LDB_SUCCESS) {
2396 el = ldb_msg_find_element(ac->msg,
2397 "isCriticalSystemObject");
2398 el->flags = LDB_FLAG_MOD_REPLACE;
2401 if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
2402 (old_pgrid != new_pgrid)) {
2403 /* Older AD deployments don't know about the RODC group */
2404 if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
2405 ret = samldb_prim_group_tester(ac, new_pgrid);
2406 if (ret != LDB_SUCCESS) {
2411 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2412 "primaryGroupID", new_pgrid);
2413 if (ret != LDB_SUCCESS) {
2416 el = ldb_msg_find_element(ac->msg,
2418 el->flags = LDB_FLAG_MOD_REPLACE;
2421 /* Propagate eventual "userAccountControl" attribute changes */
2422 if (old_uac != new_uac) {
2423 char *tempstr = talloc_asprintf(ac->msg, "%d",
2425 if (tempstr == NULL) {
2426 return ldb_module_oom(ac->module);
2429 /* Overwrite "userAccountControl" correctly */
2430 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2431 ac->req->operation);
2432 el->values[0].data = (uint8_t *) tempstr;
2433 el->values[0].length = strlen(tempstr);
2435 ldb_msg_remove_attr(ac->msg, "userAccountControl");
2441 static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
2442 struct dom_sid *sid)
2444 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2446 struct ldb_result *res = NULL;
2447 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
2448 struct security_token *user_token = NULL;
2449 struct security_descriptor *domain_sd = NULL;
2450 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2451 const char *operation = "";
2453 if (dsdb_module_am_system(ac->module)) {
2457 switch (ac->req->operation) {
2462 operation = "modify";
2465 return ldb_module_operr(ac->module);
2468 user_token = acl_user_token(ac->module);
2469 if (user_token == NULL) {
2470 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2473 ret = dsdb_module_search_dn(ac->module, ac, &res,
2476 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2478 if (ret != LDB_SUCCESS) {
2481 if (res->count != 1) {
2482 return ldb_module_operr(ac->module);
2485 ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
2486 if (ret != LDB_SUCCESS) {
2490 ret = acl_check_extended_right(ac, domain_sd,
2492 GUID_DRS_UNEXPIRE_PASSWORD,
2493 SEC_ADS_CONTROL_ACCESS,
2495 if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2499 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
2501 "Setting pwdLastSet to -1 requires the "
2502 "Unexpire-Password right that was not given "
2503 "on the Domain object",
2505 ldb_dn_get_linearized(ac->msg->dn));
2506 dsdb_acl_debug(domain_sd, user_token,
2507 domain_dn, true, 10);
2513 * This function is called on LDB modify operations. It performs some additions/
2514 * replaces on the current LDB message when "pwdLastSet" changes.
2516 static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
2518 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2519 NTTIME last_set = 0;
2520 struct ldb_message_element *el = NULL;
2521 struct ldb_message *tmp_msg = NULL;
2522 struct dom_sid *self_sid = NULL;
2524 struct ldb_result *res = NULL;
2525 const char * const attrs[] = {
2530 el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
2531 ac->req->operation);
2532 if (el == NULL || el->num_values == 0) {
2533 ldb_asprintf_errstring(ldb,
2534 "%08X: samldb: 'pwdLastSet' can't be deleted!",
2535 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2536 return LDB_ERR_UNWILLING_TO_PERFORM;
2539 /* Create a temporary message for fetching the "userAccountControl" */
2540 tmp_msg = ldb_msg_new(ac->msg);
2541 if (tmp_msg == NULL) {
2542 return ldb_module_oom(ac->module);
2544 ret = ldb_msg_add(tmp_msg, el, 0);
2545 if (ret != LDB_SUCCESS) {
2548 last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
2549 talloc_free(tmp_msg);
2552 * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
2554 if (last_set != UINT64_MAX) {
2558 /* Fetch the "objectSid" */
2559 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2560 DSDB_FLAG_NEXT_MODULE, ac->req);
2561 if (ret != LDB_SUCCESS) {
2564 self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2565 if (self_sid == NULL) {
2566 return ldb_module_operr(ac->module);
2569 ret = samldb_check_pwd_last_set_acl(ac, self_sid);
2570 if (ret != LDB_SUCCESS) {
2577 static int samldb_lockout_time(struct samldb_ctx *ac)
2579 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2581 struct ldb_message_element *el;
2582 struct ldb_message *tmp_msg;
2585 el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
2586 ac->req->operation);
2587 if (el == NULL || el->num_values == 0) {
2588 ldb_asprintf_errstring(ldb,
2589 "%08X: samldb: 'lockoutTime' can't be deleted!",
2590 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2591 return LDB_ERR_UNWILLING_TO_PERFORM;
2594 /* Create a temporary message for fetching the "lockoutTime" */
2595 tmp_msg = ldb_msg_new(ac->msg);
2596 if (tmp_msg == NULL) {
2597 return ldb_module_oom(ac->module);
2599 ret = ldb_msg_add(tmp_msg, el, 0);
2600 if (ret != LDB_SUCCESS) {
2603 lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
2606 talloc_free(tmp_msg);
2608 if (lockoutTime != 0) {
2612 /* lockoutTime == 0 resets badPwdCount */
2613 ldb_msg_remove_attr(ac->msg, "badPwdCount");
2614 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
2616 if (ret != LDB_SUCCESS) {
2619 el = ldb_msg_find_element(ac->msg, "badPwdCount");
2620 el->flags = LDB_FLAG_MOD_REPLACE;
2625 static int samldb_group_type_change(struct samldb_ctx *ac)
2627 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2628 uint32_t group_type, old_group_type, account_type;
2629 struct ldb_message_element *el;
2630 struct ldb_message *tmp_msg;
2632 struct ldb_result *res;
2633 const char * const attrs[] = { "groupType", NULL };
2635 el = dsdb_get_single_valued_attr(ac->msg, "groupType",
2636 ac->req->operation);
2638 /* we are not affected */
2642 /* Create a temporary message for fetching the "groupType" */
2643 tmp_msg = ldb_msg_new(ac->msg);
2644 if (tmp_msg == NULL) {
2645 return ldb_module_oom(ac->module);
2647 ret = ldb_msg_add(tmp_msg, el, 0);
2648 if (ret != LDB_SUCCESS) {
2651 group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
2652 talloc_free(tmp_msg);
2654 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2655 DSDB_FLAG_NEXT_MODULE |
2656 DSDB_SEARCH_SHOW_DELETED, ac->req);
2657 if (ret != LDB_SUCCESS) {
2660 old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
2661 if (old_group_type == 0) {
2662 return ldb_operr(ldb);
2665 /* Group type switching isn't so easy as it seems: We can only
2666 * change in this directions: global <-> universal <-> local
2667 * On each step also the group type itself
2668 * (security/distribution) is variable. */
2670 if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
2671 switch (group_type) {
2672 case GTYPE_SECURITY_GLOBAL_GROUP:
2673 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
2674 /* change to "universal" allowed */
2675 if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
2676 (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
2677 ldb_set_errstring(ldb,
2678 "samldb: Change from security/distribution local group forbidden!");
2679 return LDB_ERR_UNWILLING_TO_PERFORM;
2683 case GTYPE_SECURITY_UNIVERSAL_GROUP:
2684 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
2685 /* each change allowed */
2687 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
2688 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
2689 /* change to "universal" allowed */
2690 if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
2691 (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
2692 ldb_set_errstring(ldb,
2693 "samldb: Change from security/distribution global group forbidden!");
2694 return LDB_ERR_UNWILLING_TO_PERFORM;
2698 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
2700 /* we don't allow this "groupType" values */
2701 return LDB_ERR_UNWILLING_TO_PERFORM;
2706 account_type = ds_gtype2atype(group_type);
2707 if (account_type == 0) {
2708 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
2709 return LDB_ERR_UNWILLING_TO_PERFORM;
2711 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
2713 if (ret != LDB_SUCCESS) {
2716 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2717 el->flags = LDB_FLAG_MOD_REPLACE;
2722 static int samldb_member_check(struct samldb_ctx *ac)
2724 const char * const attrs[] = { "objectSid", NULL };
2725 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2726 struct ldb_message_element *el;
2727 struct ldb_dn *member_dn;
2728 struct dom_sid *sid;
2729 struct ldb_result *res;
2730 struct dom_sid *group_sid;
2734 /* Fetch information from the existing object */
2736 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2737 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
2738 if (ret != LDB_SUCCESS) {
2741 if (res->count != 1) {
2742 return ldb_operr(ldb);
2745 group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2746 if (group_sid == NULL) {
2747 return ldb_operr(ldb);
2750 /* We've to walk over all modification entries and consider the "member"
2752 for (i = 0; i < ac->msg->num_elements; i++) {
2753 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
2757 el = &ac->msg->elements[i];
2758 for (j = 0; j < el->num_values; j++) {
2759 struct ldb_result *group_res;
2760 const char *group_attrs[] = { "primaryGroupID" , NULL };
2761 uint32_t prim_group_rid;
2763 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2764 /* Deletes will be handled in
2765 * repl_meta_data, and deletes not
2766 * matching a member will return
2767 * LDB_ERR_UNWILLING_TO_PERFORM
2772 member_dn = ldb_dn_from_ldb_val(ac, ldb,
2774 if (!ldb_dn_validate(member_dn)) {
2775 return ldb_operr(ldb);
2778 /* Denies to add "member"s to groups which are primary
2779 * ones for them - in this case return
2780 * ERR_ENTRY_ALREADY_EXISTS. */
2782 ret = dsdb_module_search_dn(ac->module, ac, &group_res,
2783 member_dn, group_attrs,
2784 DSDB_FLAG_NEXT_MODULE, ac->req);
2785 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2786 /* member DN doesn't exist yet */
2789 if (ret != LDB_SUCCESS) {
2792 prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
2793 if (prim_group_rid == (uint32_t) -1) {
2794 /* the member hasn't to be a user account ->
2795 * therefore no check needed in this case. */
2799 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
2802 return ldb_operr(ldb);
2805 if (dom_sid_equal(group_sid, sid)) {
2806 ldb_asprintf_errstring(ldb,
2807 "samldb: member %s already set via primaryGroupID %u",
2808 ldb_dn_get_linearized(member_dn), prim_group_rid);
2809 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2819 /* SAM objects have special rules regarding the "description" attribute on
2820 * modify operations. */
2821 static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
2823 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2824 const char * const attrs[] = { "objectClass", "description", NULL };
2825 struct ldb_result *res;
2829 /* Fetch information from the existing object */
2830 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2831 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
2832 "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
2833 if (ret != LDB_SUCCESS) {
2834 /* don't treat it specially ... let normal error codes
2835 happen from other places */
2836 ldb_reset_err_string(ldb);
2839 if (res->count == 0) {
2840 /* we didn't match the filter */
2845 /* We've to walk over all modification entries and consider the
2846 * "description" ones. */
2847 for (i = 0; i < ac->msg->num_elements; i++) {
2848 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
2849 ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
2859 /* This trigger adapts the "servicePrincipalName" attributes if the
2860 * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
2861 static int samldb_service_principal_names_change(struct samldb_ctx *ac)
2863 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2864 struct ldb_message_element *el = NULL, *el2 = NULL;
2865 struct ldb_message *msg;
2866 const char * const attrs[] = { "servicePrincipalName", NULL };
2867 struct ldb_result *res;
2868 const char *dns_hostname = NULL, *old_dns_hostname = NULL,
2869 *sam_accountname = NULL, *old_sam_accountname = NULL;
2873 el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
2874 ac->req->operation);
2875 el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
2876 ac->req->operation);
2877 if ((el == NULL) && (el2 == NULL)) {
2878 /* we are not affected */
2882 /* Create a temporary message for fetching the "dNSHostName" */
2884 const char *dns_attrs[] = { "dNSHostName", NULL };
2885 msg = ldb_msg_new(ac->msg);
2887 return ldb_module_oom(ac->module);
2889 ret = ldb_msg_add(msg, el, 0);
2890 if (ret != LDB_SUCCESS) {
2893 dns_hostname = talloc_strdup(ac,
2894 ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
2895 if (dns_hostname == NULL) {
2896 return ldb_module_oom(ac->module);
2901 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
2902 dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
2903 if (ret == LDB_SUCCESS) {
2904 old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
2908 /* Create a temporary message for fetching the "sAMAccountName" */
2910 char *tempstr, *tempstr2 = NULL;
2911 const char *acct_attrs[] = { "sAMAccountName", NULL };
2913 msg = ldb_msg_new(ac->msg);
2915 return ldb_module_oom(ac->module);
2917 ret = ldb_msg_add(msg, el2, 0);
2918 if (ret != LDB_SUCCESS) {
2921 tempstr = talloc_strdup(ac,
2922 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
2925 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
2926 DSDB_FLAG_NEXT_MODULE, ac->req);
2927 if (ret == LDB_SUCCESS) {
2928 tempstr2 = talloc_strdup(ac,
2929 ldb_msg_find_attr_as_string(res->msgs[0],
2930 "sAMAccountName", NULL));
2934 /* The "sAMAccountName" needs some additional trimming: we need
2935 * to remove the trailing "$"s if they exist. */
2936 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
2937 (tempstr[strlen(tempstr) - 1] == '$')) {
2938 tempstr[strlen(tempstr) - 1] = '\0';
2940 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
2941 (tempstr2[strlen(tempstr2) - 1] == '$')) {
2942 tempstr2[strlen(tempstr2) - 1] = '\0';
2944 sam_accountname = tempstr;
2945 old_sam_accountname = tempstr2;
2948 if (old_dns_hostname == NULL) {
2949 /* we cannot change when the old name is unknown */
2950 dns_hostname = NULL;
2952 if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
2953 (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
2954 /* The "dNSHostName" didn't change */
2955 dns_hostname = NULL;
2958 if (old_sam_accountname == NULL) {
2959 /* we cannot change when the old name is unknown */
2960 sam_accountname = NULL;
2962 if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
2963 (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
2964 /* The "sAMAccountName" didn't change */
2965 sam_accountname = NULL;
2968 if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
2969 /* Well, there are information missing (old name(s)) or the
2970 * names didn't change. We've nothing to do and can exit here */
2974 /* Potential "servicePrincipalName" changes in the same request have to
2975 * be handled before the update (Windows behaviour). */
2976 el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
2978 msg = ldb_msg_new(ac->msg);
2980 return ldb_module_oom(ac->module);
2982 msg->dn = ac->msg->dn;
2985 ret = ldb_msg_add(msg, el, el->flags);
2986 if (ret != LDB_SUCCESS) {
2990 ldb_msg_remove_element(ac->msg, el);
2992 el = ldb_msg_find_element(ac->msg,
2993 "servicePrincipalName");
2994 } while (el != NULL);
2996 ret = dsdb_module_modify(ac->module, msg,
2997 DSDB_FLAG_NEXT_MODULE, ac->req);
2998 if (ret != LDB_SUCCESS) {
3004 /* Fetch the "servicePrincipalName"s if any */
3005 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
3006 DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
3007 if (ret != LDB_SUCCESS) {
3010 if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
3011 return ldb_operr(ldb);
3014 if (res->msgs[0]->num_elements == 1) {
3016 * Yes, we do have "servicePrincipalName"s. First we update them
3017 * locally, that means we do always substitute the current
3018 * "dNSHostName" with the new one and/or "sAMAccountName"
3019 * without "$" with the new one and then we append the
3020 * modified "servicePrincipalName"s as a message element
3021 * replace to the modification request (Windows behaviour). We
3022 * need also to make sure that the values remain case-
3023 * insensitively unique.
3026 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
3027 LDB_FLAG_MOD_REPLACE, &el);
3028 if (ret != LDB_SUCCESS) {
3032 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
3033 char *old_str, *new_str;
3036 struct ldb_val *vals;
3040 res->msgs[0]->elements[0].values[i].data;
3042 new_str = talloc_strdup(ac->msg,
3043 strtok_r(old_str, "/", &pos));
3044 if (new_str == NULL) {
3045 return ldb_module_oom(ac->module);
3048 while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
3049 if ((dns_hostname != NULL) &&
3050 (strcasecmp_m(tok, old_dns_hostname) == 0)) {
3053 if ((sam_accountname != NULL) &&
3054 (strcasecmp_m(tok, old_sam_accountname) == 0)) {
3055 tok = sam_accountname;
3058 new_str = talloc_asprintf(ac->msg, "%s/%s",
3060 if (new_str == NULL) {
3061 return ldb_module_oom(ac->module);
3065 /* Uniqueness check */
3066 for (j = 0; (!found) && (j < el->num_values); j++) {
3067 if (strcasecmp_m((char *)el->values[j].data,
3077 * append the new "servicePrincipalName" -
3078 * code derived from ldb_msg_add_value().
3080 * Open coded to make it clear that we must
3081 * append to the MOD_REPLACE el created above.
3083 vals = talloc_realloc(ac->msg, el->values,
3085 el->num_values + 1);
3087 return ldb_module_oom(ac->module);
3090 el->values[el->num_values] = data_blob_string_const(new_str);
3100 /* This checks the "fSMORoleOwner" attributes */
3101 static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
3103 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3104 const char * const no_attrs[] = { NULL };
3105 struct ldb_message_element *el;
3106 struct ldb_message *tmp_msg;
3107 struct ldb_dn *res_dn;
3108 struct ldb_result *res;
3111 el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
3112 ac->req->operation);
3114 /* we are not affected */
3118 /* Create a temporary message for fetching the "fSMORoleOwner" */
3119 tmp_msg = ldb_msg_new(ac->msg);
3120 if (tmp_msg == NULL) {
3121 return ldb_module_oom(ac->module);
3123 ret = ldb_msg_add(tmp_msg, el, 0);
3124 if (ret != LDB_SUCCESS) {
3127 res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
3128 talloc_free(tmp_msg);
3130 if (res_dn == NULL) {
3131 ldb_set_errstring(ldb,
3132 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3133 if (ac->req->operation == LDB_ADD) {
3134 return LDB_ERR_CONSTRAINT_VIOLATION;
3136 return LDB_ERR_UNWILLING_TO_PERFORM;
3140 /* Fetched DN has to reference a "nTDSDSA" entry */
3141 ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
3143 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3144 ac->req, "(objectClass=nTDSDSA)");
3145 if (ret != LDB_SUCCESS) {
3148 if (res->count != 1) {
3149 ldb_set_errstring(ldb,
3150 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3151 return LDB_ERR_UNWILLING_TO_PERFORM;
3160 * Return zero if the number of zero bits in the address (looking from low to
3161 * high) is equal to or greater than the length minus the mask. Otherwise it
3164 static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
3167 /* <address> is an integer in big-endian form, <len> bits long. All
3168 bits between <mask> and <len> must be zero. */
3170 unsigned int byte_len;
3171 unsigned int byte_mask;
3172 unsigned int bit_mask;
3174 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
3175 address[0], address[1], address[2], address[3],
3177 } else if (len == 128){
3178 DBG_INFO("Looking at address "
3179 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
3180 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
3181 address[0], address[1], address[2], address[3],
3182 address[4], address[5], address[6], address[7],
3183 address[8], address[9], address[10], address[11],
3184 address[12], address[13], address[14], address[15],
3189 DBG_INFO("mask %u is too big (> %u)\n", mask, len);
3193 /* single address subnet.
3194 * In IPv4 all 255s is invalid by the bitmask != address rule
3195 * in MS-ADTS. IPv6 does not suffer.
3198 if (address[0] == 255 &&
3199 address[1] == 255 &&
3200 address[2] == 255 &&
3209 byte_mask = mask / 8;
3211 for (i = byte_len - 1; i > byte_mask; i--){
3212 DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
3213 if (address[i] != 0){
3217 bit_mask = (1 << (8 - (mask & 7))) - 1;
3218 DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
3219 bit_mask & address[byte_mask]);
3220 if (address[byte_mask] & bit_mask){
3224 /* According to MS-ADTS, the mask can't exactly equal the bitmask for
3225 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
3226 * because the bitmask implied by "/17" is 255.255.80.0.
3228 * The bit_mask used in the previous check is the complement of what
3231 if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
3233 for (i = 0; i < byte_mask; i++){
3234 if (address[i] != 255){
3248 static int check_address_roundtrip(const char *address, int family,
3249 const uint8_t *address_bytes,
3250 char *buffer, int buffer_len)
3253 * Check that the address is in the canonical RFC5952 format for IPv6,
3254 * and lacks extra leading zeros for each dotted decimal for IPv4.
3255 * Handily this is what inet_ntop() gives you.
3257 const char *address_redux = inet_ntop(family, address_bytes,
3258 buffer, buffer_len);
3259 if (address_redux == NULL){
3260 DBG_INFO("Address round trip %s failed unexpectedly"
3261 " with errno %d\n", address, errno);
3264 if (strcasecmp(address, address_redux) != 0){
3265 DBG_INFO("Address %s round trips to %s; fail!\n",
3266 address, address_redux);
3267 /* If the address family is IPv6, and the address is in a
3271 if (strchr(address_redux, '.') != NULL){
3272 DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
3273 "lying in a range that was once used for "
3274 "IPv4 embedding (that is, it might also be "
3275 "represented as '%s').\n", address,
3286 * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
3287 * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
3288 * CIDR address range without saying so explicitly. Here we follow the CIDR
3291 * Return 0 on success, -1 on error.
3293 static int verify_cidr(const char *cidr)
3295 char *address = NULL, *slash = NULL, *endptr = NULL;
3296 bool has_colon, has_dot;
3299 uint8_t *address_bytes = NULL;
3300 char *address_redux = NULL;
3301 unsigned int address_len;
3302 TALLOC_CTX *frame = NULL;
3304 DBG_DEBUG("CIDR is %s\n", cidr);
3305 frame = talloc_stackframe();
3306 address = talloc_strdup(frame, cidr);
3307 if (address == NULL){
3311 /* there must be a '/' */
3312 slash = strchr(address, '/');
3316 /* terminate the address for strchr, inet_pton */
3319 mask = strtoul(slash + 1, &endptr, 10);
3321 DBG_INFO("Windows does not like the zero mask, "
3322 "so nor do we: %s\n", cidr);
3326 if (*endptr != '\0' || endptr == slash + 1){
3327 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
3331 address_bytes = talloc_size(frame, sizeof(struct in6_addr));
3332 if (address_bytes == NULL){
3336 address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
3337 if (address_redux == NULL){
3341 DBG_INFO("found address %s, mask %lu\n", address, mask);
3342 has_colon = (strchr(address, ':') == NULL) ? false : true;
3343 has_dot = (strchr(address, '.') == NULL) ? false : true;
3344 if (has_dot && has_colon){
3345 /* This seems to be an IPv4 address embedded in IPv6, which is
3346 icky. We don't support it. */
3347 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
3350 } else if (has_colon){ /* looks like IPv6 */
3351 res = inet_pton(AF_INET6, address, address_bytes);
3353 DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
3357 if (check_address_roundtrip(address, AF_INET6, address_bytes,
3358 address_redux, INET6_ADDRSTRLEN)){
3361 } else if (has_dot) {
3362 /* looks like IPv4 */
3363 if (strcmp(address, "0.0.0.0") == 0){
3364 DBG_INFO("Windows does not like the zero IPv4 address, "
3368 res = inet_pton(AF_INET, address, address_bytes);
3370 DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
3375 if (check_address_roundtrip(address, AF_INET, address_bytes,
3376 address_redux, INET_ADDRSTRLEN)){
3380 /* This doesn't look like an IP address at all. */
3384 ret = check_cidr_zero_bits(address_bytes, address_len, mask);
3393 static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
3395 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3396 const char *cidr = NULL;
3397 const struct ldb_val *rdn_value = NULL;
3399 rdn_value = ldb_dn_get_rdn_val(dn);
3400 if (rdn_value == NULL) {
3401 ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
3403 return LDB_ERR_UNWILLING_TO_PERFORM;
3406 cidr = ldb_dn_escape_value(ac, *rdn_value);
3407 DBG_INFO("looking at cidr '%s'\n", cidr);
3409 ldb_set_errstring(ldb,
3410 "samldb: adding an empty subnet cidr seems wrong");
3411 return LDB_ERR_UNWILLING_TO_PERFORM;
3414 if (verify_cidr(cidr)){
3415 ldb_set_errstring(ldb,
3416 "samldb: subnet value is invalid");
3417 return LDB_ERR_INVALID_DN_SYNTAX;
3423 static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
3427 struct loadparm_context *lp_ctx;
3432 if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
3433 ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
3437 ret = samdb_rodc(ldb, &rodc);
3438 if (ret != LDB_SUCCESS) {
3439 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
3444 const char *domain = NULL;
3445 struct ldb_dn *fsmo_role_dn;
3446 struct ldb_dn *role_owner_dn;
3447 ldb_set_errstring(ldb, "RODC modify is forbidden!");
3448 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3449 struct loadparm_context);
3451 err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3452 &fsmo_role_dn, &role_owner_dn);
3453 if (W_ERROR_IS_OK(err)) {
3454 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3455 if (server_dn != NULL) {
3456 ldb_dn_remove_child_components(server_dn, 1);
3458 domain = samdb_dn_to_dnshostname(ldb, req,
3462 if (domain == NULL) {
3463 domain = lpcfg_dnsdomain(lp_ctx);
3465 referral = talloc_asprintf(req,
3468 ldb_dn_get_linearized(dn));
3477 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
3479 struct ldb_context *ldb;
3480 struct samldb_ctx *ac;
3481 struct ldb_message_element *el;
3483 char *referral = NULL;
3485 ldb = ldb_module_get_ctx(module);
3486 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
3488 /* do not manipulate our control entries */
3489 if (ldb_dn_is_special(req->op.add.message->dn)) {
3490 return ldb_next_request(module, req);
3493 referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
3494 if (referral != NULL) {
3495 ret = ldb_module_send_referral(req, referral);
3499 el = ldb_msg_find_element(req->op.add.message, "userParameters");
3500 if (el != NULL && ldb_req_is_untrusted(req)) {
3501 const char *reason = "samldb_add: "
3502 "setting userParameters is not supported over LDAP, "
3503 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3504 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3505 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3508 ac = samldb_ctx_init(module, req);
3510 return ldb_operr(ldb);
3513 /* build the new msg */
3514 ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
3515 if (ac->msg == NULL) {
3517 ldb_debug(ldb, LDB_DEBUG_FATAL,
3518 "samldb_add: ldb_msg_copy_shallow failed!\n");
3519 return ldb_operr(ldb);
3522 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3524 ret = samldb_fsmo_role_owner_check(ac);
3525 if (ret != LDB_SUCCESS) {
3530 if (samdb_find_attribute(ldb, ac->msg,
3531 "objectclass", "user") != NULL) {
3532 ac->type = SAMLDB_TYPE_USER;
3534 ret = samldb_prim_group_trigger(ac);
3535 if (ret != LDB_SUCCESS) {
3539 ret = samldb_objectclass_trigger(ac);
3540 if (ret != LDB_SUCCESS) {
3544 return samldb_fill_object(ac);
3547 if (samdb_find_attribute(ldb, ac->msg,
3548 "objectclass", "group") != NULL) {
3549 ac->type = SAMLDB_TYPE_GROUP;
3551 ret = samldb_objectclass_trigger(ac);
3552 if (ret != LDB_SUCCESS) {
3556 return samldb_fill_object(ac);
3559 /* perhaps a foreignSecurityPrincipal? */
3560 if (samdb_find_attribute(ldb, ac->msg,
3562 "foreignSecurityPrincipal") != NULL) {
3563 return samldb_fill_foreignSecurityPrincipal_object(ac);
3566 if (samdb_find_attribute(ldb, ac->msg,
3567 "objectclass", "classSchema") != NULL) {
3568 ac->type = SAMLDB_TYPE_CLASS;
3570 /* If in provision, these checks are too slow to do */
3571 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3572 ret = samldb_schema_governsid_valid_check(ac);
3573 if (ret != LDB_SUCCESS) {
3578 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3579 if (ret != LDB_SUCCESS) {
3583 ret = samldb_schema_info_update(ac);
3584 if (ret != LDB_SUCCESS) {
3589 return samldb_fill_object(ac);
3592 if (samdb_find_attribute(ldb, ac->msg,
3593 "objectclass", "attributeSchema") != NULL) {
3594 ac->type = SAMLDB_TYPE_ATTRIBUTE;
3596 /* If in provision, these checks are too slow to do */
3597 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3598 ret = samldb_schema_attributeid_valid_check(ac);
3599 if (ret != LDB_SUCCESS) {
3603 ret = samldb_schema_add_handle_linkid(ac);
3604 if (ret != LDB_SUCCESS) {
3608 ret = samldb_schema_add_handle_mapiid(ac);
3609 if (ret != LDB_SUCCESS) {
3614 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3615 if (ret != LDB_SUCCESS) {
3619 ret = samldb_schema_info_update(ac);
3620 if (ret != LDB_SUCCESS) {
3625 return samldb_fill_object(ac);
3628 if (samdb_find_attribute(ldb, ac->msg,
3629 "objectclass", "subnet") != NULL) {
3630 ret = samldb_verify_subnet(ac, ac->msg->dn);
3631 if (ret != LDB_SUCCESS) {
3635 /* We are just checking the value is valid, and there are no
3636 values to fill in. */
3641 /* nothing matched, go on */
3642 return ldb_next_request(module, req);
3646 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
3648 struct ldb_context *ldb;
3649 struct samldb_ctx *ac;
3650 struct ldb_message_element *el, *el2;
3651 struct ldb_control *is_undelete;
3652 bool modified = false;
3655 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3656 /* do not manipulate our control entries */
3657 return ldb_next_request(module, req);
3660 ldb = ldb_module_get_ctx(module);
3663 * we are going to need some special handling if in Undelete call.
3664 * Since tombstone_reanimate module will restore certain attributes,
3665 * we need to relax checks for: sAMAccountType, primaryGroupID
3667 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3669 /* make sure that "objectSid" is not specified */
3670 el = ldb_msg_find_element(req->op.mod.message, "objectSid");
3672 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
3673 ldb_set_errstring(ldb,
3674 "samldb: objectSid must not be specified!");
3675 return LDB_ERR_UNWILLING_TO_PERFORM;
3678 if (is_undelete == NULL) {
3679 /* make sure that "sAMAccountType" is not specified */
3680 el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
3682 ldb_set_errstring(ldb,
3683 "samldb: sAMAccountType must not be specified!");
3684 return LDB_ERR_UNWILLING_TO_PERFORM;
3687 /* make sure that "isCriticalSystemObject" is not specified */
3688 el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
3690 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
3691 ldb_set_errstring(ldb,
3692 "samldb: isCriticalSystemObject must not be specified!");
3693 return LDB_ERR_UNWILLING_TO_PERFORM;
3697 /* msDS-IntId is not allowed to be modified
3698 * except when modification comes from replication */
3699 if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
3700 if (!ldb_request_get_control(req,
3701 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
3702 return LDB_ERR_CONSTRAINT_VIOLATION;
3706 el = ldb_msg_find_element(req->op.mod.message, "userParameters");
3707 if (el != NULL && ldb_req_is_untrusted(req)) {
3708 const char *reason = "samldb: "
3709 "setting userParameters is not supported over LDAP, "
3710 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3711 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3712 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3715 ac = samldb_ctx_init(module, req);
3717 return ldb_operr(ldb);
3720 /* build the new msg */
3721 ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3722 if (ac->msg == NULL) {
3724 ldb_debug(ldb, LDB_DEBUG_FATAL,
3725 "samldb_modify: ldb_msg_copy_shallow failed!\n");
3726 return ldb_operr(ldb);
3729 if (is_undelete == NULL) {
3730 el = ldb_msg_find_element(ac->msg, "primaryGroupID");
3732 ret = samldb_prim_group_trigger(ac);
3733 if (ret != LDB_SUCCESS) {
3739 el = ldb_msg_find_element(ac->msg, "userAccountControl");
3742 ret = samldb_user_account_control_change(ac);
3743 if (ret != LDB_SUCCESS) {
3748 el = ldb_msg_find_element(ac->msg, "pwdLastSet");
3751 ret = samldb_pwd_last_set_change(ac);
3752 if (ret != LDB_SUCCESS) {
3757 el = ldb_msg_find_element(ac->msg, "lockoutTime");
3760 ret = samldb_lockout_time(ac);
3761 if (ret != LDB_SUCCESS) {
3766 el = ldb_msg_find_element(ac->msg, "groupType");
3769 ret = samldb_group_type_change(ac);
3770 if (ret != LDB_SUCCESS) {
3775 el = ldb_msg_find_element(ac->msg, "sAMAccountName");
3777 ret = samldb_sam_accountname_valid_check(ac);
3779 * Other errors are checked for elsewhere, we just
3780 * want to prevent duplicates
3782 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
3787 el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
3789 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3790 if (ret != LDB_SUCCESS) {
3795 el = ldb_msg_find_element(ac->msg, "attributeID");
3797 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3798 "Once set, attributeID values may not be modified");
3799 return LDB_ERR_CONSTRAINT_VIOLATION;
3802 el = ldb_msg_find_element(ac->msg, "governsID");
3804 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3805 "Once set, governsID values may not be modified");
3806 return LDB_ERR_CONSTRAINT_VIOLATION;
3809 el = ldb_msg_find_element(ac->msg, "member");
3811 ret = samldb_member_check(ac);
3812 if (ret != LDB_SUCCESS) {
3817 el = ldb_msg_find_element(ac->msg, "description");
3819 ret = samldb_description_check(ac, &modified);
3820 if (ret != LDB_SUCCESS) {
3825 el = ldb_msg_find_element(ac->msg, "dNSHostName");
3826 el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
3827 if ((el != NULL) || (el2 != NULL)) {
3829 ret = samldb_service_principal_names_change(ac);
3830 if (ret != LDB_SUCCESS) {
3835 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3837 ret = samldb_fsmo_role_owner_check(ac);
3838 if (ret != LDB_SUCCESS) {
3844 struct ldb_request *child_req;
3846 /* Now perform the real modifications as a child request */
3847 ret = ldb_build_mod_req(&child_req, ldb, ac,
3850 req, dsdb_next_callback,
3852 LDB_REQ_SET_LOCATION(child_req);
3853 if (ret != LDB_SUCCESS) {
3857 return ldb_next_request(module, child_req);
3862 /* no change which interests us, go on */
3863 return ldb_next_request(module, req);
3868 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
3870 struct ldb_context *ldb;
3871 struct dom_sid *sid;
3875 struct ldb_result *res = NULL;
3876 struct ldb_result *res_users = NULL;
3877 const char * const attrs[] = { "objectSid", "isDeleted", NULL };
3878 const char * const noattrs[] = { NULL };
3880 ldb = ldb_module_get_ctx(ac->module);
3882 /* Finds out the SID/RID of the SAM object */
3883 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
3885 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3887 if (ret != LDB_SUCCESS) {
3891 if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
3895 sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
3897 /* No SID - it might not be a SAM object - therefore ok */
3900 status = dom_sid_split_rid(ac, sid, NULL, &rid);
3901 if (!NT_STATUS_IS_OK(status)) {
3902 return ldb_operr(ldb);
3905 /* Special object (security principal?) */
3908 /* do not allow deletion of well-known sids */
3909 if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
3910 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
3911 return LDB_ERR_OTHER;
3914 /* Deny delete requests from groups which are primary ones */
3915 ret = dsdb_module_search(ac->module, ac, &res_users,
3916 ldb_get_default_basedn(ldb),
3917 LDB_SCOPE_SUBTREE, noattrs,
3918 DSDB_FLAG_NEXT_MODULE,
3920 "(&(primaryGroupID=%u)(objectClass=user))", rid);
3921 if (ret != LDB_SUCCESS) {
3924 if (res_users->count > 0) {
3925 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3926 "Refusing to delete %s, as it "
3927 "is still the primaryGroupID "
3929 ldb_dn_get_linearized(res->msgs[0]->dn),
3933 * Yes, this seems very wrong, but we have a test
3934 * for this exact error code in sam.py
3936 return LDB_ERR_ENTRY_ALREADY_EXISTS;
3942 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
3944 struct samldb_ctx *ac;
3945 char *referral = NULL;
3947 struct ldb_context *ldb;
3949 if (ldb_dn_is_special(req->op.del.dn)) {
3950 /* do not manipulate our control entries */
3951 return ldb_next_request(module, req);
3954 ldb = ldb_module_get_ctx(module);
3956 referral = refer_if_rodc(ldb, req, req->op.del.dn);
3957 if (referral != NULL) {
3958 ret = ldb_module_send_referral(req, referral);
3962 ac = samldb_ctx_init(module, req);
3964 return ldb_operr(ldb_module_get_ctx(module));
3967 ret = samldb_prim_group_users_check(ac);
3968 if (ret != LDB_SUCCESS) {
3974 return ldb_next_request(module, req);
3979 static int check_rename_constraints(struct ldb_message *msg,
3980 struct samldb_ctx *ac,
3981 struct ldb_dn *olddn, struct ldb_dn *newdn)
3983 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3984 struct ldb_dn *dn1, *dn2, *nc_root;
3985 int32_t systemFlags;
3986 bool move_op = false;
3987 bool rename_op = false;
3990 /* Skip the checks if old and new DN are the same, or if we have the
3991 * relax control specified or if the returned objects is already
3992 * deleted and needs only to be moved for consistency. */
3994 if (ldb_dn_compare(olddn, newdn) == 0) {
3997 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
4001 if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
4003 * check originating request if we are supposed
4004 * to "see" this record in first place.
4006 if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
4007 return LDB_ERR_NO_SUCH_OBJECT;
4009 return LDB_ERR_UNWILLING_TO_PERFORM;
4012 /* Objects under CN=System */
4014 dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
4015 if (dn1 == NULL) return ldb_oom(ldb);
4017 if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
4019 return LDB_ERR_OPERATIONS_ERROR;
4022 if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
4023 (ldb_dn_compare_base(dn1, newdn) != 0)) {
4025 ldb_asprintf_errstring(ldb,
4026 "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
4027 ldb_dn_get_linearized(olddn));
4028 return LDB_ERR_OTHER;
4035 if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
4036 (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
4037 ldb_asprintf_errstring(ldb,
4038 "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
4039 ldb_dn_get_linearized(olddn));
4040 return LDB_ERR_UNWILLING_TO_PERFORM;
4043 /* subnet objects */
4044 if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
4045 ret = samldb_verify_subnet(ac, newdn);
4046 if (ret != LDB_SUCCESS) {
4054 dn1 = ldb_dn_get_parent(ac, olddn);
4055 if (dn1 == NULL) return ldb_oom(ldb);
4056 dn2 = ldb_dn_get_parent(ac, newdn);
4057 if (dn2 == NULL) return ldb_oom(ldb);
4059 if (ldb_dn_compare(dn1, dn2) == 0) {
4068 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
4070 /* Fetch name context */
4072 ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
4073 if (ret != LDB_SUCCESS) {
4077 if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
4079 ldb_asprintf_errstring(ldb,
4080 "subtree_rename: Cannot move %s within schema partition",
4081 ldb_dn_get_linearized(olddn));
4082 return LDB_ERR_UNWILLING_TO_PERFORM;
4085 (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
4086 ldb_asprintf_errstring(ldb,
4087 "subtree_rename: Cannot rename %s within schema partition",
4088 ldb_dn_get_linearized(olddn));
4089 return LDB_ERR_UNWILLING_TO_PERFORM;
4091 } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
4093 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
4094 /* Here we have to do more: control the
4095 * "ALLOW_LIMITED_MOVE" flag. This means that the
4096 * grand-grand-parents of two objects have to be equal
4097 * in order to perform the move (this is used for
4098 * moving "server" objects in the "sites" container). */
4100 systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
4103 dn1 = ldb_dn_copy(ac, olddn);
4104 if (dn1 == NULL) return ldb_oom(ldb);
4105 dn2 = ldb_dn_copy(ac, newdn);
4106 if (dn2 == NULL) return ldb_oom(ldb);
4108 limited_move &= ldb_dn_remove_child_components(dn1, 3);
4109 limited_move &= ldb_dn_remove_child_components(dn2, 3);
4110 limited_move &= ldb_dn_compare(dn1, dn2) == 0;
4117 && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
4118 ldb_asprintf_errstring(ldb,
4119 "subtree_rename: Cannot move %s to %s in config partition",
4120 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4121 return LDB_ERR_UNWILLING_TO_PERFORM;
4125 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
4126 ldb_asprintf_errstring(ldb,
4127 "subtree_rename: Cannot rename %s to %s within config partition",
4128 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4129 return LDB_ERR_UNWILLING_TO_PERFORM;
4131 } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
4133 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
4134 ldb_asprintf_errstring(ldb,
4135 "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
4136 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4137 return LDB_ERR_UNWILLING_TO_PERFORM;
4140 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
4141 ldb_asprintf_errstring(ldb,
4142 "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
4143 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4144 return LDB_ERR_UNWILLING_TO_PERFORM;
4148 talloc_free(nc_root);
4154 static int samldb_rename_search_base_callback(struct ldb_request *req,
4155 struct ldb_reply *ares)
4157 struct samldb_ctx *ac;
4160 ac = talloc_get_type(req->context, struct samldb_ctx);
4163 return ldb_module_done(ac->req, NULL, NULL,
4164 LDB_ERR_OPERATIONS_ERROR);
4166 if (ares->error != LDB_SUCCESS) {
4167 return ldb_module_done(ac->req, ares->controls,
4168 ares->response, ares->error);
4171 switch (ares->type) {
4172 case LDB_REPLY_ENTRY:
4174 * This is the root entry of the originating move
4175 * respectively rename request. It has been already
4176 * stored in the list using "subtree_rename_search()".
4177 * Only this one is subject to constraint checking.
4179 ret = check_rename_constraints(ares->message, ac,
4180 ac->req->op.rename.olddn,
4181 ac->req->op.rename.newdn);
4182 if (ret != LDB_SUCCESS) {
4183 return ldb_module_done(ac->req, NULL, NULL,
4188 case LDB_REPLY_REFERRAL:
4192 case LDB_REPLY_DONE:
4195 * Great, no problem with the rename, so go ahead as
4196 * if we never were here
4198 ret = ldb_next_request(ac->module, ac->req);
4209 static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
4211 struct ldb_context *ldb;
4212 static const char * const attrs[] = { "objectClass", "systemFlags",
4213 "isDeleted", NULL };
4214 struct ldb_request *search_req;
4215 struct samldb_ctx *ac;
4218 if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
4219 return ldb_next_request(module, req);
4222 ldb = ldb_module_get_ctx(module);
4224 ac = samldb_ctx_init(module, req);
4226 return ldb_oom(ldb);
4229 ret = ldb_build_search_req(&search_req, ldb, ac,
4230 req->op.rename.olddn,
4236 samldb_rename_search_base_callback,
4238 LDB_REQ_SET_LOCATION(search_req);
4239 if (ret != LDB_SUCCESS) {
4243 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4245 if (ret != LDB_SUCCESS) {
4249 return ldb_next_request(ac->module, search_req);
4254 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
4256 struct ldb_context *ldb = ldb_module_get_ctx(module);
4257 struct dsdb_fsmo_extended_op *exop;
4260 exop = talloc_get_type(req->op.extended.data,
4261 struct dsdb_fsmo_extended_op);
4263 ldb_set_errstring(ldb,
4264 "samldb_extended_allocate_rid_pool: invalid extended data");
4265 return LDB_ERR_PROTOCOL_ERROR;
4268 ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
4269 if (ret != LDB_SUCCESS) {
4273 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4276 static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
4278 struct ldb_context *ldb = ldb_module_get_ctx(module);
4279 struct dsdb_extended_allocate_rid *exop;
4282 exop = talloc_get_type(req->op.extended.data,
4283 struct dsdb_extended_allocate_rid);
4285 ldb_set_errstring(ldb,
4286 "samldb_extended_allocate_rid: invalid extended data");
4287 return LDB_ERR_PROTOCOL_ERROR;
4290 ret = ridalloc_allocate_rid(module, &exop->rid, req);
4291 if (ret != LDB_SUCCESS) {
4295 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4298 static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
4300 struct ldb_context *ldb = ldb_module_get_ctx(module);
4304 if (req->op.extended.data != NULL) {
4305 ldb_set_errstring(ldb,
4306 "samldb_extended_allocate_rid_pool_for_us: invalid extended data (should be NULL)");
4307 return LDB_ERR_PROTOCOL_ERROR;
4310 ret = ridalloc_create_own_rid_set(module, req,
4312 if (ret != LDB_SUCCESS) {
4316 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4319 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
4321 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
4322 return samldb_extended_allocate_rid_pool(module, req);
4325 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
4326 return samldb_extended_allocate_rid(module, req);
4329 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
4330 return samldb_extended_create_own_rid_set(module, req);
4333 return ldb_next_request(module, req);
4337 static const struct ldb_module_ops ldb_samldb_module_ops = {
4340 .modify = samldb_modify,
4341 .del = samldb_delete,
4342 .rename = samldb_rename,
4343 .extended = samldb_extended
4347 int ldb_samldb_module_init(const char *version)
4349 LDB_MODULE_CHECK_VERSION(version);
4350 return ldb_register_module(&ldb_samldb_module_ops);