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_PROVISION_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 search_flags =
1684 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_EXTENDED_DN;
1685 uint32_t prev_rid, new_rid, uac;
1686 struct dom_sid *prev_sid, *new_sid;
1687 struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1688 const char *new_prim_group_dn_ext_str = NULL;
1689 struct ldb_dn *user_dn = NULL;
1690 const char *user_dn_ext_str = NULL;
1692 const char * const noattrs[] = { NULL };
1694 el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1695 ac->req->operation);
1697 /* we are not affected */
1701 /* Fetch information from the existing object */
1703 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1704 search_flags, ac->req);
1705 if (ret != LDB_SUCCESS) {
1708 user_dn = res->msgs[0]->dn;
1709 user_dn_ext_str = ldb_dn_get_extended_linearized(ac, user_dn, 1);
1710 if (user_dn_ext_str == NULL) {
1711 return ldb_operr(ldb);
1714 uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1716 /* Finds out the DN of the old primary group */
1718 prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1720 if (prev_rid == (uint32_t) -1) {
1721 /* User objects do always have a mandatory "primaryGroupID"
1722 * attribute. If this doesn't exist then the object is of the
1723 * wrong type. This is the exact Windows error code */
1724 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1727 prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1728 if (prev_sid == NULL) {
1729 return ldb_operr(ldb);
1732 /* Finds out the DN of the new primary group
1733 * Notice: in order to parse the primary group ID correctly we create
1734 * a temporary message here. */
1736 msg = ldb_msg_new(ac->msg);
1738 return ldb_module_oom(ac->module);
1740 ret = ldb_msg_add(msg, el, 0);
1741 if (ret != LDB_SUCCESS) {
1744 new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1746 if (new_rid == (uint32_t) -1) {
1747 /* we aren't affected of any primary group change */
1751 if (prev_rid == new_rid) {
1755 if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
1756 ldb_asprintf_errstring(ldb,
1757 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
1758 "primaryGroupID=%u!",
1759 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1761 return LDB_ERR_UNWILLING_TO_PERFORM;
1764 if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
1765 ldb_asprintf_errstring(ldb,
1766 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
1767 "primaryGroupID=%u!",
1768 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1769 DOMAIN_RID_READONLY_DCS);
1770 return LDB_ERR_UNWILLING_TO_PERFORM;
1773 ret = dsdb_module_search(ac->module, ac, &group_res,
1774 ldb_get_default_basedn(ldb),
1776 noattrs, search_flags,
1779 ldap_encode_ndr_dom_sid(ac, prev_sid));
1780 if (ret != LDB_SUCCESS) {
1783 if (group_res->count != 1) {
1784 return ldb_operr(ldb);
1786 prev_prim_group_dn = group_res->msgs[0]->dn;
1788 new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1789 if (new_sid == NULL) {
1790 return ldb_operr(ldb);
1793 ret = dsdb_module_search(ac->module, ac, &group_res,
1794 ldb_get_default_basedn(ldb),
1796 noattrs, search_flags,
1799 ldap_encode_ndr_dom_sid(ac, new_sid));
1800 if (ret != LDB_SUCCESS) {
1803 if (group_res->count != 1) {
1804 /* Here we know if the specified new primary group candidate is
1806 return LDB_ERR_UNWILLING_TO_PERFORM;
1808 new_prim_group_dn = group_res->msgs[0]->dn;
1809 new_prim_group_dn_ext_str = ldb_dn_get_extended_linearized(ac,
1810 new_prim_group_dn, 1);
1811 if (new_prim_group_dn_ext_str == NULL) {
1812 return ldb_operr(ldb);
1815 /* We need to be already a normal member of the new primary
1816 * group in order to be successful. */
1817 el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1818 new_prim_group_dn_ext_str);
1820 return LDB_ERR_UNWILLING_TO_PERFORM;
1823 /* Remove the "member" attribute on the new primary group */
1824 msg = ldb_msg_new(ac->msg);
1826 return ldb_module_oom(ac->module);
1828 msg->dn = new_prim_group_dn;
1830 ret = samdb_msg_add_delval(ldb, msg, msg, "member", user_dn_ext_str);
1831 if (ret != LDB_SUCCESS) {
1835 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1836 if (ret != LDB_SUCCESS) {
1841 /* Add a "member" attribute for the previous primary group */
1842 msg = ldb_msg_new(ac->msg);
1844 return ldb_module_oom(ac->module);
1846 msg->dn = prev_prim_group_dn;
1848 ret = samdb_msg_add_addval(ldb, msg, msg, "member", user_dn_ext_str);
1849 if (ret != LDB_SUCCESS) {
1853 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1854 if (ret != LDB_SUCCESS) {
1862 static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1866 if (ac->req->operation == LDB_ADD) {
1867 ret = samldb_prim_group_set(ac);
1869 ret = samldb_prim_group_change(ac);
1875 static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
1876 uint32_t user_account_control)
1879 bool need_check = false;
1880 const struct uac_to_guid {
1885 const char *error_string;
1888 .uac = UF_TEMP_DUPLICATE_ACCOUNT,
1890 .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
1893 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1894 .needs = UF_WORKSTATION_TRUST_ACCOUNT,
1895 .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
1898 .uac = UF_TRUSTED_FOR_DELEGATION,
1899 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1900 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1903 .uac = UF_NORMAL_ACCOUNT,
1904 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
1905 .error_string = "Setting more than one account type not permitted"
1908 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1909 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
1910 .error_string = "Setting more than one account type not permitted"
1913 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1914 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
1915 .error_string = "Setting more than one account type not permitted"
1918 .uac = UF_SERVER_TRUST_ACCOUNT,
1919 .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
1920 .error_string = "Setting more than one account type not permitted"
1923 .uac = UF_TRUSTED_FOR_DELEGATION,
1924 .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1925 .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1929 for (i = 0; i < ARRAY_SIZE(map); i++) {
1930 if (user_account_control & map[i].uac) {
1935 if (need_check == false) {
1939 for (i = 0; i < ARRAY_SIZE(map); i++) {
1940 uint32_t this_uac = user_account_control & map[i].uac;
1941 if (this_uac != 0) {
1943 ret = LDB_ERR_OTHER;
1945 } else if (map[i].needs != 0) {
1946 if ((map[i].needs & user_account_control) == 0) {
1947 ret = LDB_ERR_OTHER;
1950 } else if (map[i].not_with != 0) {
1951 if ((map[i].not_with & user_account_control) != 0) {
1952 ret = LDB_ERR_OTHER;
1958 if (ret != LDB_SUCCESS) {
1959 switch (ac->req->operation) {
1961 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1962 "Failed to add %s: %s",
1963 ldb_dn_get_linearized(ac->msg->dn),
1964 map[i].error_string);
1967 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1968 "Failed to modify %s: %s",
1969 ldb_dn_get_linearized(ac->msg->dn),
1970 map[i].error_string);
1973 return ldb_module_operr(ac->module);
1980 * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
1983 static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
1984 struct dom_sid *sid,
1985 uint32_t user_account_control,
1986 uint32_t user_account_control_old)
1989 bool need_acl_check = false;
1990 struct ldb_result *res;
1991 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
1992 struct security_token *user_token;
1993 struct security_descriptor *domain_sd;
1994 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
1995 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1996 const struct uac_to_guid {
1998 uint32_t priv_to_change_from;
2001 enum sec_privilege privilege;
2002 bool delete_is_privileged;
2003 bool admin_required;
2004 const char *error_string;
2007 .uac = UF_PASSWD_NOTREQD,
2008 .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
2009 .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"
2012 .uac = UF_DONT_EXPIRE_PASSWD,
2013 .guid = GUID_DRS_UNEXPIRE_PASSWORD,
2014 .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
2017 .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
2018 .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
2019 .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"
2022 .uac = UF_SERVER_TRUST_ACCOUNT,
2023 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2024 .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"
2027 .uac = UF_PARTIAL_SECRETS_ACCOUNT,
2028 .guid = GUID_DRS_DS_INSTALL_REPLICA,
2029 .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"
2032 .uac = UF_WORKSTATION_TRUST_ACCOUNT,
2033 .priv_to_change_from = UF_NORMAL_ACCOUNT,
2034 .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
2037 .uac = UF_NORMAL_ACCOUNT,
2038 .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
2039 .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
2042 .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
2043 .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2044 .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",
2045 .delete_is_privileged = true
2048 .uac = UF_TRUSTED_FOR_DELEGATION,
2049 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2050 .delete_is_privileged = true,
2051 .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2054 .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
2055 .privilege = SEC_PRIV_ENABLE_DELEGATION,
2056 .delete_is_privileged = true,
2057 .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2062 if (dsdb_module_am_system(ac->module)) {
2066 for (i = 0; i < ARRAY_SIZE(map); i++) {
2067 if (user_account_control & map[i].uac) {
2068 need_acl_check = true;
2072 if (need_acl_check == false) {
2076 user_token = acl_user_token(ac->module);
2077 if (user_token == NULL) {
2078 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2081 ret = dsdb_module_search_dn(ac->module, ac, &res,
2084 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2086 if (ret != LDB_SUCCESS) {
2089 if (res->count != 1) {
2090 return ldb_module_operr(ac->module);
2093 ret = dsdb_get_sd_from_ldb_message(ldb,
2094 ac, res->msgs[0], &domain_sd);
2096 if (ret != LDB_SUCCESS) {
2100 for (i = 0; i < ARRAY_SIZE(map); i++) {
2101 uint32_t this_uac_new = user_account_control & map[i].uac;
2102 uint32_t this_uac_old = user_account_control_old & map[i].uac;
2103 if (this_uac_new != this_uac_old) {
2104 if (this_uac_old != 0) {
2105 if (map[i].delete_is_privileged == false) {
2110 struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
2111 if (control == NULL) {
2112 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2114 } else if (map[i].privilege != SEC_PRIV_INVALID) {
2115 bool have_priv = security_token_has_privilege(user_token,
2117 if (have_priv == false) {
2118 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2120 } else if (map[i].priv_to_change_from & user_account_control_old) {
2121 bool is_admin = security_token_has_builtin_administrators(user_token);
2122 if (is_admin == false) {
2123 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2125 } else if (map[i].guid) {
2126 ret = acl_check_extended_right(ac, domain_sd,
2129 SEC_ADS_CONTROL_ACCESS,
2134 if (ret != LDB_SUCCESS) {
2139 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2140 switch (ac->req->operation) {
2142 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2143 "Failed to add %s: %s",
2144 ldb_dn_get_linearized(ac->msg->dn),
2145 map[i].error_string);
2148 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2149 "Failed to modify %s: %s",
2150 ldb_dn_get_linearized(ac->msg->dn),
2151 map[i].error_string);
2154 return ldb_module_operr(ac->module);
2157 dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
2166 static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
2167 struct dom_sid *sid,
2169 uint32_t user_account_control,
2170 uint32_t user_account_control_old)
2173 struct dsdb_control_password_user_account_control *uac = NULL;
2175 ret = samldb_check_user_account_control_invariants(ac, user_account_control);
2176 if (ret != LDB_SUCCESS) {
2179 ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
2180 if (ret != LDB_SUCCESS) {
2184 uac = talloc_zero(ac->req,
2185 struct dsdb_control_password_user_account_control);
2187 return ldb_module_oom(ac->module);
2190 uac->req_flags = req_uac;
2191 uac->old_flags = user_account_control_old;
2192 uac->new_flags = user_account_control;
2194 ret = ldb_request_add_control(ac->req,
2195 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
2197 if (ret != LDB_SUCCESS) {
2206 * This function is called on LDB modify operations. It performs some additions/
2207 * replaces on the current LDB message when "userAccountControl" changes.
2209 static int samldb_user_account_control_change(struct samldb_ctx *ac)
2211 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2217 uint32_t old_uac_computed;
2223 NTTIME old_lockoutTime;
2224 struct ldb_message_element *el;
2225 struct ldb_val *val;
2226 struct ldb_val computer_val;
2227 struct ldb_message *tmp_msg;
2228 struct dom_sid *sid;
2230 struct ldb_result *res;
2231 const char * const attrs[] = {
2233 "isCriticalSystemObject",
2234 "userAccountControl",
2235 "msDS-User-Account-Control-Computed",
2240 bool is_computer = false;
2241 bool old_is_critical = false;
2242 bool new_is_critical = false;
2244 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2245 ac->req->operation);
2246 if (el == NULL || el->num_values == 0) {
2247 ldb_asprintf_errstring(ldb,
2248 "%08X: samldb: 'userAccountControl' can't be deleted!",
2249 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2250 return LDB_ERR_UNWILLING_TO_PERFORM;
2253 /* Create a temporary message for fetching the "userAccountControl" */
2254 tmp_msg = ldb_msg_new(ac->msg);
2255 if (tmp_msg == NULL) {
2256 return ldb_module_oom(ac->module);
2258 ret = ldb_msg_add(tmp_msg, el, 0);
2259 if (ret != LDB_SUCCESS) {
2262 raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
2263 "userAccountControl",
2265 talloc_free(tmp_msg);
2267 * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2268 * are only generated and not stored. We ignore them almost
2269 * completely, along with unknown bits and UF_SCRIPT.
2271 * The only exception is ACB_AUTOLOCK, which features in
2272 * clear_acb when the bit is cleared in this modify operation.
2274 * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2275 * ignored by clients and servers
2277 new_uac = raw_uac & UF_SETTABLE_BITS;
2279 /* Fetch the old "userAccountControl" and "objectClass" */
2280 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2281 DSDB_FLAG_NEXT_MODULE, ac->req);
2282 if (ret != LDB_SUCCESS) {
2285 old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
2287 return ldb_operr(ldb);
2289 old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
2290 "msDS-User-Account-Control-Computed", 0);
2291 old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
2293 old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
2294 "isCriticalSystemObject", 0);
2295 /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
2296 el = ldb_msg_find_element(res->msgs[0], "objectClass");
2298 return ldb_operr(ldb);
2300 computer_val = data_blob_string_const("computer");
2301 val = ldb_msg_find_val(el, &computer_val);
2306 old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
2307 old_atype = ds_uf2atype(old_ufa);
2308 old_pgrid = ds_uf2prim_group_rid(old_uac);
2310 new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
2313 * "userAccountControl" = 0 or missing one of the
2314 * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2315 * 3.1.1.8.10 point 8
2317 new_ufa = UF_NORMAL_ACCOUNT;
2320 sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2322 return ldb_module_operr(ac->module);
2325 ret = samldb_check_user_account_control_rules(ac, sid,
2329 if (ret != LDB_SUCCESS) {
2333 new_atype = ds_uf2atype(new_ufa);
2334 new_pgrid = ds_uf2prim_group_rid(new_uac);
2336 clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
2339 case UF_NORMAL_ACCOUNT:
2340 new_is_critical = old_is_critical;
2343 case UF_INTERDOMAIN_TRUST_ACCOUNT:
2344 new_is_critical = true;
2347 case UF_WORKSTATION_TRUST_ACCOUNT:
2348 new_is_critical = false;
2349 if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
2351 ldb_asprintf_errstring(ldb,
2352 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
2353 "requires objectclass 'computer'!",
2354 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2355 return LDB_ERR_UNWILLING_TO_PERFORM;
2357 new_is_critical = true;
2361 case UF_SERVER_TRUST_ACCOUNT:
2363 ldb_asprintf_errstring(ldb,
2364 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2365 "requires objectclass 'computer'!",
2366 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2367 return LDB_ERR_UNWILLING_TO_PERFORM;
2369 new_is_critical = true;
2373 ldb_asprintf_errstring(ldb,
2374 "%08X: samldb: invalid userAccountControl[0x%08X]",
2375 W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
2376 return LDB_ERR_OTHER;
2379 if (old_atype != new_atype) {
2380 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2381 "sAMAccountType", new_atype);
2382 if (ret != LDB_SUCCESS) {
2385 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2386 el->flags = LDB_FLAG_MOD_REPLACE;
2389 /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
2390 if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
2391 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
2392 ldb_msg_remove_attr(ac->msg, "lockoutTime");
2393 ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
2395 if (ret != LDB_SUCCESS) {
2398 el = ldb_msg_find_element(ac->msg, "lockoutTime");
2399 el->flags = LDB_FLAG_MOD_REPLACE;
2402 /* "isCriticalSystemObject" might be set/changed */
2403 if (old_is_critical != new_is_critical) {
2404 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
2405 new_is_critical ? "TRUE": "FALSE");
2406 if (ret != LDB_SUCCESS) {
2409 el = ldb_msg_find_element(ac->msg,
2410 "isCriticalSystemObject");
2411 el->flags = LDB_FLAG_MOD_REPLACE;
2414 if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
2415 (old_pgrid != new_pgrid)) {
2416 /* Older AD deployments don't know about the RODC group */
2417 if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
2418 ret = samldb_prim_group_tester(ac, new_pgrid);
2419 if (ret != LDB_SUCCESS) {
2424 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2425 "primaryGroupID", new_pgrid);
2426 if (ret != LDB_SUCCESS) {
2429 el = ldb_msg_find_element(ac->msg,
2431 el->flags = LDB_FLAG_MOD_REPLACE;
2434 /* Propagate eventual "userAccountControl" attribute changes */
2435 if (old_uac != new_uac) {
2436 char *tempstr = talloc_asprintf(ac->msg, "%d",
2438 if (tempstr == NULL) {
2439 return ldb_module_oom(ac->module);
2442 /* Overwrite "userAccountControl" correctly */
2443 el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2444 ac->req->operation);
2445 el->values[0].data = (uint8_t *) tempstr;
2446 el->values[0].length = strlen(tempstr);
2448 ldb_msg_remove_attr(ac->msg, "userAccountControl");
2454 static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
2455 struct dom_sid *sid)
2457 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2459 struct ldb_result *res = NULL;
2460 const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
2461 struct security_token *user_token = NULL;
2462 struct security_descriptor *domain_sd = NULL;
2463 struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2464 const char *operation = "";
2466 if (dsdb_module_am_system(ac->module)) {
2470 switch (ac->req->operation) {
2475 operation = "modify";
2478 return ldb_module_operr(ac->module);
2481 user_token = acl_user_token(ac->module);
2482 if (user_token == NULL) {
2483 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2486 ret = dsdb_module_search_dn(ac->module, ac, &res,
2489 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2491 if (ret != LDB_SUCCESS) {
2494 if (res->count != 1) {
2495 return ldb_module_operr(ac->module);
2498 ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
2499 if (ret != LDB_SUCCESS) {
2503 ret = acl_check_extended_right(ac, domain_sd,
2505 GUID_DRS_UNEXPIRE_PASSWORD,
2506 SEC_ADS_CONTROL_ACCESS,
2508 if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2512 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
2514 "Setting pwdLastSet to -1 requires the "
2515 "Unexpire-Password right that was not given "
2516 "on the Domain object",
2518 ldb_dn_get_linearized(ac->msg->dn));
2519 dsdb_acl_debug(domain_sd, user_token,
2520 domain_dn, true, 10);
2526 * This function is called on LDB modify operations. It performs some additions/
2527 * replaces on the current LDB message when "pwdLastSet" changes.
2529 static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
2531 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2532 NTTIME last_set = 0;
2533 struct ldb_message_element *el = NULL;
2534 struct ldb_message *tmp_msg = NULL;
2535 struct dom_sid *self_sid = NULL;
2537 struct ldb_result *res = NULL;
2538 const char * const attrs[] = {
2543 el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
2544 ac->req->operation);
2545 if (el == NULL || el->num_values == 0) {
2546 ldb_asprintf_errstring(ldb,
2547 "%08X: samldb: 'pwdLastSet' can't be deleted!",
2548 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2549 return LDB_ERR_UNWILLING_TO_PERFORM;
2552 /* Create a temporary message for fetching the "userAccountControl" */
2553 tmp_msg = ldb_msg_new(ac->msg);
2554 if (tmp_msg == NULL) {
2555 return ldb_module_oom(ac->module);
2557 ret = ldb_msg_add(tmp_msg, el, 0);
2558 if (ret != LDB_SUCCESS) {
2561 last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
2562 talloc_free(tmp_msg);
2565 * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
2567 if (last_set != UINT64_MAX) {
2571 /* Fetch the "objectSid" */
2572 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2573 DSDB_FLAG_NEXT_MODULE, ac->req);
2574 if (ret != LDB_SUCCESS) {
2577 self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2578 if (self_sid == NULL) {
2579 return ldb_module_operr(ac->module);
2582 ret = samldb_check_pwd_last_set_acl(ac, self_sid);
2583 if (ret != LDB_SUCCESS) {
2590 static int samldb_lockout_time(struct samldb_ctx *ac)
2592 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2594 struct ldb_message_element *el;
2595 struct ldb_message *tmp_msg;
2598 el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
2599 ac->req->operation);
2600 if (el == NULL || el->num_values == 0) {
2601 ldb_asprintf_errstring(ldb,
2602 "%08X: samldb: 'lockoutTime' can't be deleted!",
2603 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2604 return LDB_ERR_UNWILLING_TO_PERFORM;
2607 /* Create a temporary message for fetching the "lockoutTime" */
2608 tmp_msg = ldb_msg_new(ac->msg);
2609 if (tmp_msg == NULL) {
2610 return ldb_module_oom(ac->module);
2612 ret = ldb_msg_add(tmp_msg, el, 0);
2613 if (ret != LDB_SUCCESS) {
2616 lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
2619 talloc_free(tmp_msg);
2621 if (lockoutTime != 0) {
2625 /* lockoutTime == 0 resets badPwdCount */
2626 ldb_msg_remove_attr(ac->msg, "badPwdCount");
2627 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
2629 if (ret != LDB_SUCCESS) {
2632 el = ldb_msg_find_element(ac->msg, "badPwdCount");
2633 el->flags = LDB_FLAG_MOD_REPLACE;
2638 static int samldb_group_type_change(struct samldb_ctx *ac)
2640 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2641 uint32_t group_type, old_group_type, account_type;
2642 struct ldb_message_element *el;
2643 struct ldb_message *tmp_msg;
2645 struct ldb_result *res;
2646 const char * const attrs[] = { "groupType", NULL };
2648 el = dsdb_get_single_valued_attr(ac->msg, "groupType",
2649 ac->req->operation);
2651 /* we are not affected */
2655 /* Create a temporary message for fetching the "groupType" */
2656 tmp_msg = ldb_msg_new(ac->msg);
2657 if (tmp_msg == NULL) {
2658 return ldb_module_oom(ac->module);
2660 ret = ldb_msg_add(tmp_msg, el, 0);
2661 if (ret != LDB_SUCCESS) {
2664 group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
2665 talloc_free(tmp_msg);
2667 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2668 DSDB_FLAG_NEXT_MODULE |
2669 DSDB_SEARCH_SHOW_DELETED, ac->req);
2670 if (ret != LDB_SUCCESS) {
2673 old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
2674 if (old_group_type == 0) {
2675 return ldb_operr(ldb);
2678 /* Group type switching isn't so easy as it seems: We can only
2679 * change in this directions: global <-> universal <-> local
2680 * On each step also the group type itself
2681 * (security/distribution) is variable. */
2683 if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
2684 switch (group_type) {
2685 case GTYPE_SECURITY_GLOBAL_GROUP:
2686 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
2687 /* change to "universal" allowed */
2688 if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
2689 (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
2690 ldb_set_errstring(ldb,
2691 "samldb: Change from security/distribution local group forbidden!");
2692 return LDB_ERR_UNWILLING_TO_PERFORM;
2696 case GTYPE_SECURITY_UNIVERSAL_GROUP:
2697 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
2698 /* each change allowed */
2700 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
2701 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
2702 /* change to "universal" allowed */
2703 if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
2704 (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
2705 ldb_set_errstring(ldb,
2706 "samldb: Change from security/distribution global group forbidden!");
2707 return LDB_ERR_UNWILLING_TO_PERFORM;
2711 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
2713 /* we don't allow this "groupType" values */
2714 return LDB_ERR_UNWILLING_TO_PERFORM;
2719 account_type = ds_gtype2atype(group_type);
2720 if (account_type == 0) {
2721 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
2722 return LDB_ERR_UNWILLING_TO_PERFORM;
2724 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
2726 if (ret != LDB_SUCCESS) {
2729 el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2730 el->flags = LDB_FLAG_MOD_REPLACE;
2735 static int samldb_member_check(struct samldb_ctx *ac)
2737 const char * const attrs[] = { "objectSid", NULL };
2738 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2739 struct ldb_message_element *el;
2740 struct ldb_dn *member_dn;
2741 struct dom_sid *sid;
2742 struct ldb_result *res;
2743 struct dom_sid *group_sid;
2747 /* Fetch information from the existing object */
2749 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2750 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
2751 if (ret != LDB_SUCCESS) {
2754 if (res->count != 1) {
2755 return ldb_operr(ldb);
2758 group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2759 if (group_sid == NULL) {
2760 return ldb_operr(ldb);
2763 /* We've to walk over all modification entries and consider the "member"
2765 for (i = 0; i < ac->msg->num_elements; i++) {
2766 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
2770 el = &ac->msg->elements[i];
2771 for (j = 0; j < el->num_values; j++) {
2772 struct ldb_result *group_res;
2773 const char *group_attrs[] = { "primaryGroupID" , NULL };
2774 uint32_t prim_group_rid;
2776 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2777 /* Deletes will be handled in
2778 * repl_meta_data, and deletes not
2779 * matching a member will return
2780 * LDB_ERR_UNWILLING_TO_PERFORM
2785 member_dn = ldb_dn_from_ldb_val(ac, ldb,
2787 if (!ldb_dn_validate(member_dn)) {
2788 return ldb_operr(ldb);
2791 /* Denies to add "member"s to groups which are primary
2792 * ones for them - in this case return
2793 * ERR_ENTRY_ALREADY_EXISTS. */
2795 ret = dsdb_module_search_dn(ac->module, ac, &group_res,
2796 member_dn, group_attrs,
2797 DSDB_FLAG_NEXT_MODULE, ac->req);
2798 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2799 /* member DN doesn't exist yet */
2802 if (ret != LDB_SUCCESS) {
2805 prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
2806 if (prim_group_rid == (uint32_t) -1) {
2807 /* the member hasn't to be a user account ->
2808 * therefore no check needed in this case. */
2812 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
2815 return ldb_operr(ldb);
2818 if (dom_sid_equal(group_sid, sid)) {
2819 ldb_asprintf_errstring(ldb,
2820 "samldb: member %s already set via primaryGroupID %u",
2821 ldb_dn_get_linearized(member_dn), prim_group_rid);
2822 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2832 /* SAM objects have special rules regarding the "description" attribute on
2833 * modify operations. */
2834 static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
2836 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2837 const char * const attrs[] = { "objectClass", "description", NULL };
2838 struct ldb_result *res;
2842 /* Fetch information from the existing object */
2843 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2844 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
2845 "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
2846 if (ret != LDB_SUCCESS) {
2847 /* don't treat it specially ... let normal error codes
2848 happen from other places */
2849 ldb_reset_err_string(ldb);
2852 if (res->count == 0) {
2853 /* we didn't match the filter */
2858 /* We've to walk over all modification entries and consider the
2859 * "description" ones. */
2860 for (i = 0; i < ac->msg->num_elements; i++) {
2861 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
2862 ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
2872 /* This trigger adapts the "servicePrincipalName" attributes if the
2873 * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
2874 static int samldb_service_principal_names_change(struct samldb_ctx *ac)
2876 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2877 struct ldb_message_element *el = NULL, *el2 = NULL;
2878 struct ldb_message *msg;
2879 const char * const attrs[] = { "servicePrincipalName", NULL };
2880 struct ldb_result *res;
2881 const char *dns_hostname = NULL, *old_dns_hostname = NULL,
2882 *sam_accountname = NULL, *old_sam_accountname = NULL;
2886 el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
2887 ac->req->operation);
2888 el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
2889 ac->req->operation);
2890 if ((el == NULL) && (el2 == NULL)) {
2891 /* we are not affected */
2895 /* Create a temporary message for fetching the "dNSHostName" */
2897 const char *dns_attrs[] = { "dNSHostName", NULL };
2898 msg = ldb_msg_new(ac->msg);
2900 return ldb_module_oom(ac->module);
2902 ret = ldb_msg_add(msg, el, 0);
2903 if (ret != LDB_SUCCESS) {
2906 dns_hostname = talloc_strdup(ac,
2907 ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
2908 if (dns_hostname == NULL) {
2909 return ldb_module_oom(ac->module);
2914 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
2915 dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
2916 if (ret == LDB_SUCCESS) {
2917 old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
2921 /* Create a temporary message for fetching the "sAMAccountName" */
2923 char *tempstr, *tempstr2 = NULL;
2924 const char *acct_attrs[] = { "sAMAccountName", NULL };
2926 msg = ldb_msg_new(ac->msg);
2928 return ldb_module_oom(ac->module);
2930 ret = ldb_msg_add(msg, el2, 0);
2931 if (ret != LDB_SUCCESS) {
2934 tempstr = talloc_strdup(ac,
2935 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
2938 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
2939 DSDB_FLAG_NEXT_MODULE, ac->req);
2940 if (ret == LDB_SUCCESS) {
2941 tempstr2 = talloc_strdup(ac,
2942 ldb_msg_find_attr_as_string(res->msgs[0],
2943 "sAMAccountName", NULL));
2947 /* The "sAMAccountName" needs some additional trimming: we need
2948 * to remove the trailing "$"s if they exist. */
2949 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
2950 (tempstr[strlen(tempstr) - 1] == '$')) {
2951 tempstr[strlen(tempstr) - 1] = '\0';
2953 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
2954 (tempstr2[strlen(tempstr2) - 1] == '$')) {
2955 tempstr2[strlen(tempstr2) - 1] = '\0';
2957 sam_accountname = tempstr;
2958 old_sam_accountname = tempstr2;
2961 if (old_dns_hostname == NULL) {
2962 /* we cannot change when the old name is unknown */
2963 dns_hostname = NULL;
2965 if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
2966 (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
2967 /* The "dNSHostName" didn't change */
2968 dns_hostname = NULL;
2971 if (old_sam_accountname == NULL) {
2972 /* we cannot change when the old name is unknown */
2973 sam_accountname = NULL;
2975 if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
2976 (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
2977 /* The "sAMAccountName" didn't change */
2978 sam_accountname = NULL;
2981 if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
2982 /* Well, there are information missing (old name(s)) or the
2983 * names didn't change. We've nothing to do and can exit here */
2987 /* Potential "servicePrincipalName" changes in the same request have to
2988 * be handled before the update (Windows behaviour). */
2989 el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
2991 msg = ldb_msg_new(ac->msg);
2993 return ldb_module_oom(ac->module);
2995 msg->dn = ac->msg->dn;
2998 ret = ldb_msg_add(msg, el, el->flags);
2999 if (ret != LDB_SUCCESS) {
3003 ldb_msg_remove_element(ac->msg, el);
3005 el = ldb_msg_find_element(ac->msg,
3006 "servicePrincipalName");
3007 } while (el != NULL);
3009 ret = dsdb_module_modify(ac->module, msg,
3010 DSDB_FLAG_NEXT_MODULE, ac->req);
3011 if (ret != LDB_SUCCESS) {
3017 /* Fetch the "servicePrincipalName"s if any */
3018 ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
3019 DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
3020 if (ret != LDB_SUCCESS) {
3023 if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
3024 return ldb_operr(ldb);
3027 if (res->msgs[0]->num_elements == 1) {
3029 * Yes, we do have "servicePrincipalName"s. First we update them
3030 * locally, that means we do always substitute the current
3031 * "dNSHostName" with the new one and/or "sAMAccountName"
3032 * without "$" with the new one and then we append the
3033 * modified "servicePrincipalName"s as a message element
3034 * replace to the modification request (Windows behaviour). We
3035 * need also to make sure that the values remain case-
3036 * insensitively unique.
3039 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
3040 LDB_FLAG_MOD_REPLACE, &el);
3041 if (ret != LDB_SUCCESS) {
3045 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
3046 char *old_str, *new_str;
3049 struct ldb_val *vals;
3053 res->msgs[0]->elements[0].values[i].data;
3055 new_str = talloc_strdup(ac->msg,
3056 strtok_r(old_str, "/", &pos));
3057 if (new_str == NULL) {
3058 return ldb_module_oom(ac->module);
3061 while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
3062 if ((dns_hostname != NULL) &&
3063 (strcasecmp_m(tok, old_dns_hostname) == 0)) {
3066 if ((sam_accountname != NULL) &&
3067 (strcasecmp_m(tok, old_sam_accountname) == 0)) {
3068 tok = sam_accountname;
3071 new_str = talloc_asprintf(ac->msg, "%s/%s",
3073 if (new_str == NULL) {
3074 return ldb_module_oom(ac->module);
3078 /* Uniqueness check */
3079 for (j = 0; (!found) && (j < el->num_values); j++) {
3080 if (strcasecmp_m((char *)el->values[j].data,
3090 * append the new "servicePrincipalName" -
3091 * code derived from ldb_msg_add_value().
3093 * Open coded to make it clear that we must
3094 * append to the MOD_REPLACE el created above.
3096 vals = talloc_realloc(ac->msg, el->values,
3098 el->num_values + 1);
3100 return ldb_module_oom(ac->module);
3103 el->values[el->num_values] = data_blob_string_const(new_str);
3113 /* This checks the "fSMORoleOwner" attributes */
3114 static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
3116 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3117 const char * const no_attrs[] = { NULL };
3118 struct ldb_message_element *el;
3119 struct ldb_message *tmp_msg;
3120 struct ldb_dn *res_dn;
3121 struct ldb_result *res;
3124 el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
3125 ac->req->operation);
3127 /* we are not affected */
3131 /* Create a temporary message for fetching the "fSMORoleOwner" */
3132 tmp_msg = ldb_msg_new(ac->msg);
3133 if (tmp_msg == NULL) {
3134 return ldb_module_oom(ac->module);
3136 ret = ldb_msg_add(tmp_msg, el, 0);
3137 if (ret != LDB_SUCCESS) {
3140 res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
3141 talloc_free(tmp_msg);
3143 if (res_dn == NULL) {
3144 ldb_set_errstring(ldb,
3145 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3146 if (ac->req->operation == LDB_ADD) {
3147 return LDB_ERR_CONSTRAINT_VIOLATION;
3149 return LDB_ERR_UNWILLING_TO_PERFORM;
3153 /* Fetched DN has to reference a "nTDSDSA" entry */
3154 ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
3156 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3157 ac->req, "(objectClass=nTDSDSA)");
3158 if (ret != LDB_SUCCESS) {
3161 if (res->count != 1) {
3162 ldb_set_errstring(ldb,
3163 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3164 return LDB_ERR_UNWILLING_TO_PERFORM;
3173 * Return zero if the number of zero bits in the address (looking from low to
3174 * high) is equal to or greater than the length minus the mask. Otherwise it
3177 static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
3180 /* <address> is an integer in big-endian form, <len> bits long. All
3181 bits between <mask> and <len> must be zero. */
3183 unsigned int byte_len;
3184 unsigned int byte_mask;
3185 unsigned int bit_mask;
3187 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
3188 address[0], address[1], address[2], address[3],
3190 } else if (len == 128){
3191 DBG_INFO("Looking at address "
3192 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
3193 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
3194 address[0], address[1], address[2], address[3],
3195 address[4], address[5], address[6], address[7],
3196 address[8], address[9], address[10], address[11],
3197 address[12], address[13], address[14], address[15],
3202 DBG_INFO("mask %u is too big (> %u)\n", mask, len);
3206 /* single address subnet.
3207 * In IPv4 all 255s is invalid by the bitmask != address rule
3208 * in MS-ADTS. IPv6 does not suffer.
3211 if (address[0] == 255 &&
3212 address[1] == 255 &&
3213 address[2] == 255 &&
3222 byte_mask = mask / 8;
3224 for (i = byte_len - 1; i > byte_mask; i--){
3225 DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
3226 if (address[i] != 0){
3230 bit_mask = (1 << (8 - (mask & 7))) - 1;
3231 DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
3232 bit_mask & address[byte_mask]);
3233 if (address[byte_mask] & bit_mask){
3237 /* According to MS-ADTS, the mask can't exactly equal the bitmask for
3238 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
3239 * because the bitmask implied by "/17" is 255.255.80.0.
3241 * The bit_mask used in the previous check is the complement of what
3244 if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
3246 for (i = 0; i < byte_mask; i++){
3247 if (address[i] != 255){
3261 static int check_address_roundtrip(const char *address, int family,
3262 const uint8_t *address_bytes,
3263 char *buffer, int buffer_len)
3266 * Check that the address is in the canonical RFC5952 format for IPv6,
3267 * and lacks extra leading zeros for each dotted decimal for IPv4.
3268 * Handily this is what inet_ntop() gives you.
3270 const char *address_redux = inet_ntop(family, address_bytes,
3271 buffer, buffer_len);
3272 if (address_redux == NULL){
3273 DBG_INFO("Address round trip %s failed unexpectedly"
3274 " with errno %d\n", address, errno);
3277 if (strcasecmp(address, address_redux) != 0){
3278 DBG_INFO("Address %s round trips to %s; fail!\n",
3279 address, address_redux);
3280 /* If the address family is IPv6, and the address is in a
3284 if (strchr(address_redux, '.') != NULL){
3285 DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
3286 "lying in a range that was once used for "
3287 "IPv4 embedding (that is, it might also be "
3288 "represented as '%s').\n", address,
3299 * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
3300 * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
3301 * CIDR address range without saying so explicitly. Here we follow the CIDR
3304 * Return 0 on success, -1 on error.
3306 static int verify_cidr(const char *cidr)
3308 char *address = NULL, *slash = NULL, *endptr = NULL;
3309 bool has_colon, has_dot;
3312 uint8_t *address_bytes = NULL;
3313 char *address_redux = NULL;
3314 unsigned int address_len;
3315 TALLOC_CTX *frame = NULL;
3318 DBG_DEBUG("CIDR is %s\n", cidr);
3319 frame = talloc_stackframe();
3320 address = talloc_strdup(frame, cidr);
3321 if (address == NULL){
3325 /* there must be a '/' */
3326 slash = strchr(address, '/');
3330 /* terminate the address for strchr, inet_pton */
3333 mask = strtoul_err(slash + 1, &endptr, 10, &error);
3335 DBG_INFO("Windows does not like the zero mask, "
3336 "so nor do we: %s\n", cidr);
3340 if (*endptr != '\0' || endptr == slash + 1 || error != 0){
3341 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
3345 address_bytes = talloc_size(frame, sizeof(struct in6_addr));
3346 if (address_bytes == NULL){
3350 address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
3351 if (address_redux == NULL){
3355 DBG_INFO("found address %s, mask %lu\n", address, mask);
3356 has_colon = (strchr(address, ':') == NULL) ? false : true;
3357 has_dot = (strchr(address, '.') == NULL) ? false : true;
3358 if (has_dot && has_colon){
3359 /* This seems to be an IPv4 address embedded in IPv6, which is
3360 icky. We don't support it. */
3361 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
3364 } else if (has_colon){ /* looks like IPv6 */
3365 res = inet_pton(AF_INET6, address, address_bytes);
3367 DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
3371 if (check_address_roundtrip(address, AF_INET6, address_bytes,
3372 address_redux, INET6_ADDRSTRLEN)){
3375 } else if (has_dot) {
3376 /* looks like IPv4 */
3377 if (strcmp(address, "0.0.0.0") == 0){
3378 DBG_INFO("Windows does not like the zero IPv4 address, "
3382 res = inet_pton(AF_INET, address, address_bytes);
3384 DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
3389 if (check_address_roundtrip(address, AF_INET, address_bytes,
3390 address_redux, INET_ADDRSTRLEN)){
3394 /* This doesn't look like an IP address at all. */
3398 ret = check_cidr_zero_bits(address_bytes, address_len, mask);
3407 static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
3409 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3410 const char *cidr = NULL;
3411 const struct ldb_val *rdn_value = NULL;
3413 rdn_value = ldb_dn_get_rdn_val(dn);
3414 if (rdn_value == NULL) {
3415 ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
3417 return LDB_ERR_UNWILLING_TO_PERFORM;
3420 cidr = ldb_dn_escape_value(ac, *rdn_value);
3421 DBG_INFO("looking at cidr '%s'\n", cidr);
3423 ldb_set_errstring(ldb,
3424 "samldb: adding an empty subnet cidr seems wrong");
3425 return LDB_ERR_UNWILLING_TO_PERFORM;
3428 if (verify_cidr(cidr)){
3429 ldb_set_errstring(ldb,
3430 "samldb: subnet value is invalid");
3431 return LDB_ERR_INVALID_DN_SYNTAX;
3437 static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
3441 struct loadparm_context *lp_ctx;
3446 if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
3447 ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
3451 ret = samdb_rodc(ldb, &rodc);
3452 if (ret != LDB_SUCCESS) {
3453 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
3458 const char *domain = NULL;
3459 struct ldb_dn *fsmo_role_dn;
3460 struct ldb_dn *role_owner_dn;
3461 ldb_set_errstring(ldb, "RODC modify is forbidden!");
3462 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3463 struct loadparm_context);
3465 err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3466 &fsmo_role_dn, &role_owner_dn);
3467 if (W_ERROR_IS_OK(err)) {
3468 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3469 if (server_dn != NULL) {
3470 ldb_dn_remove_child_components(server_dn, 1);
3472 domain = samdb_dn_to_dnshostname(ldb, req,
3476 if (domain == NULL) {
3477 domain = lpcfg_dnsdomain(lp_ctx);
3479 referral = talloc_asprintf(req,
3482 ldb_dn_get_linearized(dn));
3491 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
3493 struct ldb_context *ldb;
3494 struct samldb_ctx *ac;
3495 struct ldb_message_element *el;
3497 char *referral = NULL;
3499 ldb = ldb_module_get_ctx(module);
3500 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
3502 /* do not manipulate our control entries */
3503 if (ldb_dn_is_special(req->op.add.message->dn)) {
3504 return ldb_next_request(module, req);
3507 referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
3508 if (referral != NULL) {
3509 ret = ldb_module_send_referral(req, referral);
3513 el = ldb_msg_find_element(req->op.add.message, "userParameters");
3514 if (el != NULL && ldb_req_is_untrusted(req)) {
3515 const char *reason = "samldb_add: "
3516 "setting userParameters is not supported over LDAP, "
3517 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3518 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3519 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3522 ac = samldb_ctx_init(module, req);
3524 return ldb_operr(ldb);
3527 /* build the new msg */
3528 ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
3529 if (ac->msg == NULL) {
3531 ldb_debug(ldb, LDB_DEBUG_FATAL,
3532 "samldb_add: ldb_msg_copy_shallow failed!\n");
3533 return ldb_operr(ldb);
3536 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3538 ret = samldb_fsmo_role_owner_check(ac);
3539 if (ret != LDB_SUCCESS) {
3544 if (samdb_find_attribute(ldb, ac->msg,
3545 "objectclass", "user") != NULL) {
3546 ac->type = SAMLDB_TYPE_USER;
3548 ret = samldb_prim_group_trigger(ac);
3549 if (ret != LDB_SUCCESS) {
3553 ret = samldb_objectclass_trigger(ac);
3554 if (ret != LDB_SUCCESS) {
3558 return samldb_fill_object(ac);
3561 if (samdb_find_attribute(ldb, ac->msg,
3562 "objectclass", "group") != NULL) {
3563 ac->type = SAMLDB_TYPE_GROUP;
3565 ret = samldb_objectclass_trigger(ac);
3566 if (ret != LDB_SUCCESS) {
3570 return samldb_fill_object(ac);
3573 /* perhaps a foreignSecurityPrincipal? */
3574 if (samdb_find_attribute(ldb, ac->msg,
3576 "foreignSecurityPrincipal") != NULL) {
3577 return samldb_fill_foreignSecurityPrincipal_object(ac);
3580 if (samdb_find_attribute(ldb, ac->msg,
3581 "objectclass", "classSchema") != NULL) {
3582 ac->type = SAMLDB_TYPE_CLASS;
3584 /* If in provision, these checks are too slow to do */
3585 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3586 ret = samldb_schema_governsid_valid_check(ac);
3587 if (ret != LDB_SUCCESS) {
3592 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3593 if (ret != LDB_SUCCESS) {
3597 ret = samldb_schema_info_update(ac);
3598 if (ret != LDB_SUCCESS) {
3603 return samldb_fill_object(ac);
3606 if (samdb_find_attribute(ldb, ac->msg,
3607 "objectclass", "attributeSchema") != NULL) {
3608 ac->type = SAMLDB_TYPE_ATTRIBUTE;
3610 /* If in provision, these checks are too slow to do */
3611 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3612 ret = samldb_schema_attributeid_valid_check(ac);
3613 if (ret != LDB_SUCCESS) {
3617 ret = samldb_schema_add_handle_linkid(ac);
3618 if (ret != LDB_SUCCESS) {
3622 ret = samldb_schema_add_handle_mapiid(ac);
3623 if (ret != LDB_SUCCESS) {
3628 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3629 if (ret != LDB_SUCCESS) {
3633 ret = samldb_schema_info_update(ac);
3634 if (ret != LDB_SUCCESS) {
3639 return samldb_fill_object(ac);
3642 if (samdb_find_attribute(ldb, ac->msg,
3643 "objectclass", "subnet") != NULL) {
3644 ret = samldb_verify_subnet(ac, ac->msg->dn);
3645 if (ret != LDB_SUCCESS) {
3649 /* We are just checking the value is valid, and there are no
3650 values to fill in. */
3655 /* nothing matched, go on */
3656 return ldb_next_request(module, req);
3660 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
3662 struct ldb_context *ldb;
3663 struct samldb_ctx *ac;
3664 struct ldb_message_element *el, *el2;
3665 struct ldb_control *is_undelete;
3666 bool modified = false;
3669 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3670 /* do not manipulate our control entries */
3671 return ldb_next_request(module, req);
3674 ldb = ldb_module_get_ctx(module);
3677 * we are going to need some special handling if in Undelete call.
3678 * Since tombstone_reanimate module will restore certain attributes,
3679 * we need to relax checks for: sAMAccountType, primaryGroupID
3681 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3683 /* make sure that "objectSid" is not specified */
3684 el = ldb_msg_find_element(req->op.mod.message, "objectSid");
3686 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
3687 ldb_set_errstring(ldb,
3688 "samldb: objectSid must not be specified!");
3689 return LDB_ERR_UNWILLING_TO_PERFORM;
3692 if (is_undelete == NULL) {
3693 /* make sure that "sAMAccountType" is not specified */
3694 el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
3696 ldb_set_errstring(ldb,
3697 "samldb: sAMAccountType must not be specified!");
3698 return LDB_ERR_UNWILLING_TO_PERFORM;
3701 /* make sure that "isCriticalSystemObject" is not specified */
3702 el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
3704 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
3705 ldb_set_errstring(ldb,
3706 "samldb: isCriticalSystemObject must not be specified!");
3707 return LDB_ERR_UNWILLING_TO_PERFORM;
3711 /* msDS-IntId is not allowed to be modified
3712 * except when modification comes from replication */
3713 if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
3714 if (!ldb_request_get_control(req,
3715 DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
3716 return LDB_ERR_CONSTRAINT_VIOLATION;
3720 el = ldb_msg_find_element(req->op.mod.message, "userParameters");
3721 if (el != NULL && ldb_req_is_untrusted(req)) {
3722 const char *reason = "samldb: "
3723 "setting userParameters is not supported over LDAP, "
3724 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3725 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3726 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3729 ac = samldb_ctx_init(module, req);
3731 return ldb_operr(ldb);
3734 /* build the new msg */
3735 ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3736 if (ac->msg == NULL) {
3738 ldb_debug(ldb, LDB_DEBUG_FATAL,
3739 "samldb_modify: ldb_msg_copy_shallow failed!\n");
3740 return ldb_operr(ldb);
3743 if (is_undelete == NULL) {
3744 el = ldb_msg_find_element(ac->msg, "primaryGroupID");
3746 ret = samldb_prim_group_trigger(ac);
3747 if (ret != LDB_SUCCESS) {
3753 el = ldb_msg_find_element(ac->msg, "userAccountControl");
3756 ret = samldb_user_account_control_change(ac);
3757 if (ret != LDB_SUCCESS) {
3762 el = ldb_msg_find_element(ac->msg, "pwdLastSet");
3765 ret = samldb_pwd_last_set_change(ac);
3766 if (ret != LDB_SUCCESS) {
3771 el = ldb_msg_find_element(ac->msg, "lockoutTime");
3774 ret = samldb_lockout_time(ac);
3775 if (ret != LDB_SUCCESS) {
3780 el = ldb_msg_find_element(ac->msg, "groupType");
3783 ret = samldb_group_type_change(ac);
3784 if (ret != LDB_SUCCESS) {
3789 el = ldb_msg_find_element(ac->msg, "sAMAccountName");
3791 ret = samldb_sam_accountname_valid_check(ac);
3793 * Other errors are checked for elsewhere, we just
3794 * want to prevent duplicates
3796 if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
3801 el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
3803 ret = samldb_schema_ldapdisplayname_valid_check(ac);
3804 if (ret != LDB_SUCCESS) {
3809 el = ldb_msg_find_element(ac->msg, "attributeID");
3811 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3812 "Once set, attributeID values may not be modified");
3813 return LDB_ERR_CONSTRAINT_VIOLATION;
3816 el = ldb_msg_find_element(ac->msg, "governsID");
3818 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3819 "Once set, governsID values may not be modified");
3820 return LDB_ERR_CONSTRAINT_VIOLATION;
3823 el = ldb_msg_find_element(ac->msg, "member");
3825 struct ldb_control *fix_link_sid_ctrl = NULL;
3827 fix_link_sid_ctrl = ldb_request_get_control(ac->req,
3828 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
3829 if (fix_link_sid_ctrl == NULL) {
3830 ret = samldb_member_check(ac);
3831 if (ret != LDB_SUCCESS) {
3837 el = ldb_msg_find_element(ac->msg, "description");
3839 ret = samldb_description_check(ac, &modified);
3840 if (ret != LDB_SUCCESS) {
3845 el = ldb_msg_find_element(ac->msg, "dNSHostName");
3846 el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
3847 if ((el != NULL) || (el2 != NULL)) {
3849 ret = samldb_service_principal_names_change(ac);
3850 if (ret != LDB_SUCCESS) {
3855 el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3857 ret = samldb_fsmo_role_owner_check(ac);
3858 if (ret != LDB_SUCCESS) {
3864 struct ldb_request *child_req;
3866 /* Now perform the real modifications as a child request */
3867 ret = ldb_build_mod_req(&child_req, ldb, ac,
3870 req, dsdb_next_callback,
3872 LDB_REQ_SET_LOCATION(child_req);
3873 if (ret != LDB_SUCCESS) {
3877 return ldb_next_request(module, child_req);
3882 /* no change which interests us, go on */
3883 return ldb_next_request(module, req);
3888 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
3890 struct ldb_context *ldb;
3891 struct dom_sid *sid;
3895 struct ldb_result *res = NULL;
3896 struct ldb_result *res_users = NULL;
3897 const char * const attrs[] = { "objectSid", "isDeleted", NULL };
3898 const char * const noattrs[] = { NULL };
3900 ldb = ldb_module_get_ctx(ac->module);
3902 /* Finds out the SID/RID of the SAM object */
3903 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
3905 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3907 if (ret != LDB_SUCCESS) {
3911 if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
3915 sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
3917 /* No SID - it might not be a SAM object - therefore ok */
3920 status = dom_sid_split_rid(ac, sid, NULL, &rid);
3921 if (!NT_STATUS_IS_OK(status)) {
3922 return ldb_operr(ldb);
3925 /* Special object (security principal?) */
3928 /* do not allow deletion of well-known sids */
3929 if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
3930 (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
3931 return LDB_ERR_OTHER;
3934 /* Deny delete requests from groups which are primary ones */
3935 ret = dsdb_module_search(ac->module, ac, &res_users,
3936 ldb_get_default_basedn(ldb),
3937 LDB_SCOPE_SUBTREE, noattrs,
3938 DSDB_FLAG_NEXT_MODULE,
3940 "(&(primaryGroupID=%u)(objectClass=user))", rid);
3941 if (ret != LDB_SUCCESS) {
3944 if (res_users->count > 0) {
3945 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3946 "Refusing to delete %s, as it "
3947 "is still the primaryGroupID "
3949 ldb_dn_get_linearized(res->msgs[0]->dn),
3953 * Yes, this seems very wrong, but we have a test
3954 * for this exact error code in sam.py
3956 return LDB_ERR_ENTRY_ALREADY_EXISTS;
3962 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
3964 struct samldb_ctx *ac;
3965 char *referral = NULL;
3967 struct ldb_context *ldb;
3969 if (ldb_dn_is_special(req->op.del.dn)) {
3970 /* do not manipulate our control entries */
3971 return ldb_next_request(module, req);
3974 ldb = ldb_module_get_ctx(module);
3976 referral = refer_if_rodc(ldb, req, req->op.del.dn);
3977 if (referral != NULL) {
3978 ret = ldb_module_send_referral(req, referral);
3982 ac = samldb_ctx_init(module, req);
3984 return ldb_operr(ldb_module_get_ctx(module));
3987 ret = samldb_prim_group_users_check(ac);
3988 if (ret != LDB_SUCCESS) {
3994 return ldb_next_request(module, req);
3999 static int check_rename_constraints(struct ldb_message *msg,
4000 struct samldb_ctx *ac,
4001 struct ldb_dn *olddn, struct ldb_dn *newdn)
4003 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4004 struct ldb_dn *dn1, *dn2, *nc_root;
4005 int32_t systemFlags;
4006 bool move_op = false;
4007 bool rename_op = false;
4010 /* Skip the checks if old and new DN are the same, or if we have the
4011 * relax control specified or if the returned objects is already
4012 * deleted and needs only to be moved for consistency. */
4014 if (ldb_dn_compare(olddn, newdn) == 0) {
4017 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
4021 if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
4023 * check originating request if we are supposed
4024 * to "see" this record in first place.
4026 if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
4027 return LDB_ERR_NO_SUCH_OBJECT;
4029 return LDB_ERR_UNWILLING_TO_PERFORM;
4032 /* Objects under CN=System */
4034 dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
4035 if (dn1 == NULL) return ldb_oom(ldb);
4037 if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
4039 return LDB_ERR_OPERATIONS_ERROR;
4042 if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
4043 (ldb_dn_compare_base(dn1, newdn) != 0)) {
4045 ldb_asprintf_errstring(ldb,
4046 "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
4047 ldb_dn_get_linearized(olddn));
4048 return LDB_ERR_OTHER;
4055 if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
4056 (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
4057 ldb_asprintf_errstring(ldb,
4058 "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
4059 ldb_dn_get_linearized(olddn));
4060 return LDB_ERR_UNWILLING_TO_PERFORM;
4063 /* subnet objects */
4064 if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
4065 ret = samldb_verify_subnet(ac, newdn);
4066 if (ret != LDB_SUCCESS) {
4074 dn1 = ldb_dn_get_parent(ac, olddn);
4075 if (dn1 == NULL) return ldb_oom(ldb);
4076 dn2 = ldb_dn_get_parent(ac, newdn);
4077 if (dn2 == NULL) return ldb_oom(ldb);
4079 if (ldb_dn_compare(dn1, dn2) == 0) {
4088 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
4090 /* Fetch name context */
4092 ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
4093 if (ret != LDB_SUCCESS) {
4097 if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
4099 ldb_asprintf_errstring(ldb,
4100 "subtree_rename: Cannot move %s within schema partition",
4101 ldb_dn_get_linearized(olddn));
4102 return LDB_ERR_UNWILLING_TO_PERFORM;
4105 (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
4106 ldb_asprintf_errstring(ldb,
4107 "subtree_rename: Cannot rename %s within schema partition",
4108 ldb_dn_get_linearized(olddn));
4109 return LDB_ERR_UNWILLING_TO_PERFORM;
4111 } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
4113 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
4114 /* Here we have to do more: control the
4115 * "ALLOW_LIMITED_MOVE" flag. This means that the
4116 * grand-grand-parents of two objects have to be equal
4117 * in order to perform the move (this is used for
4118 * moving "server" objects in the "sites" container). */
4120 systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
4123 dn1 = ldb_dn_copy(ac, olddn);
4124 if (dn1 == NULL) return ldb_oom(ldb);
4125 dn2 = ldb_dn_copy(ac, newdn);
4126 if (dn2 == NULL) return ldb_oom(ldb);
4128 limited_move &= ldb_dn_remove_child_components(dn1, 3);
4129 limited_move &= ldb_dn_remove_child_components(dn2, 3);
4130 limited_move &= ldb_dn_compare(dn1, dn2) == 0;
4137 && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
4138 ldb_asprintf_errstring(ldb,
4139 "subtree_rename: Cannot move %s to %s in config partition",
4140 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4141 return LDB_ERR_UNWILLING_TO_PERFORM;
4145 (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
4146 ldb_asprintf_errstring(ldb,
4147 "subtree_rename: Cannot rename %s to %s within config partition",
4148 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4149 return LDB_ERR_UNWILLING_TO_PERFORM;
4151 } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
4153 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
4154 ldb_asprintf_errstring(ldb,
4155 "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
4156 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4157 return LDB_ERR_UNWILLING_TO_PERFORM;
4160 (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
4161 ldb_asprintf_errstring(ldb,
4162 "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
4163 ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4164 return LDB_ERR_UNWILLING_TO_PERFORM;
4168 talloc_free(nc_root);
4174 static int samldb_rename_search_base_callback(struct ldb_request *req,
4175 struct ldb_reply *ares)
4177 struct samldb_ctx *ac;
4180 ac = talloc_get_type(req->context, struct samldb_ctx);
4183 return ldb_module_done(ac->req, NULL, NULL,
4184 LDB_ERR_OPERATIONS_ERROR);
4186 if (ares->error != LDB_SUCCESS) {
4187 return ldb_module_done(ac->req, ares->controls,
4188 ares->response, ares->error);
4191 switch (ares->type) {
4192 case LDB_REPLY_ENTRY:
4194 * This is the root entry of the originating move
4195 * respectively rename request. It has been already
4196 * stored in the list using "subtree_rename_search()".
4197 * Only this one is subject to constraint checking.
4199 ret = check_rename_constraints(ares->message, ac,
4200 ac->req->op.rename.olddn,
4201 ac->req->op.rename.newdn);
4202 if (ret != LDB_SUCCESS) {
4203 return ldb_module_done(ac->req, NULL, NULL,
4208 case LDB_REPLY_REFERRAL:
4212 case LDB_REPLY_DONE:
4215 * Great, no problem with the rename, so go ahead as
4216 * if we never were here
4218 ret = ldb_next_request(ac->module, ac->req);
4229 static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
4231 struct ldb_context *ldb;
4232 static const char * const attrs[] = { "objectClass", "systemFlags",
4233 "isDeleted", NULL };
4234 struct ldb_request *search_req;
4235 struct samldb_ctx *ac;
4238 if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
4239 return ldb_next_request(module, req);
4242 ldb = ldb_module_get_ctx(module);
4244 ac = samldb_ctx_init(module, req);
4246 return ldb_oom(ldb);
4249 ret = ldb_build_search_req(&search_req, ldb, ac,
4250 req->op.rename.olddn,
4256 samldb_rename_search_base_callback,
4258 LDB_REQ_SET_LOCATION(search_req);
4259 if (ret != LDB_SUCCESS) {
4263 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4265 if (ret != LDB_SUCCESS) {
4269 return ldb_next_request(ac->module, search_req);
4274 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
4276 struct ldb_context *ldb = ldb_module_get_ctx(module);
4277 struct dsdb_fsmo_extended_op *exop;
4280 exop = talloc_get_type(req->op.extended.data,
4281 struct dsdb_fsmo_extended_op);
4283 ldb_set_errstring(ldb,
4284 "samldb_extended_allocate_rid_pool: invalid extended data");
4285 return LDB_ERR_PROTOCOL_ERROR;
4288 ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
4289 if (ret != LDB_SUCCESS) {
4293 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4296 static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
4298 struct ldb_context *ldb = ldb_module_get_ctx(module);
4299 struct dsdb_extended_allocate_rid *exop;
4302 exop = talloc_get_type(req->op.extended.data,
4303 struct dsdb_extended_allocate_rid);
4305 ldb_set_errstring(ldb,
4306 "samldb_extended_allocate_rid: invalid extended data");
4307 return LDB_ERR_PROTOCOL_ERROR;
4310 ret = ridalloc_allocate_rid(module, &exop->rid, req);
4311 if (ret != LDB_SUCCESS) {
4315 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4318 static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
4320 struct ldb_context *ldb = ldb_module_get_ctx(module);
4324 if (req->op.extended.data != NULL) {
4325 ldb_set_errstring(ldb,
4326 "samldb_extended_allocate_rid_pool_for_us: invalid extended data (should be NULL)");
4327 return LDB_ERR_PROTOCOL_ERROR;
4330 ret = ridalloc_create_own_rid_set(module, req,
4332 if (ret != LDB_SUCCESS) {
4336 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4339 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
4341 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
4342 return samldb_extended_allocate_rid_pool(module, req);
4345 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
4346 return samldb_extended_allocate_rid(module, req);
4349 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
4350 return samldb_extended_create_own_rid_set(module, req);
4353 return ldb_next_request(module, req);
4357 static const struct ldb_module_ops ldb_samldb_module_ops = {
4360 .modify = samldb_modify,
4361 .del = samldb_delete,
4362 .rename = samldb_rename,
4363 .extended = samldb_extended
4367 int ldb_samldb_module_init(const char *version)
4369 LDB_MODULE_CHECK_VERSION(version);
4370 return ldb_register_module(&ldb_samldb_module_ops);