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
36 #include "ldb_errors.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "ldb_module.h"
39 #include "auth/auth.h"
40 #include "dsdb/gmsa/util.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "dsdb/samdb/ldb_modules/util.h"
43 #include "dsdb/samdb/ldb_modules/ridalloc.h"
44 #include "libcli/security/security.h"
45 #include "librpc/gen_ndr/security.h"
46 #include "librpc/gen_ndr/ndr_security.h"
48 #include "param/param.h"
49 #include "libds/common/flag_mapping.h"
50 #include "system/network.h"
51 #include "librpc/gen_ndr/irpc.h"
52 #include "lib/crypto/gmsa.h"
53 #include "lib/util/data_blob.h"
54 #include "lib/util/smb_strtox.h"
55 #include "lib/util/time.h"
60 enum samldb_add_type
{
67 typedef int (*samldb_step_fn_t
)(struct samldb_ctx
*);
70 struct samldb_step
*next
;
75 struct ldb_module
*module
;
76 struct ldb_request
*req
;
78 /* used for add operations */
79 enum samldb_add_type type
;
82 * should we apply the need_trailing_dollar restriction to
86 bool need_trailing_dollar
;
88 /* the resulting message */
89 struct ldb_message
*msg
;
91 /* used in "samldb_find_for_defaultObjectCategory" */
92 struct ldb_dn
*dn
, *res_dn
;
94 /* the SID to be assigned to the resulting account */
95 const struct dom_sid
*sid
;
97 /* all the async steps necessary to complete the operation */
98 struct samldb_step
*steps
;
99 struct samldb_step
*curstep
;
101 /* If someone set an ares to forward controls and response back to the caller */
102 struct ldb_reply
*ares
;
105 static struct samldb_ctx
*samldb_ctx_init(struct ldb_module
*module
,
106 struct ldb_request
*req
)
108 struct ldb_context
*ldb
;
109 struct samldb_ctx
*ac
;
111 ldb
= ldb_module_get_ctx(module
);
113 ac
= talloc_zero(req
, struct samldb_ctx
);
125 static int samldb_add_step(struct samldb_ctx
*ac
, samldb_step_fn_t fn
)
127 struct samldb_step
*step
, *stepper
;
129 step
= talloc_zero(ac
, struct samldb_step
);
131 return ldb_oom(ldb_module_get_ctx(ac
->module
));
136 if (ac
->steps
== NULL
) {
140 if (ac
->curstep
== NULL
)
141 return ldb_operr(ldb_module_get_ctx(ac
->module
));
142 for (stepper
= ac
->curstep
; stepper
->next
!= NULL
;
143 stepper
= stepper
->next
);
144 stepper
->next
= step
;
150 static int samldb_first_step(struct samldb_ctx
*ac
)
152 if (ac
->steps
== NULL
) {
153 return ldb_operr(ldb_module_get_ctx(ac
->module
));
156 ac
->curstep
= ac
->steps
;
157 return ac
->curstep
->fn(ac
);
160 static int samldb_next_step(struct samldb_ctx
*ac
)
162 if (ac
->curstep
->next
) {
163 ac
->curstep
= ac
->curstep
->next
;
164 return ac
->curstep
->fn(ac
);
167 /* We exit the samldb module here. If someone set an "ares" to forward
168 * controls and response back to the caller, use them. */
170 return ldb_module_done(ac
->req
, ac
->ares
->controls
,
171 ac
->ares
->response
, LDB_SUCCESS
);
173 return ldb_module_done(ac
->req
, NULL
, NULL
, LDB_SUCCESS
);
177 static int samldb_get_single_valued_attr(struct ldb_context
*ldb
,
178 struct samldb_ctx
*ac
,
183 * The steps we end up going through to get and check a single valued
186 struct ldb_message_element
*el
= NULL
;
191 ret
= dsdb_get_expected_new_values(ac
,
197 if (ret
!= LDB_SUCCESS
) {
201 /* we are not affected */
205 if (el
->num_values
> 1) {
206 ldb_asprintf_errstring(
208 "samldb: %s has %u values, should be single-valued!",
209 attr
, el
->num_values
);
210 return LDB_ERR_CONSTRAINT_VIOLATION
;
211 } else if (el
->num_values
== 0) {
212 ldb_asprintf_errstring(
214 "samldb: new value for %s "
215 "not provided for mandatory, single-valued attribute!",
217 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
221 if (el
->values
[0].length
== 0) {
222 ldb_asprintf_errstring(
224 "samldb: %s is of zero length, should have a value!",
226 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
229 *value
= (char *)el
->values
[0].data
;
234 static int samldb_unique_attr_check(struct samldb_ctx
*ac
, const char *attr
,
235 const char *attr_conflict
,
236 struct ldb_dn
*base_dn
)
238 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
239 const char * const no_attrs
[] = { NULL
};
240 struct ldb_result
*res
= NULL
;
241 const char *str
= NULL
;
242 const char *enc_str
= NULL
;
245 ret
= samldb_get_single_valued_attr(ldb
, ac
, attr
, &str
);
246 if (ret
!= LDB_SUCCESS
) {
250 /* the attribute wasn't found */
254 enc_str
= ldb_binary_encode_string(ac
, str
);
255 if (enc_str
== NULL
) {
256 return ldb_module_oom(ac
->module
);
260 * No other object should have the attribute with this value.
262 if (attr_conflict
!= NULL
) {
263 ret
= dsdb_module_search(ac
->module
, ac
, &res
,
265 LDB_SCOPE_SUBTREE
, no_attrs
,
266 DSDB_FLAG_NEXT_MODULE
, ac
->req
,
269 attr_conflict
, enc_str
);
271 ret
= dsdb_module_search(ac
->module
, ac
, &res
,
273 LDB_SCOPE_SUBTREE
, no_attrs
,
274 DSDB_FLAG_NEXT_MODULE
, ac
->req
,
275 "(%s=%s)", attr
, enc_str
);
277 if (ret
!= LDB_SUCCESS
) {
280 if (res
->count
> 1) {
281 return ldb_operr(ldb
);
282 } else if (res
->count
== 1) {
283 if (ldb_dn_compare(res
->msgs
[0]->dn
, ac
->msg
->dn
) != 0) {
284 ldb_asprintf_errstring(ldb
,
285 "samldb: %s '%s' already in use!",
287 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
297 static inline int samldb_sam_account_upn_clash_sub_search(
298 struct samldb_ctx
*ac
,
300 struct ldb_dn
*base_dn
,
307 * A very specific helper function for samldb_sam_account_upn_clash(),
308 * where we end up doing this same thing several times in a row.
310 const char * const no_attrs
[] = { NULL
};
311 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
312 struct ldb_result
*res
= NULL
;
314 char *enc_value
= ldb_binary_encode_string(ac
, value
);
315 if (enc_value
== NULL
) {
316 return ldb_module_oom(ac
->module
);
318 ret
= dsdb_module_search(ac
->module
, mem_ctx
, &res
,
320 LDB_SCOPE_SUBTREE
, no_attrs
,
321 DSDB_FLAG_NEXT_MODULE
, ac
->req
,
324 talloc_free(enc_value
);
326 if (ret
!= LDB_SUCCESS
) {
328 } else if (res
->count
> 1) {
329 return ldb_operr(ldb
);
330 } else if (res
->count
== 1) {
331 if (ldb_dn_compare(res
->msgs
[0]->dn
, ac
->msg
->dn
) != 0){
332 ldb_asprintf_errstring(ldb
,
334 "is already in use %s",
335 attr
, value
, err_msg
);
336 /* different errors for different attrs */
337 if (strcasecmp("userPrincipalName", attr
) == 0) {
338 return LDB_ERR_CONSTRAINT_VIOLATION
;
340 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
346 static int samaccountname_bad_chars_check(struct samldb_ctx
*ac
,
350 * The rules here are based on
352 * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
354 * Windows considers UTF-8 sequences that map to "similar" characters
355 * (e.g. 'a', 'ā') to be the same sAMAccountName, and we don't. Names
356 * that are not valid UTF-8 *are* allowed.
358 * Additionally, Samba collapses multiple spaces, and Windows doesn't.
360 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
363 for (i
= 0; name
[i
] != '\0'; i
++) {
366 if (c
< 32 || c
== 127) {
367 ldb_asprintf_errstring(
369 "samldb: sAMAccountName contains invalid "
370 "0x%.2x character\n", c
);
371 return LDB_ERR_CONSTRAINT_VIOLATION
;
373 p
= strchr("\"[]:;|=+*?<>/\\,", c
);
375 ldb_asprintf_errstring(
377 "samldb: sAMAccountName contains invalid "
378 "'%c' character\n", c
);
379 return LDB_ERR_CONSTRAINT_VIOLATION
;
384 ldb_asprintf_errstring(
386 "samldb: sAMAccountName is empty\n");
387 return LDB_ERR_CONSTRAINT_VIOLATION
;
390 if (name
[i
- 1] == '.') {
391 ldb_asprintf_errstring(
393 "samldb: sAMAccountName ends with '.'");
394 return LDB_ERR_CONSTRAINT_VIOLATION
;
399 static int samldb_sam_account_upn_clash(struct samldb_ctx
*ac
)
401 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
403 struct ldb_dn
*base_dn
= ldb_get_default_basedn(ldb
);
404 TALLOC_CTX
*tmp_ctx
= NULL
;
405 const char *real_sam
= NULL
;
406 const char *real_upn
= NULL
;
407 char *implied_sam
= NULL
;
408 char *implied_upn
= NULL
;
409 const char *realm
= NULL
;
411 ret
= samldb_get_single_valued_attr(ldb
, ac
,
414 if (ret
!= LDB_SUCCESS
) {
417 ret
= samldb_get_single_valued_attr(ldb
, ac
,
420 if (ret
!= LDB_SUCCESS
) {
423 if (real_upn
== NULL
&& real_sam
== NULL
) {
424 /* Not changing these things, so we're done */
428 tmp_ctx
= talloc_new(ac
);
429 realm
= samdb_dn_to_dns_domain(tmp_ctx
, base_dn
);
431 talloc_free(tmp_ctx
);
432 return ldb_operr(ldb
);
435 if (real_upn
!= NULL
) {
437 * note we take the last @ in the upn because the first (i.e.
438 * sAMAccountName equivalent) part can contain @.
440 * It is also OK (per Windows) for a UPN to have zero @s.
443 char *upn_realm
= NULL
;
444 implied_sam
= talloc_strdup(tmp_ctx
, real_upn
);
445 if (implied_sam
== NULL
) {
446 talloc_free(tmp_ctx
);
447 return ldb_module_oom(ac
->module
);
450 at
= strrchr(implied_sam
, '@');
453 * there is no @ in this UPN, so we treat the whole
454 * thing as a sAMAccountName for the purposes of a
457 DBG_INFO("samldb: userPrincipalName '%s' contains "
458 "no '@' character\n", implied_sam
);
461 * Now, this upn only implies a sAMAccountName if the
462 * realm is our realm. So we need to compare the tail
463 * of the upn to the realm.
467 if (strcasecmp(upn_realm
, realm
) != 0) {
468 /* implied_sam is not the implied
469 * sAMAccountName after all, because it is
470 * from a different realm. */
471 TALLOC_FREE(implied_sam
);
476 if (real_sam
!= NULL
) {
477 implied_upn
= talloc_asprintf(tmp_ctx
, "%s@%s",
479 if (implied_upn
== NULL
) {
480 talloc_free(tmp_ctx
);
481 return ldb_module_oom(ac
->module
);
486 * Now we have all of the actual and implied names, in which to search
489 if (real_sam
!= NULL
) {
490 ret
= samldb_sam_account_upn_clash_sub_search(
491 ac
, tmp_ctx
, base_dn
, "sAMAccountName",
494 if (ret
!= LDB_SUCCESS
) {
495 talloc_free(tmp_ctx
);
498 ret
= samaccountname_bad_chars_check(ac
, real_sam
);
499 if (ret
!= LDB_SUCCESS
) {
500 talloc_free(tmp_ctx
);
504 if (implied_upn
!= NULL
) {
505 ret
= samldb_sam_account_upn_clash_sub_search(
506 ac
, tmp_ctx
, base_dn
, "userPrincipalName", implied_upn
,
507 "(implied by sAMAccountName)");
509 if (ret
!= LDB_SUCCESS
) {
510 talloc_free(tmp_ctx
);
514 if (real_upn
!= NULL
) {
515 ret
= samldb_sam_account_upn_clash_sub_search(
516 ac
, tmp_ctx
, base_dn
, "userPrincipalName",
519 if (ret
!= LDB_SUCCESS
) {
520 talloc_free(tmp_ctx
);
524 if (implied_sam
!= NULL
) {
525 ret
= samldb_sam_account_upn_clash_sub_search(
526 ac
, tmp_ctx
, base_dn
, "sAMAccountName", implied_sam
,
527 "(implied by userPrincipalName)");
528 if (ret
!= LDB_SUCCESS
) {
529 talloc_free(tmp_ctx
);
534 talloc_free(tmp_ctx
);
539 /* This is run during an add or modify */
540 static int samldb_sam_accountname_valid_check(struct samldb_ctx
*ac
)
544 struct security_token
*user_token
= NULL
;
545 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
546 struct ldb_message_element
*el
= NULL
;
548 ret
= dsdb_get_expected_new_values(ac
,
553 if (ret
!= LDB_SUCCESS
) {
557 if (el
== NULL
|| el
->num_values
== 0) {
558 ldb_asprintf_errstring(ldb
,
559 "%08X: samldb: 'samAccountName' can't be deleted/empty!",
560 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
561 if (ac
->req
->operation
== LDB_ADD
) {
562 return LDB_ERR_CONSTRAINT_VIOLATION
;
564 return LDB_ERR_UNWILLING_TO_PERFORM
;
568 ret
= samldb_unique_attr_check(ac
, "samAccountName", NULL
,
569 ldb_get_default_basedn(
570 ldb_module_get_ctx(ac
->module
)));
573 * Error code munging to try and match what must be some quite
574 * strange code-paths in Windows
576 if (ret
== LDB_ERR_CONSTRAINT_VIOLATION
577 && ac
->req
->operation
== LDB_MODIFY
) {
578 ret
= LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
579 } else if (ret
== LDB_ERR_OBJECT_CLASS_VIOLATION
) {
580 ret
= LDB_ERR_CONSTRAINT_VIOLATION
;
582 if (ret
!= LDB_SUCCESS
) {
586 ret
= samldb_sam_account_upn_clash(ac
);
587 if (ret
!= LDB_SUCCESS
) {
591 if (!ac
->need_trailing_dollar
) {
595 /* This does not permit a single $ */
596 if (el
->values
[0].length
< 2) {
597 ldb_asprintf_errstring(ldb
,
598 "%08X: samldb: 'samAccountName' "
599 "can't just be one character!",
600 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
601 return LDB_ERR_UNWILLING_TO_PERFORM
;
604 user_token
= acl_user_token(ac
->module
);
605 if (user_token
== NULL
) {
606 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
610 = security_token_has_builtin_administrators(user_token
);
614 * Administrators are allowed to select strange names.
615 * This is poor practice but not prevented.
620 if (el
->values
[0].data
[el
->values
[0].length
- 1] != '$') {
621 ldb_asprintf_errstring(ldb
,
622 "%08X: samldb: 'samAccountName' "
623 "must have a trailing $!",
624 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
625 return LDB_ERR_UNWILLING_TO_PERFORM
;
627 if (el
->values
[0].data
[el
->values
[0].length
- 2] == '$') {
628 ldb_asprintf_errstring(ldb
,
629 "%08X: samldb: 'samAccountName' "
630 "must not have a double trailing $!",
631 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
632 return LDB_ERR_UNWILLING_TO_PERFORM
;
638 static int samldb_schema_attributeid_valid_check(struct samldb_ctx
*ac
)
640 int ret
= samldb_unique_attr_check(ac
, "attributeID", "governsID",
641 ldb_get_schema_basedn(
642 ldb_module_get_ctx(ac
->module
)));
643 if (ret
== LDB_ERR_ENTRY_ALREADY_EXISTS
) {
644 ret
= LDB_ERR_UNWILLING_TO_PERFORM
;
649 static int samldb_schema_governsid_valid_check(struct samldb_ctx
*ac
)
651 int ret
= samldb_unique_attr_check(ac
, "governsID", "attributeID",
652 ldb_get_schema_basedn(
653 ldb_module_get_ctx(ac
->module
)));
654 if (ret
== LDB_ERR_ENTRY_ALREADY_EXISTS
) {
655 ret
= LDB_ERR_UNWILLING_TO_PERFORM
;
660 static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx
*ac
)
662 int ret
= samldb_unique_attr_check(ac
, "lDAPDisplayName", NULL
,
663 ldb_get_schema_basedn(
664 ldb_module_get_ctx(ac
->module
)));
665 if (ret
== LDB_ERR_ENTRY_ALREADY_EXISTS
) {
666 ret
= LDB_ERR_UNWILLING_TO_PERFORM
;
671 static int samldb_check_linkid_used(struct samldb_ctx
*ac
,
672 struct dsdb_schema
*schema
,
673 struct ldb_dn
*schema_dn
,
674 struct ldb_context
*ldb
,
679 struct ldb_result
*ldb_res
;
681 if (dsdb_attribute_by_linkID(schema
, linkID
)) {
686 ret
= dsdb_module_search(ac
->module
, ac
,
688 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
689 DSDB_FLAG_NEXT_MODULE
,
691 "(linkID=%d)", linkID
);
692 if (ret
!= LDB_SUCCESS
) {
693 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
694 __location__
": Searching for linkID=%d failed - %s\n",
697 return ldb_operr(ldb
);
700 *found
= (ldb_res
->count
!= 0);
701 talloc_free(ldb_res
);
706 /* Find the next open forward linkID in the schema. */
707 static int samldb_generate_next_linkid(struct samldb_ctx
*ac
,
708 struct dsdb_schema
*schema
,
709 int32_t *next_linkID
)
712 struct ldb_context
*ldb
;
713 struct ldb_dn
*schema_dn
;
714 bool linkID_used
= true;
717 * Windows starts at about 0xB0000000 in order to stop potential
718 * collisions with future additions to the schema. We pass this
719 * around as a signed int sometimes, but this should be sufficient.
721 *next_linkID
= 0x40000000;
723 ldb
= ldb_module_get_ctx(ac
->module
);
724 schema_dn
= ldb_get_schema_basedn(ldb
);
726 while (linkID_used
) {
728 ret
= samldb_check_linkid_used(ac
, schema
,
730 *next_linkID
, &linkID_used
);
731 if (ret
!= LDB_SUCCESS
) {
739 static int samldb_schema_add_handle_linkid(struct samldb_ctx
*ac
)
742 bool ok
, found
= false;
743 struct ldb_message_element
*el
;
745 const struct dsdb_attribute
*attr
;
746 struct ldb_context
*ldb
;
747 struct ldb_dn
*schema_dn
;
748 struct dsdb_schema
*schema
;
749 int32_t new_linkID
= 0;
751 ldb
= ldb_module_get_ctx(ac
->module
);
752 schema
= dsdb_get_schema(ldb
, ac
);
753 schema_dn
= ldb_get_schema_basedn(ldb
);
755 ret
= dsdb_get_expected_new_values(ac
,
760 if (ret
!= LDB_SUCCESS
) {
764 if (el
== NULL
|| el
->num_values
== 0) {
768 enc_str
= ldb_binary_encode(ac
, el
->values
[0]);
769 if (enc_str
== NULL
) {
770 return ldb_module_oom(ac
->module
);
773 ok
= (strcmp(enc_str
, "0") == 0);
779 * This OID indicates that the caller wants the linkID
780 * to be automatically generated. We therefore assign
781 * it the next open linkID.
783 ok
= (strcmp(enc_str
, "1.2.840.113556.1.2.50") == 0);
785 ret
= samldb_generate_next_linkid(ac
, schema
, &new_linkID
);
786 if (ret
!= LDB_SUCCESS
) {
790 ldb_msg_remove_element(ac
->msg
, el
);
791 ret
= samdb_msg_add_int(ldb
, ac
->msg
, ac
->msg
, "linkID",
797 * Using either the attributeID or lDAPDisplayName of
798 * another attribute in the linkID field indicates that
799 * we should make this the backlink of that attribute.
801 attr
= dsdb_attribute_by_attributeID_oid(schema
, enc_str
);
803 attr
= dsdb_attribute_by_lDAPDisplayName(schema
, enc_str
);
808 * The attribute we're adding this as a backlink of must
811 if (attr
->linkID
% 2 != 0) {
812 return LDB_ERR_UNWILLING_TO_PERFORM
;
815 new_linkID
= attr
->linkID
+ 1;
817 /* Make sure that this backlink doesn't already exist. */
818 ret
= samldb_check_linkid_used(ac
, schema
,
821 if (ret
!= LDB_SUCCESS
) {
826 return LDB_ERR_UNWILLING_TO_PERFORM
;
829 ldb_msg_remove_element(ac
->msg
, el
);
830 ret
= samdb_msg_add_int(ldb
, ac
->msg
, ac
->msg
, "linkID",
835 schema_dn
= ldb_get_schema_basedn(ldb_module_get_ctx(ac
->module
));
836 ret
= samldb_unique_attr_check(ac
, "linkID", NULL
, schema_dn
);
837 if (ret
== LDB_ERR_ENTRY_ALREADY_EXISTS
) {
838 return LDB_ERR_UNWILLING_TO_PERFORM
;
844 static int samldb_check_mapiid_used(struct samldb_ctx
*ac
,
845 struct dsdb_schema
*schema
,
846 struct ldb_dn
*schema_dn
,
847 struct ldb_context
*ldb
,
852 struct ldb_result
*ldb_res
;
854 ret
= dsdb_module_search(ac
->module
, ac
,
856 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
857 DSDB_FLAG_NEXT_MODULE
,
859 "(mAPIID=%d)", mapiid
);
860 if (ret
!= LDB_SUCCESS
) {
861 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
862 __location__
": Searching for mAPIID=%d failed - %s\n",
865 return ldb_operr(ldb
);
868 *found
= (ldb_res
->count
!= 0);
869 talloc_free(ldb_res
);
874 static int samldb_generate_next_mapiid(struct samldb_ctx
*ac
,
875 struct dsdb_schema
*schema
,
876 int32_t *next_mapiid
)
879 struct ldb_context
*ldb
;
880 struct ldb_dn
*schema_dn
;
881 bool mapiid_used
= true;
883 /* Windows' generation seems to start about here */
884 *next_mapiid
= 60000;
886 ldb
= ldb_module_get_ctx(ac
->module
);
887 schema_dn
= ldb_get_schema_basedn(ldb
);
889 while (mapiid_used
) {
891 ret
= samldb_check_mapiid_used(ac
, schema
,
893 *next_mapiid
, &mapiid_used
);
894 if (ret
!= LDB_SUCCESS
) {
902 static int samldb_schema_add_handle_mapiid(struct samldb_ctx
*ac
)
906 struct ldb_message_element
*el
;
908 struct ldb_context
*ldb
;
909 struct ldb_dn
*schema_dn
;
910 struct dsdb_schema
*schema
;
911 int32_t new_mapiid
= 0;
914 * The mAPIID of a new attribute should be automatically generated
915 * if a specific OID is put as the mAPIID, as according to
916 * [MS-ADTS] 3.1.1.2.3.2.
919 ldb
= ldb_module_get_ctx(ac
->module
);
920 schema
= dsdb_get_schema(ldb
, ac
);
921 schema_dn
= ldb_get_schema_basedn(ldb
);
923 ret
= dsdb_get_expected_new_values(ac
,
928 if (ret
!= LDB_SUCCESS
) {
932 if (el
== NULL
|| el
->num_values
== 0) {
936 enc_str
= ldb_binary_encode(ac
, el
->values
[0]);
937 if (enc_str
== NULL
) {
938 return ldb_module_oom(ac
->module
);
941 ok
= (strcmp(enc_str
, "1.2.840.113556.1.2.49") == 0);
943 ret
= samldb_generate_next_mapiid(ac
, schema
,
945 if (ret
!= LDB_SUCCESS
) {
949 ldb_msg_remove_element(ac
->msg
, el
);
950 ret
= samdb_msg_add_int(ldb
, ac
->msg
, ac
->msg
,
951 "mAPIID", new_mapiid
);
955 schema_dn
= ldb_get_schema_basedn(ldb_module_get_ctx(ac
->module
));
956 ret
= samldb_unique_attr_check(ac
, "mAPIID", NULL
, schema_dn
);
957 if (ret
== LDB_ERR_ENTRY_ALREADY_EXISTS
) {
958 return LDB_ERR_UNWILLING_TO_PERFORM
;
964 /* sAMAccountName handling */
965 static int samldb_generate_sAMAccountName(struct samldb_ctx
*ac
,
966 struct ldb_message
*msg
)
968 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
972 * This is currently a Samba-only behaviour, to add a trailing
973 * $ even for the generated accounts.
976 if (ac
->need_trailing_dollar
) {
977 /* Format: $000000-00000000000$ */
978 name
= talloc_asprintf(msg
, "$%.6X-%.6X%.5X$",
979 (unsigned int)generate_random(),
980 (unsigned int)generate_random(),
981 (unsigned int)generate_random());
983 /* Format: $000000-000000000000 */
985 name
= talloc_asprintf(msg
, "$%.6X-%.6X%.6X",
986 (unsigned int)generate_random(),
987 (unsigned int)generate_random(),
988 (unsigned int)generate_random());
993 return ldb_msg_add_steal_string(msg
, "sAMAccountName", name
);
996 static int samldb_check_sAMAccountName(struct samldb_ctx
*ac
)
1000 if (ldb_msg_find_element(ac
->msg
, "sAMAccountName") == NULL
) {
1001 ret
= samldb_generate_sAMAccountName(ac
, ac
->msg
);
1002 if (ret
!= LDB_SUCCESS
) {
1007 ret
= samldb_sam_accountname_valid_check(ac
);
1008 if (ret
!= LDB_SUCCESS
) {
1012 return samldb_next_step(ac
);
1016 static bool samldb_msg_add_sid(struct ldb_message
*msg
,
1018 const struct dom_sid
*sid
)
1021 enum ndr_err_code ndr_err
;
1023 ndr_err
= ndr_push_struct_blob(&v
, msg
, sid
,
1024 (ndr_push_flags_fn_t
)ndr_push_dom_sid
);
1025 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1028 return (ldb_msg_add_value(msg
, name
, &v
, NULL
) == 0);
1032 /* allocate a SID using our RID Set */
1033 static int samldb_allocate_sid(struct samldb_ctx
*ac
)
1036 struct dom_sid
*sid
;
1037 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1040 ret
= ridalloc_allocate_rid(ac
->module
, &rid
, ac
->req
);
1041 if (ret
!= LDB_SUCCESS
) {
1045 sid
= dom_sid_add_rid(ac
, samdb_domain_sid(ldb
), rid
);
1047 return ldb_module_oom(ac
->module
);
1050 if ( ! samldb_msg_add_sid(ac
->msg
, "objectSid", sid
)) {
1051 return ldb_operr(ldb
);
1056 return samldb_next_step(ac
);
1060 see if a krbtgt_number is available
1062 static bool samldb_krbtgtnumber_available(struct samldb_ctx
*ac
,
1063 uint32_t krbtgt_number
)
1065 TALLOC_CTX
*tmp_ctx
= talloc_new(ac
);
1066 struct ldb_result
*res
;
1067 const char * const no_attrs
[] = { NULL
};
1070 ret
= dsdb_module_search(ac
->module
, tmp_ctx
, &res
,
1071 ldb_get_default_basedn(ldb_module_get_ctx(ac
->module
)),
1072 LDB_SCOPE_SUBTREE
, no_attrs
,
1073 DSDB_FLAG_NEXT_MODULE
,
1075 "(msDS-SecondaryKrbTgtNumber=%u)",
1077 if (ret
== LDB_SUCCESS
&& res
->count
== 0) {
1078 talloc_free(tmp_ctx
);
1081 talloc_free(tmp_ctx
);
1085 /* special handling for add in RODC join */
1086 static int samldb_rodc_add(struct samldb_ctx
*ac
)
1088 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1089 uint32_t krbtgt_number
, i_start
, i
;
1091 struct ldb_val newpass_utf16
;
1093 /* find a unused msDS-SecondaryKrbTgtNumber */
1094 i_start
= generate_random() & 0xFFFF;
1099 for (i
=i_start
; i
<=0xFFFF; i
++) {
1100 if (samldb_krbtgtnumber_available(ac
, i
)) {
1105 for (i
=1; i
<i_start
; i
++) {
1106 if (samldb_krbtgtnumber_available(ac
, i
)) {
1112 ldb_asprintf_errstring(ldb
,
1113 "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
1114 W_ERROR_V(WERR_NO_SYSTEM_RESOURCES
));
1115 return LDB_ERR_OTHER
;
1119 ldb_msg_remove_attr(ac
->msg
, "msDS-SecondaryKrbTgtNumber");
1120 ret
= samdb_msg_append_uint(ldb
, ac
->msg
, ac
->msg
,
1121 "msDS-SecondaryKrbTgtNumber", krbtgt_number
,
1122 LDB_FLAG_INTERNAL_DISABLE_VALIDATION
);
1123 if (ret
!= LDB_SUCCESS
) {
1124 return ldb_operr(ldb
);
1127 ret
= ldb_msg_add_fmt(ac
->msg
, "sAMAccountName", "krbtgt_%u",
1129 if (ret
!= LDB_SUCCESS
) {
1130 return ldb_operr(ldb
);
1133 newpass_utf16
= data_blob_talloc_zero(ac
->module
, 256);
1134 if (newpass_utf16
.data
== NULL
) {
1135 return ldb_oom(ldb
);
1138 * Note that the password_hash module will ignore
1139 * this value and use it's own generate_secret_buffer()
1140 * that's why we can just use generate_random_buffer()
1143 generate_random_buffer(newpass_utf16
.data
, newpass_utf16
.length
);
1144 ret
= ldb_msg_add_steal_value(ac
->msg
, "clearTextPassword", &newpass_utf16
);
1145 if (ret
!= LDB_SUCCESS
) {
1146 return ldb_operr(ldb
);
1149 return samldb_next_step(ac
);
1152 static int samldb_gmsa_add(struct samldb_ctx
*ac
)
1154 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1155 int ret
= LDB_SUCCESS
;
1156 NTTIME current_time
= 0;
1157 const bool userPassword
= dsdb_user_password_support(ac
->module
,
1162 ok
= dsdb_gmsa_current_time(ldb
, ¤t_time
);
1164 ret
= ldb_operr(ldb
);
1168 /* Remove any user‐specified passwords. */
1169 dsdb_remove_password_related_attrs(ac
->msg
, userPassword
);
1171 /* Remove any user‐specified password IDs. */
1172 ldb_msg_remove_attr(ac
->msg
, "msDS-ManagedPasswordId");
1173 ldb_msg_remove_attr(ac
->msg
, "msDS-ManagedPasswordPreviousId");
1176 DATA_BLOB pwd_id_blob
= {};
1177 DATA_BLOB password_blob
= {};
1178 struct gmsa_null_terminated_password
*password
= NULL
;
1181 * The account must have a SID allocated for us to be able to
1182 * derive its password.
1184 if (ac
->sid
== NULL
) {
1185 ret
= ldb_operr(ldb
);
1189 /* Calculate the password and ID blobs. */
1190 ret
= gmsa_generate_blobs(ldb
,
1200 password_blob
= (DATA_BLOB
){.data
= password
->buf
,
1201 .length
= GMSA_PASSWORD_LEN
};
1203 /* Add the new password blob. */
1204 ret
= ldb_msg_append_steal_value(ac
->msg
,
1205 "clearTextPassword",
1212 /* Add the new password ID blob. */
1213 ret
= ldb_msg_append_steal_value(ac
->msg
,
1214 "msDS-ManagedPasswordId",
1222 ret
= samldb_next_step(ac
);
1231 static int samldb_find_for_defaultObjectCategory(struct samldb_ctx
*ac
)
1233 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1234 struct ldb_result
*res
;
1235 const char * const no_attrs
[] = { NULL
};
1240 ret
= dsdb_module_search(ac
->module
, ac
, &res
,
1241 ac
->dn
, LDB_SCOPE_BASE
, no_attrs
,
1242 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
1243 | DSDB_FLAG_NEXT_MODULE
,
1245 "(objectClass=classSchema)");
1246 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
1247 /* Don't be pricky when the DN doesn't exist if we have the */
1248 /* RELAX control specified */
1249 if (ldb_request_get_control(ac
->req
,
1250 LDB_CONTROL_RELAX_OID
) == NULL
) {
1251 ldb_set_errstring(ldb
,
1252 "samldb_find_defaultObjectCategory: "
1253 "Invalid DN for 'defaultObjectCategory'!");
1254 return LDB_ERR_CONSTRAINT_VIOLATION
;
1257 if ((ret
!= LDB_ERR_NO_SUCH_OBJECT
) && (ret
!= LDB_SUCCESS
)) {
1261 if (ret
== LDB_SUCCESS
) {
1262 /* ensure the defaultObjectCategory has a full GUID */
1263 struct ldb_message
*m
;
1264 m
= ldb_msg_new(ac
->msg
);
1266 return ldb_oom(ldb
);
1268 m
->dn
= ac
->msg
->dn
;
1269 if (ldb_msg_add_string(m
, "defaultObjectCategory",
1270 ldb_dn_get_extended_linearized(m
, res
->msgs
[0]->dn
, 1)) !=
1272 return ldb_oom(ldb
);
1274 m
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
1276 ret
= dsdb_module_modify(ac
->module
, m
,
1277 DSDB_FLAG_NEXT_MODULE
,
1279 if (ret
!= LDB_SUCCESS
) {
1285 ac
->res_dn
= ac
->dn
;
1287 return samldb_next_step(ac
);
1291 * msDS-IntId attributeSchema attribute handling
1292 * during LDB_ADD request processing
1294 static int samldb_add_handle_msDS_IntId(struct samldb_ctx
*ac
)
1298 uint32_t msds_intid
;
1299 int32_t system_flags
;
1300 struct ldb_context
*ldb
;
1301 struct ldb_result
*ldb_res
;
1302 struct ldb_dn
*schema_dn
;
1303 struct samldb_msds_intid_persistant
*msds_intid_struct
;
1304 struct dsdb_schema
*schema
;
1306 ldb
= ldb_module_get_ctx(ac
->module
);
1307 schema_dn
= ldb_get_schema_basedn(ldb
);
1309 /* replicated update should always go through */
1310 if (ldb_request_get_control(ac
->req
,
1311 DSDB_CONTROL_REPLICATED_UPDATE_OID
)) {
1315 /* msDS-IntId is handled by system and should never be
1316 * passed by clients */
1317 if (ldb_msg_find_element(ac
->msg
, "msDS-IntId")) {
1318 return LDB_ERR_UNWILLING_TO_PERFORM
;
1321 /* do not generate msDS-IntId if Relax control is passed */
1322 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
1326 /* check Functional Level */
1327 if (dsdb_functional_level(ldb
) < DS_DOMAIN_FUNCTION_2003
) {
1331 /* check systemFlags for SCHEMA_BASE_OBJECT flag */
1332 system_flags
= ldb_msg_find_attr_as_int(ac
->msg
, "systemFlags", 0);
1333 if (system_flags
& SYSTEM_FLAG_SCHEMA_BASE_OBJECT
) {
1336 schema
= dsdb_get_schema(ldb
, NULL
);
1338 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
1339 "samldb_schema_info_update: no dsdb_schema loaded");
1340 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1341 return ldb_operr(ldb
);
1344 msds_intid_struct
= (struct samldb_msds_intid_persistant
*) ldb_get_opaque(ldb
, SAMLDB_MSDS_INTID_OPAQUE
);
1345 if (!msds_intid_struct
) {
1346 msds_intid_struct
= talloc(ldb
, struct samldb_msds_intid_persistant
);
1347 /* Generate new value for msDs-IntId
1348 * Value should be in 0x80000000..0xBFFFFFFF range */
1349 msds_intid
= generate_random() % 0X3FFFFFFF;
1350 msds_intid
+= 0x80000000;
1351 msds_intid_struct
->msds_intid
= msds_intid
;
1352 DEBUG(2, ("No samldb_msds_intid_persistant struct, allocating a new one\n"));
1354 msds_intid
= msds_intid_struct
->msds_intid
;
1357 /* probe id values until unique one is found */
1360 if (msds_intid
> 0xBFFFFFFF) {
1361 msds_intid
= 0x80000001;
1364 * We search in the schema if we have already this
1365 * intid (using dsdb_attribute_by_attributeID_id
1366 * because in the range 0x80000000 0xBFFFFFFF,
1367 * attributeID is a DSDB_ATTID_TYPE_INTID).
1369 * If so generate another random value.
1371 * We have to check the DB in case someone else has
1372 * modified the database while we are doing our
1373 * changes too (this case should be very very rare) in
1376 if (dsdb_attribute_by_attributeID_id(schema
, msds_intid
)) {
1378 msds_intid
= generate_random() % 0X3FFFFFFF;
1379 msds_intid
+= 0x80000000;
1384 ret
= dsdb_module_search(ac
->module
, ac
,
1386 schema_dn
, LDB_SCOPE_ONELEVEL
, NULL
,
1387 DSDB_FLAG_NEXT_MODULE
,
1389 "(msDS-IntId=%d)", msds_intid
);
1390 if (ret
!= LDB_SUCCESS
) {
1391 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
1392 __location__
": Searching for msDS-IntId=%d failed - %s\n",
1394 ldb_errstring(ldb
));
1395 return ldb_operr(ldb
);
1397 id_exists
= (ldb_res
->count
> 0);
1398 talloc_free(ldb_res
);
1401 msds_intid_struct
->msds_intid
= msds_intid
;
1402 ldb_set_opaque(ldb
, SAMLDB_MSDS_INTID_OPAQUE
, msds_intid_struct
);
1404 return samdb_msg_add_int(ldb
, ac
->msg
, ac
->msg
, "msDS-IntId",
1410 * samldb_add_entry (async)
1413 static int samldb_add_entry_callback(struct ldb_request
*req
,
1414 struct ldb_reply
*ares
)
1416 struct ldb_context
*ldb
;
1417 struct samldb_ctx
*ac
;
1420 ac
= talloc_get_type(req
->context
, struct samldb_ctx
);
1421 ldb
= ldb_module_get_ctx(ac
->module
);
1424 return ldb_module_done(ac
->req
, NULL
, NULL
,
1425 LDB_ERR_OPERATIONS_ERROR
);
1428 if (ares
->type
== LDB_REPLY_REFERRAL
) {
1429 return ldb_module_send_referral(ac
->req
, ares
->referral
);
1432 if (ares
->error
!= LDB_SUCCESS
) {
1433 return ldb_module_done(ac
->req
, ares
->controls
,
1434 ares
->response
, ares
->error
);
1436 if (ares
->type
!= LDB_REPLY_DONE
) {
1437 ldb_asprintf_errstring(ldb
, "Invalid LDB reply type %d", ares
->type
);
1438 return ldb_module_done(ac
->req
, NULL
, NULL
,
1439 LDB_ERR_OPERATIONS_ERROR
);
1442 /* The caller may wish to get controls back from the add */
1443 ac
->ares
= talloc_steal(ac
, ares
);
1445 ret
= samldb_next_step(ac
);
1446 if (ret
!= LDB_SUCCESS
) {
1447 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1452 static int samldb_add_entry(struct samldb_ctx
*ac
)
1454 struct ldb_context
*ldb
;
1455 struct ldb_request
*req
;
1458 ldb
= ldb_module_get_ctx(ac
->module
);
1460 ret
= ldb_build_add_req(&req
, ldb
, ac
,
1463 ac
, samldb_add_entry_callback
,
1465 LDB_REQ_SET_LOCATION(req
);
1466 if (ret
!= LDB_SUCCESS
) {
1470 return ldb_next_request(ac
->module
, req
);
1474 * return true if msg carries an attributeSchema that is intended to be RODC
1475 * filtered but is also a system-critical attribute.
1477 static bool check_rodc_critical_attribute(struct ldb_message
*msg
)
1479 uint32_t schemaFlagsEx
, searchFlags
, rodc_filtered_flags
;
1481 schemaFlagsEx
= ldb_msg_find_attr_as_uint(msg
, "schemaFlagsEx", 0);
1482 searchFlags
= ldb_msg_find_attr_as_uint(msg
, "searchFlags", 0);
1483 rodc_filtered_flags
= (SEARCH_FLAG_RODC_ATTRIBUTE
1484 | SEARCH_FLAG_CONFIDENTIAL
);
1486 if ((schemaFlagsEx
& SCHEMA_FLAG_ATTR_IS_CRITICAL
) &&
1487 ((searchFlags
& rodc_filtered_flags
) == rodc_filtered_flags
)) {
1495 static int samldb_fill_object(struct samldb_ctx
*ac
)
1497 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1500 /* Add information for the different account types */
1502 case SAMLDB_TYPE_USER
: {
1503 struct ldb_control
*rodc_control
= ldb_request_get_control(ac
->req
,
1504 LDB_CONTROL_RODC_DCPROMO_OID
);
1505 if (rodc_control
!= NULL
) {
1506 /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
1507 rodc_control
->critical
= false;
1508 ret
= samldb_add_step(ac
, samldb_rodc_add
);
1509 if (ret
!= LDB_SUCCESS
) return ret
;
1512 if (dsdb_account_is_gmsa(ldb
, ac
->msg
)) {
1513 ret
= samldb_add_step(ac
, samldb_gmsa_add
);
1514 if (ret
!= LDB_SUCCESS
) {
1519 /* check if we have a valid sAMAccountName */
1520 ret
= samldb_add_step(ac
, samldb_check_sAMAccountName
);
1521 if (ret
!= LDB_SUCCESS
) return ret
;
1523 ret
= samldb_add_step(ac
, samldb_add_entry
);
1524 if (ret
!= LDB_SUCCESS
) return ret
;
1528 case SAMLDB_TYPE_GROUP
: {
1529 /* check if we have a valid sAMAccountName */
1530 ret
= samldb_add_step(ac
, samldb_check_sAMAccountName
);
1531 if (ret
!= LDB_SUCCESS
) return ret
;
1533 ret
= samldb_add_step(ac
, samldb_add_entry
);
1534 if (ret
!= LDB_SUCCESS
) return ret
;
1538 case SAMLDB_TYPE_CLASS
: {
1539 const char *lDAPDisplayName
= NULL
;
1540 const struct ldb_val
*rdn_value
, *def_obj_cat_val
;
1541 unsigned int v
= ldb_msg_find_attr_as_uint(ac
->msg
, "objectClassCategory", -2);
1543 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
1544 if (!ldb_msg_find_element(ac
->msg
, "subClassOf")) {
1545 ret
= ldb_msg_add_string(ac
->msg
, "subClassOf", "top");
1546 if (ret
!= LDB_SUCCESS
) return ret
;
1549 ret
= samdb_find_or_add_attribute(ldb
, ac
->msg
,
1551 if (ret
!= LDB_SUCCESS
) return ret
;
1553 /* do not allow one to mark an attributeSchema as RODC filtered if it
1554 * is system-critical */
1555 if (check_rodc_critical_attribute(ac
->msg
)) {
1556 ldb_asprintf_errstring(ldb
, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
1557 ldb_dn_get_linearized(ac
->msg
->dn
));
1558 return LDB_ERR_UNWILLING_TO_PERFORM
;
1561 rdn_value
= ldb_dn_get_rdn_val(ac
->msg
->dn
);
1562 if (rdn_value
== NULL
) {
1563 return ldb_operr(ldb
);
1565 if (!ldb_msg_find_element(ac
->msg
, "lDAPDisplayName")) {
1566 /* the RDN has prefix "CN" */
1567 ret
= ldb_msg_add_string(ac
->msg
, "lDAPDisplayName",
1568 samdb_cn_to_lDAPDisplayName(ac
->msg
,
1569 (const char *) rdn_value
->data
));
1570 if (ret
!= LDB_SUCCESS
) {
1576 lDAPDisplayName
= ldb_msg_find_attr_as_string(ac
->msg
,
1579 ret
= ldb_valid_attr_name(lDAPDisplayName
);
1581 lDAPDisplayName
[0] == '*' ||
1582 lDAPDisplayName
[0] == '@')
1584 return dsdb_module_werror(ac
->module
,
1585 LDB_ERR_UNWILLING_TO_PERFORM
,
1586 WERR_DS_INVALID_LDAP_DISPLAY_NAME
,
1587 "lDAPDisplayName is invalid");
1590 if (!ldb_msg_find_element(ac
->msg
, "schemaIDGUID")) {
1593 guid
= GUID_random();
1594 ret
= dsdb_msg_add_guid(ac
->msg
, &guid
, "schemaIDGUID");
1595 if (ret
!= LDB_SUCCESS
) {
1601 def_obj_cat_val
= ldb_msg_find_ldb_val(ac
->msg
,
1602 "defaultObjectCategory");
1603 if (def_obj_cat_val
!= NULL
) {
1604 /* "defaultObjectCategory" has been set by the caller.
1605 * Do some checks for consistency.
1606 * NOTE: The real constraint check (that
1607 * 'defaultObjectCategory' is the DN of the new
1608 * objectclass or any parent of it) is still incomplete.
1609 * For now we say that 'defaultObjectCategory' is valid
1610 * if it exists and it is of objectclass "classSchema".
1612 ac
->dn
= ldb_dn_from_ldb_val(ac
, ldb
, def_obj_cat_val
);
1613 if (ac
->dn
== NULL
) {
1614 ldb_set_errstring(ldb
,
1615 "Invalid DN for 'defaultObjectCategory'!");
1616 return LDB_ERR_CONSTRAINT_VIOLATION
;
1619 /* "defaultObjectCategory" has not been set by the
1620 * caller. Use the entry DN for it. */
1621 ac
->dn
= ac
->msg
->dn
;
1623 ret
= ldb_msg_add_string(ac
->msg
, "defaultObjectCategory",
1624 ldb_dn_alloc_linearized(ac
->msg
, ac
->dn
));
1625 if (ret
!= LDB_SUCCESS
) {
1631 ret
= samldb_add_step(ac
, samldb_add_entry
);
1632 if (ret
!= LDB_SUCCESS
) return ret
;
1634 /* Now perform the checks for the 'defaultObjectCategory'. The
1635 * lookup DN was already saved in "ac->dn" */
1636 ret
= samldb_add_step(ac
, samldb_find_for_defaultObjectCategory
);
1637 if (ret
!= LDB_SUCCESS
) return ret
;
1639 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
1641 /* Windows 2003 does this*/
1642 ret
= samdb_msg_add_uint(ldb
, ac
->msg
, ac
->msg
, "objectClassCategory", 0);
1643 if (ret
!= LDB_SUCCESS
) {
1650 case SAMLDB_TYPE_ATTRIBUTE
: {
1651 const char *lDAPDisplayName
= NULL
;
1652 const struct ldb_val
*rdn_value
;
1653 struct ldb_message_element
*el
;
1654 rdn_value
= ldb_dn_get_rdn_val(ac
->msg
->dn
);
1655 if (rdn_value
== NULL
) {
1656 return ldb_operr(ldb
);
1658 if (!ldb_msg_find_element(ac
->msg
, "lDAPDisplayName")) {
1659 /* the RDN has prefix "CN" */
1660 ret
= ldb_msg_add_string(ac
->msg
, "lDAPDisplayName",
1661 samdb_cn_to_lDAPDisplayName(ac
->msg
,
1662 (const char *) rdn_value
->data
));
1663 if (ret
!= LDB_SUCCESS
) {
1669 lDAPDisplayName
= ldb_msg_find_attr_as_string(ac
->msg
,
1672 ret
= ldb_valid_attr_name(lDAPDisplayName
);
1674 lDAPDisplayName
[0] == '*' ||
1675 lDAPDisplayName
[0] == '@')
1677 return dsdb_module_werror(ac
->module
,
1678 LDB_ERR_UNWILLING_TO_PERFORM
,
1679 WERR_DS_INVALID_LDAP_DISPLAY_NAME
,
1680 "lDAPDisplayName is invalid");
1683 /* do not allow one to mark an attributeSchema as RODC filtered if it
1684 * is system-critical */
1685 if (check_rodc_critical_attribute(ac
->msg
)) {
1686 ldb_asprintf_errstring(ldb
,
1687 "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
1688 ldb_dn_get_linearized(ac
->msg
->dn
));
1689 return LDB_ERR_UNWILLING_TO_PERFORM
;
1692 ret
= samdb_find_or_add_attribute(ldb
, ac
->msg
,
1693 "isSingleValued", "FALSE");
1694 if (ret
!= LDB_SUCCESS
) return ret
;
1696 if (!ldb_msg_find_element(ac
->msg
, "schemaIDGUID")) {
1699 guid
= GUID_random();
1700 ret
= dsdb_msg_add_guid(ac
->msg
, &guid
, "schemaIDGUID");
1701 if (ret
!= LDB_SUCCESS
) {
1707 el
= ldb_msg_find_element(ac
->msg
, "attributeSyntax");
1710 * No need to scream if there isn't as we have code later on
1711 * that will take care of it.
1713 const struct dsdb_syntax
*syntax
= find_syntax_map_by_ad_oid((const char *)el
->values
[0].data
);
1715 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
1716 (const char *)el
->values
[0].data
));
1718 unsigned int v
= ldb_msg_find_attr_as_uint(ac
->msg
, "oMSyntax", 0);
1719 const struct ldb_val
*val
= ldb_msg_find_ldb_val(ac
->msg
, "oMObjectClass");
1722 ret
= samdb_msg_add_uint(ldb
, ac
->msg
, ac
->msg
, "oMSyntax", syntax
->oMSyntax
);
1723 if (ret
!= LDB_SUCCESS
) {
1728 struct ldb_val val2
= ldb_val_dup(ldb
, &syntax
->oMObjectClass
);
1729 if (val2
.length
> 0) {
1730 ret
= ldb_msg_add_value(ac
->msg
, "oMObjectClass", &val2
, NULL
);
1731 if (ret
!= LDB_SUCCESS
) {
1739 /* handle msDS-IntID attribute */
1740 ret
= samldb_add_handle_msDS_IntId(ac
);
1741 if (ret
!= LDB_SUCCESS
) return ret
;
1743 ret
= samldb_add_step(ac
, samldb_add_entry
);
1744 if (ret
!= LDB_SUCCESS
) return ret
;
1749 ldb_asprintf_errstring(ldb
, "Invalid entry type!");
1750 return LDB_ERR_OPERATIONS_ERROR
;
1754 return samldb_first_step(ac
);
1757 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx
*ac
)
1759 struct ldb_context
*ldb
= NULL
;
1760 const struct ldb_val
*rdn_value
= NULL
;
1761 struct ldb_message_element
*sid_el
= NULL
;
1762 struct dom_sid
*sid
= NULL
;
1763 struct ldb_control
*as_system
= NULL
;
1764 struct ldb_control
*provision
= NULL
;
1765 bool allowed
= false;
1768 ldb
= ldb_module_get_ctx(ac
->module
);
1770 as_system
= ldb_request_get_control(ac
->req
, LDB_CONTROL_AS_SYSTEM_OID
);
1771 if (as_system
!= NULL
) {
1775 provision
= ldb_request_get_control(ac
->req
, LDB_CONTROL_PROVISION_OID
);
1776 if (provision
!= NULL
) {
1780 sid_el
= ldb_msg_find_element(ac
->msg
, "objectSid");
1782 if (!allowed
&& sid_el
== NULL
) {
1783 return dsdb_module_werror(ac
->module
,
1784 LDB_ERR_OBJECT_CLASS_VIOLATION
,
1785 WERR_DS_MISSING_REQUIRED_ATT
,
1786 "objectSid missing on foreignSecurityPrincipal");
1790 return dsdb_module_werror(ac
->module
,
1791 LDB_ERR_UNWILLING_TO_PERFORM
,
1792 WERR_DS_ILLEGAL_MOD_OPERATION
,
1793 "foreignSecurityPrincipal object not allowed");
1796 if (sid_el
!= NULL
) {
1797 sid
= samdb_result_dom_sid(ac
->msg
, ac
->msg
, "objectSid");
1799 ldb_set_errstring(ldb
,
1800 "samldb: invalid objectSid!");
1801 return LDB_ERR_CONSTRAINT_VIOLATION
;
1806 rdn_value
= ldb_dn_get_rdn_val(ac
->msg
->dn
);
1807 if (rdn_value
== NULL
) {
1808 return ldb_operr(ldb
);
1810 sid
= dom_sid_parse_talloc(ac
->msg
,
1811 (const char *)rdn_value
->data
);
1813 ldb_set_errstring(ldb
,
1814 "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
1815 return LDB_ERR_CONSTRAINT_VIOLATION
;
1817 if (! samldb_msg_add_sid(ac
->msg
, "objectSid", sid
)) {
1818 return ldb_operr(ldb
);
1822 /* finally proceed with adding the entry */
1823 ret
= samldb_add_step(ac
, samldb_add_entry
);
1824 if (ret
!= LDB_SUCCESS
) return ret
;
1826 return samldb_first_step(ac
);
1829 static int samldb_schema_info_update(struct samldb_ctx
*ac
)
1832 struct ldb_context
*ldb
;
1833 struct dsdb_schema
*schema
;
1835 /* replicated update should always go through */
1836 if (ldb_request_get_control(ac
->req
,
1837 DSDB_CONTROL_REPLICATED_UPDATE_OID
)) {
1841 /* do not update schemaInfo during provisioning */
1842 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_PROVISION_OID
)) {
1846 ldb
= ldb_module_get_ctx(ac
->module
);
1847 schema
= dsdb_get_schema(ldb
, NULL
);
1849 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
1850 "samldb_schema_info_update: no dsdb_schema loaded");
1851 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
1852 return ldb_operr(ldb
);
1855 ret
= dsdb_module_schema_info_update(ac
->module
, schema
,
1856 DSDB_FLAG_NEXT_MODULE
|
1857 DSDB_FLAG_AS_SYSTEM
,
1859 if (ret
!= LDB_SUCCESS
) {
1860 ldb_asprintf_errstring(ldb
,
1861 "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
1862 ldb_errstring(ldb
));
1869 static int samldb_prim_group_tester(struct samldb_ctx
*ac
, uint32_t rid
);
1870 static int samldb_check_user_account_control_rules(struct samldb_ctx
*ac
,
1871 struct dom_sid
*sid
,
1873 uint32_t user_account_control
,
1874 uint32_t user_account_control_old
,
1875 bool is_computer_objectclass
);
1878 * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
1880 * Has to be invoked on "add" operations on "user", "computer" and
1882 * ac->msg contains the "add"
1883 * ac->type contains the object type (main objectclass)
1885 static int samldb_objectclass_trigger(struct samldb_ctx
*ac
)
1887 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
1888 void *skip_allocate_sids
= ldb_get_opaque(ldb
,
1889 "skip_allocate_sids");
1890 struct ldb_message_element
*el
;
1891 struct dom_sid
*sid
;
1894 /* make sure that "sAMAccountType" is not specified */
1895 el
= ldb_msg_find_element(ac
->msg
, "sAMAccountType");
1897 ldb_set_errstring(ldb
,
1898 "samldb: sAMAccountType must not be specified!");
1899 return LDB_ERR_UNWILLING_TO_PERFORM
;
1902 /* Step 1: objectSid assignment */
1904 /* Don't allow the objectSid to be changed. But beside the RELAX
1905 * control we have also to guarantee that it can always be set with
1906 * SYSTEM permissions. This is needed for the "samba3sam" backend. */
1907 sid
= samdb_result_dom_sid(ac
, ac
->msg
, "objectSid");
1908 if ((sid
!= NULL
) && (!dsdb_module_am_system(ac
->module
)) &&
1909 (ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
) == NULL
)) {
1910 ldb_set_errstring(ldb
,
1911 "samldb: objectSid must not be specified!");
1912 return LDB_ERR_UNWILLING_TO_PERFORM
;
1915 /* but generate a new SID when we do have an add operations */
1916 if ((sid
== NULL
) && (ac
->req
->operation
== LDB_ADD
) && !skip_allocate_sids
) {
1917 ret
= samldb_add_step(ac
, samldb_allocate_sid
);
1918 if (ret
!= LDB_SUCCESS
) return ret
;
1922 case SAMLDB_TYPE_USER
: {
1924 uint32_t user_account_control
;
1925 bool is_computer_objectclass
;
1926 bool uac_generated
= false, uac_add_flags
= false;
1927 uint32_t default_user_account_control
= UF_NORMAL_ACCOUNT
;
1928 /* Step 1.2: Default values */
1929 ret
= dsdb_user_obj_set_defaults(ldb
, ac
->msg
, ac
->req
);
1930 if (ret
!= LDB_SUCCESS
) return ret
;
1932 is_computer_objectclass
1933 = (samdb_find_attribute(ldb
,
1939 if (is_computer_objectclass
) {
1940 default_user_account_control
1941 = UF_WORKSTATION_TRUST_ACCOUNT
;
1945 /* On add operations we might need to generate a
1946 * "userAccountControl" (if it isn't specified). */
1947 el
= ldb_msg_find_element(ac
->msg
, "userAccountControl");
1949 ret
= samdb_msg_set_uint(ldb
, ac
->msg
, ac
->msg
,
1950 "userAccountControl",
1951 default_user_account_control
);
1952 if (ret
!= LDB_SUCCESS
) {
1955 uac_generated
= true;
1956 uac_add_flags
= true;
1959 el
= ldb_msg_find_element(ac
->msg
, "userAccountControl");
1960 SMB_ASSERT(el
!= NULL
);
1962 /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
1963 user_account_control
= ldb_msg_find_attr_as_uint(ac
->msg
,
1964 "userAccountControl",
1966 raw_uac
= user_account_control
;
1968 * "userAccountControl" = 0 or missing one of
1969 * the types means "UF_NORMAL_ACCOUNT"
1970 * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer).
1971 * See MS-SAMR 3.1.1.8.10 point 8
1973 if ((user_account_control
& UF_ACCOUNT_TYPE_MASK
) == 0) {
1974 user_account_control
1975 = default_user_account_control
1976 | user_account_control
;
1977 uac_generated
= true;
1981 * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
1983 if ((user_account_control
& UF_LOCKOUT
) != 0) {
1984 user_account_control
&= ~UF_LOCKOUT
;
1985 uac_generated
= true;
1987 if ((user_account_control
& UF_PASSWORD_EXPIRED
) != 0) {
1988 user_account_control
&= ~UF_PASSWORD_EXPIRED
;
1989 uac_generated
= true;
1992 ret
= samldb_check_user_account_control_rules(ac
, NULL
,
1994 user_account_control
,
1996 is_computer_objectclass
);
1997 if (ret
!= LDB_SUCCESS
) {
2002 * Require, for non-admin modifications, a trailing $
2003 * for either objectclass=computer or a trust account
2004 * type in userAccountControl
2006 if ((user_account_control
2007 & UF_TRUST_ACCOUNT_MASK
) != 0) {
2008 ac
->need_trailing_dollar
= true;
2011 if (is_computer_objectclass
) {
2012 ac
->need_trailing_dollar
= true;
2015 /* add "sAMAccountType" attribute */
2016 ret
= dsdb_user_obj_set_account_type(ldb
, ac
->msg
, user_account_control
, NULL
);
2017 if (ret
!= LDB_SUCCESS
) {
2021 /* "isCriticalSystemObject" might be set */
2022 if (user_account_control
&
2023 (UF_SERVER_TRUST_ACCOUNT
| UF_PARTIAL_SECRETS_ACCOUNT
)) {
2024 ret
= ldb_msg_add_string_flags(ac
->msg
, "isCriticalSystemObject",
2025 "TRUE", LDB_FLAG_MOD_REPLACE
);
2026 if (ret
!= LDB_SUCCESS
) {
2029 } else if (user_account_control
& UF_WORKSTATION_TRUST_ACCOUNT
) {
2030 ret
= ldb_msg_add_string_flags(ac
->msg
, "isCriticalSystemObject",
2031 "FALSE", LDB_FLAG_MOD_REPLACE
);
2032 if (ret
!= LDB_SUCCESS
) {
2037 /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
2038 if (!ldb_msg_find_element(ac
->msg
, "primaryGroupID")) {
2041 ret
= dsdb_user_obj_set_primary_group_id(ldb
, ac
->msg
, user_account_control
, &rid
);
2042 if (ret
!= LDB_SUCCESS
) {
2046 * Older AD deployments don't know about the
2049 if (rid
== DOMAIN_RID_READONLY_DCS
) {
2050 ret
= samldb_prim_group_tester(ac
, rid
);
2051 if (ret
!= LDB_SUCCESS
) {
2057 /* Step 1.5: Add additional flags when needed */
2058 /* Obviously this is done when the "userAccountControl"
2059 * has been generated here (tested against Windows
2061 if (uac_generated
) {
2062 if (uac_add_flags
) {
2063 user_account_control
|= UF_ACCOUNTDISABLE
;
2064 user_account_control
|= UF_PASSWD_NOTREQD
;
2067 ret
= samdb_msg_set_uint(ldb
, ac
->msg
, ac
->msg
,
2068 "userAccountControl",
2069 user_account_control
);
2070 if (ret
!= LDB_SUCCESS
) {
2077 case SAMLDB_TYPE_GROUP
: {
2078 const char *tempstr
;
2080 /* Step 2.2: Default values */
2081 tempstr
= talloc_asprintf(ac
->msg
, "%d",
2082 GTYPE_SECURITY_GLOBAL_GROUP
);
2083 if (tempstr
== NULL
) return ldb_operr(ldb
);
2084 ret
= samdb_find_or_add_attribute(ldb
, ac
->msg
,
2085 "groupType", tempstr
);
2086 if (ret
!= LDB_SUCCESS
) return ret
;
2088 /* Step 2.3: "groupType" -> "sAMAccountType" */
2089 el
= ldb_msg_find_element(ac
->msg
, "groupType");
2091 uint32_t group_type
, account_type
;
2093 group_type
= ldb_msg_find_attr_as_uint(ac
->msg
,
2096 /* The creation of builtin groups requires the
2098 if (group_type
== GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
) {
2099 if (ldb_request_get_control(ac
->req
,
2100 LDB_CONTROL_RELAX_OID
) == NULL
) {
2101 return LDB_ERR_UNWILLING_TO_PERFORM
;
2105 account_type
= ds_gtype2atype(group_type
);
2106 if (account_type
== 0) {
2107 ldb_set_errstring(ldb
, "samldb: Unrecognized account type!");
2108 return LDB_ERR_UNWILLING_TO_PERFORM
;
2110 ret
= samdb_msg_add_uint_flags(ldb
, ac
->msg
, ac
->msg
,
2113 LDB_FLAG_MOD_REPLACE
);
2114 if (ret
!= LDB_SUCCESS
) {
2122 ldb_asprintf_errstring(ldb
,
2123 "Invalid entry type!");
2124 return LDB_ERR_OPERATIONS_ERROR
;
2132 * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
2134 * Has to be invoked on "add" and "modify" operations on "user" and "computer"
2136 * ac->msg contains the "add"/"modify" message
2139 static int samldb_prim_group_tester(struct samldb_ctx
*ac
, uint32_t rid
)
2141 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2142 struct dom_sid
*sid
;
2143 struct ldb_result
*res
;
2145 const char * const noattrs
[] = { NULL
};
2147 sid
= dom_sid_add_rid(ac
, samdb_domain_sid(ldb
), rid
);
2149 return ldb_operr(ldb
);
2152 ret
= dsdb_module_search(ac
->module
, ac
, &res
,
2153 ldb_get_default_basedn(ldb
),
2155 noattrs
, DSDB_FLAG_NEXT_MODULE
,
2158 ldap_encode_ndr_dom_sid(ac
, sid
));
2159 if (ret
!= LDB_SUCCESS
) {
2162 if (res
->count
!= 1) {
2164 ldb_asprintf_errstring(ldb
,
2165 "Failed to find primary group with RID %u!",
2167 return LDB_ERR_UNWILLING_TO_PERFORM
;
2174 static int samldb_prim_group_set(struct samldb_ctx
*ac
)
2176 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2179 rid
= ldb_msg_find_attr_as_uint(ac
->msg
, "primaryGroupID", (uint32_t) -1);
2180 if (rid
== (uint32_t) -1) {
2181 /* we aren't affected of any primary group set */
2184 } else if (!ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
2185 ldb_set_errstring(ldb
,
2186 "The primary group isn't settable on add operations!");
2187 return LDB_ERR_UNWILLING_TO_PERFORM
;
2190 return samldb_prim_group_tester(ac
, rid
);
2193 static int samldb_prim_group_change(struct samldb_ctx
*ac
)
2195 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2196 const char * const attrs
[] = {
2199 "userAccountControl",
2201 struct ldb_result
*res
, *group_res
;
2202 struct ldb_message_element
*el
;
2203 struct ldb_message
*msg
;
2204 uint32_t search_flags
=
2205 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_EXTENDED_DN
;
2206 uint32_t prev_rid
, new_rid
, uac
;
2207 struct dom_sid
*prev_sid
, *new_sid
;
2208 struct ldb_dn
*prev_prim_group_dn
, *new_prim_group_dn
;
2209 const char *new_prim_group_dn_ext_str
= NULL
;
2210 struct ldb_dn
*user_dn
= NULL
;
2211 const char *user_dn_ext_str
= NULL
;
2213 const char * const noattrs
[] = { NULL
};
2214 const char * const group_type_attrs
[] = { "groupType", NULL
};
2215 unsigned group_type
;
2217 ret
= dsdb_get_expected_new_values(ac
,
2221 ac
->req
->operation
);
2222 if (ret
!= LDB_SUCCESS
) {
2227 /* we are not affected */
2231 /* Fetch information from the existing object */
2233 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
, attrs
,
2234 search_flags
, ac
->req
);
2235 if (ret
!= LDB_SUCCESS
) {
2238 user_dn
= res
->msgs
[0]->dn
;
2239 user_dn_ext_str
= ldb_dn_get_extended_linearized(ac
, user_dn
, 1);
2240 if (user_dn_ext_str
== NULL
) {
2241 return ldb_operr(ldb
);
2244 uac
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "userAccountControl", 0);
2246 /* Finds out the DN of the old primary group */
2248 prev_rid
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "primaryGroupID",
2250 if (prev_rid
== (uint32_t) -1) {
2251 /* User objects do always have a mandatory "primaryGroupID"
2252 * attribute. If this doesn't exist then the object is of the
2253 * wrong type. This is the exact Windows error code */
2254 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2257 prev_sid
= dom_sid_add_rid(ac
, samdb_domain_sid(ldb
), prev_rid
);
2258 if (prev_sid
== NULL
) {
2259 return ldb_operr(ldb
);
2262 /* Finds out the DN of the new primary group
2263 * Notice: in order to parse the primary group ID correctly we create
2264 * a temporary message here. */
2266 msg
= ldb_msg_new(ac
->msg
);
2268 return ldb_module_oom(ac
->module
);
2270 ret
= ldb_msg_add(msg
, el
, 0);
2271 if (ret
!= LDB_SUCCESS
) {
2274 new_rid
= ldb_msg_find_attr_as_uint(msg
, "primaryGroupID", (uint32_t) -1);
2276 if (new_rid
== (uint32_t) -1) {
2277 /* we aren't affected of any primary group change */
2281 if (prev_rid
== new_rid
) {
2285 if ((uac
& UF_SERVER_TRUST_ACCOUNT
) && new_rid
!= DOMAIN_RID_DCS
) {
2286 ldb_asprintf_errstring(ldb
,
2287 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
2288 "primaryGroupID=%u!",
2289 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID
),
2291 return LDB_ERR_UNWILLING_TO_PERFORM
;
2294 if ((uac
& UF_PARTIAL_SECRETS_ACCOUNT
) && new_rid
!= DOMAIN_RID_READONLY_DCS
) {
2295 ldb_asprintf_errstring(ldb
,
2296 "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
2297 "primaryGroupID=%u!",
2298 W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID
),
2299 DOMAIN_RID_READONLY_DCS
);
2300 return LDB_ERR_UNWILLING_TO_PERFORM
;
2303 ret
= dsdb_module_search(ac
->module
, ac
, &group_res
,
2304 ldb_get_default_basedn(ldb
),
2306 noattrs
, search_flags
,
2309 ldap_encode_ndr_dom_sid(ac
, prev_sid
));
2310 if (ret
!= LDB_SUCCESS
) {
2313 if (group_res
->count
!= 1) {
2314 return ldb_operr(ldb
);
2316 prev_prim_group_dn
= group_res
->msgs
[0]->dn
;
2318 new_sid
= dom_sid_add_rid(ac
, samdb_domain_sid(ldb
), new_rid
);
2319 if (new_sid
== NULL
) {
2320 return ldb_operr(ldb
);
2323 ret
= dsdb_module_search(ac
->module
, ac
, &group_res
,
2324 ldb_get_default_basedn(ldb
),
2326 group_type_attrs
, search_flags
,
2329 ldap_encode_ndr_dom_sid(ac
, new_sid
));
2330 if (ret
!= LDB_SUCCESS
) {
2333 if (group_res
->count
!= 1) {
2334 /* Here we know if the specified new primary group candidate is
2336 return LDB_ERR_UNWILLING_TO_PERFORM
;
2338 new_prim_group_dn
= group_res
->msgs
[0]->dn
;
2340 /* The new primary group must not be domain-local. */
2341 group_type
= ldb_msg_find_attr_as_uint(group_res
->msgs
[0], "groupType", 0);
2342 if (group_type
& GROUP_TYPE_RESOURCE_GROUP
) {
2343 return dsdb_module_werror(ac
->module
,
2344 LDB_ERR_UNWILLING_TO_PERFORM
,
2345 WERR_MEMBER_NOT_IN_GROUP
,
2346 "may not set resource group as primary group!");
2349 new_prim_group_dn_ext_str
= ldb_dn_get_extended_linearized(ac
,
2350 new_prim_group_dn
, 1);
2351 if (new_prim_group_dn_ext_str
== NULL
) {
2352 return ldb_operr(ldb
);
2355 /* We need to be already a normal member of the new primary
2356 * group in order to be successful. */
2357 el
= samdb_find_attribute(ldb
, res
->msgs
[0], "memberOf",
2358 new_prim_group_dn_ext_str
);
2360 return LDB_ERR_UNWILLING_TO_PERFORM
;
2363 /* Remove the "member" attribute on the new primary group */
2364 msg
= ldb_msg_new(ac
->msg
);
2366 return ldb_module_oom(ac
->module
);
2368 msg
->dn
= new_prim_group_dn
;
2370 ret
= samdb_msg_add_delval(ldb
, msg
, msg
, "member", user_dn_ext_str
);
2371 if (ret
!= LDB_SUCCESS
) {
2375 ret
= dsdb_module_modify(ac
->module
, msg
, DSDB_FLAG_NEXT_MODULE
, ac
->req
);
2376 if (ret
!= LDB_SUCCESS
) {
2381 /* Add a "member" attribute for the previous primary group */
2382 msg
= ldb_msg_new(ac
->msg
);
2384 return ldb_module_oom(ac
->module
);
2386 msg
->dn
= prev_prim_group_dn
;
2388 ret
= samdb_msg_add_addval(ldb
, msg
, msg
, "member", user_dn_ext_str
);
2389 if (ret
!= LDB_SUCCESS
) {
2393 ret
= dsdb_module_modify(ac
->module
, msg
, DSDB_FLAG_NEXT_MODULE
, ac
->req
);
2394 if (ret
!= LDB_SUCCESS
) {
2402 static int samldb_prim_group_trigger(struct samldb_ctx
*ac
)
2406 if (ac
->req
->operation
== LDB_ADD
) {
2407 ret
= samldb_prim_group_set(ac
);
2409 ret
= samldb_prim_group_change(ac
);
2415 static int samldb_check_user_account_control_invariants(struct samldb_ctx
*ac
,
2416 uint32_t user_account_control
)
2420 bool need_check
= false;
2421 const struct uac_to_guid
{
2426 const char *error_string
;
2429 .uac
= UF_TEMP_DUPLICATE_ACCOUNT
,
2431 .error_string
= "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
2434 .uac
= UF_PARTIAL_SECRETS_ACCOUNT
,
2435 .needs
= UF_WORKSTATION_TRUST_ACCOUNT
,
2436 .error_string
= "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
2439 .uac
= UF_TRUSTED_FOR_DELEGATION
,
2440 .not_with
= UF_PARTIAL_SECRETS_ACCOUNT
,
2441 .error_string
= "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
2444 .uac
= UF_NORMAL_ACCOUNT
,
2445 .not_with
= UF_ACCOUNT_TYPE_MASK
& ~UF_NORMAL_ACCOUNT
,
2446 .error_string
= "Setting more than one account type not permitted"
2449 .uac
= UF_WORKSTATION_TRUST_ACCOUNT
,
2450 .not_with
= UF_ACCOUNT_TYPE_MASK
& ~UF_WORKSTATION_TRUST_ACCOUNT
,
2451 .error_string
= "Setting more than one account type not permitted"
2454 .uac
= UF_INTERDOMAIN_TRUST_ACCOUNT
,
2455 .not_with
= UF_ACCOUNT_TYPE_MASK
& ~UF_INTERDOMAIN_TRUST_ACCOUNT
,
2456 .error_string
= "Setting more than one account type not permitted"
2459 .uac
= UF_SERVER_TRUST_ACCOUNT
,
2460 .not_with
= UF_ACCOUNT_TYPE_MASK
& ~UF_SERVER_TRUST_ACCOUNT
,
2461 .error_string
= "Setting more than one account type not permitted"
2465 for (i
= 0; i
< ARRAY_SIZE(map
); i
++) {
2466 if (user_account_control
& map
[i
].uac
) {
2471 if (need_check
== false) {
2475 for (i
= 0; i
< ARRAY_SIZE(map
); i
++) {
2476 uint32_t this_uac
= user_account_control
& map
[i
].uac
;
2477 if (this_uac
!= 0) {
2479 ret
= LDB_ERR_OTHER
;
2481 } else if (map
[i
].needs
!= 0) {
2482 if ((map
[i
].needs
& user_account_control
) == 0) {
2483 ret
= LDB_ERR_OTHER
;
2486 } else if (map
[i
].not_with
!= 0) {
2487 if ((map
[i
].not_with
& user_account_control
) != 0) {
2488 ret
= LDB_ERR_OTHER
;
2494 if (ret
!= LDB_SUCCESS
) {
2495 switch (ac
->req
->operation
) {
2497 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
2498 "Failed to add %s: %s",
2499 ldb_dn_get_linearized(ac
->msg
->dn
),
2500 map
[i
].error_string
);
2503 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
2504 "Failed to modify %s: %s",
2505 ldb_dn_get_linearized(ac
->msg
->dn
),
2506 map
[i
].error_string
);
2509 return ldb_module_operr(ac
->module
);
2516 * It would be best if these rules apply, always, but for now they
2517 * apply only to non-admins
2519 static int samldb_check_user_account_control_objectclass_invariants(
2520 struct samldb_ctx
*ac
,
2521 uint32_t user_account_control
,
2522 uint32_t user_account_control_old
,
2523 bool is_computer_objectclass
)
2525 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2527 uint32_t old_ufa
= user_account_control_old
& UF_ACCOUNT_TYPE_MASK
;
2528 uint32_t new_ufa
= user_account_control
& UF_ACCOUNT_TYPE_MASK
;
2530 uint32_t old_rodc
= user_account_control_old
& UF_PARTIAL_SECRETS_ACCOUNT
;
2531 uint32_t new_rodc
= user_account_control
& UF_PARTIAL_SECRETS_ACCOUNT
;
2534 struct security_token
*user_token
2535 = acl_user_token(ac
->module
);
2536 if (user_token
== NULL
) {
2537 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
2541 = security_token_has_builtin_administrators(user_token
);
2545 * We want to allow changes to (eg) disable an account
2546 * that was created wrong, only checking the
2547 * objectclass if the account type changes.
2549 if (old_ufa
== new_ufa
&& old_rodc
== new_rodc
) {
2554 case UF_NORMAL_ACCOUNT
:
2555 if (is_computer_objectclass
&& !is_admin
) {
2556 ldb_asprintf_errstring(ldb
,
2557 "%08X: samldb: UF_NORMAL_ACCOUNT "
2558 "requires objectclass 'user' not 'computer'!",
2559 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
));
2560 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2564 case UF_INTERDOMAIN_TRUST_ACCOUNT
:
2565 if (is_computer_objectclass
) {
2566 ldb_asprintf_errstring(ldb
,
2567 "%08X: samldb: UF_INTERDOMAIN_TRUST_ACCOUNT "
2568 "requires objectclass 'user' not 'computer'!",
2569 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
));
2570 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2574 case UF_WORKSTATION_TRUST_ACCOUNT
:
2575 if (!is_computer_objectclass
) {
2577 * Modify of a user account account into a
2578 * workstation without objectclass computer
2579 * as an admin is still permitted, but not
2583 && ac
->req
->operation
== LDB_MODIFY
2587 ldb_asprintf_errstring(ldb
,
2588 "%08X: samldb: UF_WORKSTATION_TRUST_ACCOUNT "
2589 "requires objectclass 'computer'!",
2590 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
));
2591 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2595 case UF_SERVER_TRUST_ACCOUNT
:
2596 if (!is_computer_objectclass
) {
2597 ldb_asprintf_errstring(ldb
,
2598 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2599 "requires objectclass 'computer'!",
2600 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
));
2601 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
2606 ldb_asprintf_errstring(ldb
,
2607 "%08X: samldb: invalid userAccountControl[0x%08X]",
2608 W_ERROR_V(WERR_INVALID_PARAMETER
),
2609 user_account_control
);
2610 return LDB_ERR_OTHER
;
2615 static int samldb_get_domain_secdesc_and_oc(struct samldb_ctx
*ac
,
2616 struct security_descriptor
**domain_sd
,
2617 const struct dsdb_class
**objectclass
)
2619 const char * const sd_attrs
[] = {"ntSecurityDescriptor", "objectClass", NULL
};
2620 struct ldb_result
*res
;
2621 struct ldb_dn
*domain_dn
= ldb_get_default_basedn(ldb_module_get_ctx(ac
->module
));
2622 const struct dsdb_schema
*schema
= NULL
;
2623 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2624 int ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
,
2627 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
,
2629 if (ret
!= LDB_SUCCESS
) {
2632 if (res
->count
!= 1) {
2633 return ldb_module_operr(ac
->module
);
2636 schema
= dsdb_get_schema(ldb
, ac
->req
);
2638 return ldb_module_operr(ac
->module
);;
2640 *objectclass
= dsdb_get_structural_oc_from_msg(schema
, res
->msgs
[0]);
2641 return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac
->module
),
2642 ac
, res
->msgs
[0], domain_sd
);
2647 * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
2650 static int samldb_check_user_account_control_acl(struct samldb_ctx
*ac
,
2651 struct dom_sid
*sid
,
2652 uint32_t user_account_control
,
2653 uint32_t user_account_control_old
)
2657 bool need_acl_check
= false;
2658 struct security_token
*user_token
;
2659 struct security_descriptor
*domain_sd
;
2660 const struct dsdb_class
*objectclass
= NULL
;
2661 static const struct uac_to_guid
{
2663 uint32_t priv_to_change_from
;
2666 enum sec_privilege privilege
;
2667 bool delete_is_privileged
;
2668 bool admin_required
;
2669 const char *error_string
;
2672 .uac
= UF_PASSWD_NOTREQD
,
2673 .guid
= GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT
,
2674 .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"
2677 .uac
= UF_DONT_EXPIRE_PASSWD
,
2678 .guid
= GUID_DRS_UNEXPIRE_PASSWORD
,
2679 .error_string
= "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
2682 .uac
= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
,
2683 .guid
= GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD
,
2684 .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"
2687 .uac
= UF_SERVER_TRUST_ACCOUNT
,
2688 .guid
= GUID_DRS_DS_INSTALL_REPLICA
,
2689 .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"
2692 .uac
= UF_PARTIAL_SECRETS_ACCOUNT
,
2693 .guid
= GUID_DRS_DS_INSTALL_REPLICA
,
2694 .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"
2697 .uac
= UF_WORKSTATION_TRUST_ACCOUNT
,
2698 .priv_to_change_from
= UF_NORMAL_ACCOUNT
,
2699 .error_string
= "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
2702 .uac
= UF_NORMAL_ACCOUNT
,
2703 .priv_to_change_from
= UF_WORKSTATION_TRUST_ACCOUNT
,
2704 .error_string
= "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
2707 .uac
= UF_INTERDOMAIN_TRUST_ACCOUNT
,
2708 .oid
= DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID
,
2709 .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",
2710 .delete_is_privileged
= true
2713 .uac
= UF_TRUSTED_FOR_DELEGATION
,
2714 .privilege
= SEC_PRIV_ENABLE_DELEGATION
,
2715 .delete_is_privileged
= true,
2716 .error_string
= "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2719 .uac
= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
,
2720 .privilege
= SEC_PRIV_ENABLE_DELEGATION
,
2721 .delete_is_privileged
= true,
2722 .error_string
= "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2727 if (dsdb_module_am_system(ac
->module
)) {
2731 for (i
= 0; i
< ARRAY_SIZE(map
); i
++) {
2732 if (user_account_control
& map
[i
].uac
) {
2733 need_acl_check
= true;
2737 if (need_acl_check
== false) {
2741 user_token
= acl_user_token(ac
->module
);
2742 if (user_token
== NULL
) {
2743 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
2746 ret
= samldb_get_domain_secdesc_and_oc(ac
, &domain_sd
, &objectclass
);
2747 if (ret
!= LDB_SUCCESS
) {
2751 for (i
= 0; i
< ARRAY_SIZE(map
); i
++) {
2752 uint32_t this_uac_new
= user_account_control
& map
[i
].uac
;
2753 uint32_t this_uac_old
= user_account_control_old
& map
[i
].uac
;
2754 if (this_uac_new
!= this_uac_old
) {
2755 if (this_uac_old
!= 0) {
2756 if (map
[i
].delete_is_privileged
== false) {
2761 struct ldb_control
*control
= ldb_request_get_control(ac
->req
, map
[i
].oid
);
2762 if (control
== NULL
) {
2763 ret
= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
2765 } else if (map
[i
].privilege
!= SEC_PRIV_INVALID
) {
2766 bool have_priv
= security_token_has_privilege(user_token
,
2768 if (have_priv
== false) {
2769 ret
= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
2771 } else if (map
[i
].priv_to_change_from
& user_account_control_old
) {
2772 bool is_admin
= security_token_has_builtin_administrators(user_token
);
2773 if (is_admin
== false) {
2774 ret
= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
2776 } else if (map
[i
].guid
) {
2777 ret
= acl_check_extended_right(ac
,
2784 SEC_ADS_CONTROL_ACCESS
,
2789 if (ret
!= LDB_SUCCESS
) {
2794 if (ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
2795 switch (ac
->req
->operation
) {
2797 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
2798 "Failed to add %s: %s",
2799 ldb_dn_get_linearized(ac
->msg
->dn
),
2800 map
[i
].error_string
);
2803 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
2804 "Failed to modify %s: %s",
2805 ldb_dn_get_linearized(ac
->msg
->dn
),
2806 map
[i
].error_string
);
2809 return ldb_module_operr(ac
->module
);
2812 struct ldb_dn
*domain_dn
2813 = ldb_get_default_basedn(ldb_module_get_ctx(ac
->module
));
2814 dsdb_acl_debug(domain_sd
, acl_user_token(ac
->module
),
2823 static int samldb_check_user_account_control_rules(struct samldb_ctx
*ac
,
2824 struct dom_sid
*sid
,
2826 uint32_t user_account_control
,
2827 uint32_t user_account_control_old
,
2828 bool is_computer_objectclass
)
2831 struct dsdb_control_password_user_account_control
*uac
= NULL
;
2833 ret
= samldb_check_user_account_control_invariants(ac
, user_account_control
);
2834 if (ret
!= LDB_SUCCESS
) {
2837 ret
= samldb_check_user_account_control_objectclass_invariants(ac
,
2838 user_account_control
,
2839 user_account_control_old
,
2840 is_computer_objectclass
);
2841 if (ret
!= LDB_SUCCESS
) {
2845 ret
= samldb_check_user_account_control_acl(ac
, sid
, user_account_control
, user_account_control_old
);
2846 if (ret
!= LDB_SUCCESS
) {
2850 uac
= talloc_zero(ac
->req
,
2851 struct dsdb_control_password_user_account_control
);
2853 return ldb_module_oom(ac
->module
);
2856 uac
->req_flags
= req_uac
;
2857 uac
->old_flags
= user_account_control_old
;
2858 uac
->new_flags
= user_account_control
;
2860 ret
= ldb_request_add_control(ac
->req
,
2861 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID
,
2863 if (ret
!= LDB_SUCCESS
) {
2872 * This function is called on LDB modify operations. It performs some additions/
2873 * replaces on the current LDB message when "userAccountControl" changes.
2875 static int samldb_user_account_control_change(struct samldb_ctx
*ac
)
2877 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
2883 uint32_t old_uac_computed
;
2889 NTTIME old_lockoutTime
;
2890 struct ldb_message_element
*el
;
2891 struct ldb_val
*val
;
2892 struct ldb_val computer_val
;
2893 struct ldb_message
*tmp_msg
;
2894 struct dom_sid
*sid
;
2896 struct ldb_result
*res
;
2897 const char * const attrs
[] = {
2899 "isCriticalSystemObject",
2900 "userAccountControl",
2901 "msDS-User-Account-Control-Computed",
2906 bool is_computer_objectclass
= false;
2907 bool old_is_critical
= false;
2908 bool new_is_critical
= false;
2910 ret
= dsdb_get_expected_new_values(ac
,
2912 "userAccountControl",
2914 ac
->req
->operation
);
2915 if (ret
!= LDB_SUCCESS
) {
2919 if (el
== NULL
|| el
->num_values
== 0) {
2920 ldb_asprintf_errstring(ldb
,
2921 "%08X: samldb: 'userAccountControl' can't be deleted!",
2922 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
2923 return LDB_ERR_UNWILLING_TO_PERFORM
;
2926 /* Create a temporary message for fetching the "userAccountControl" */
2927 tmp_msg
= ldb_msg_new(ac
->msg
);
2928 if (tmp_msg
== NULL
) {
2929 return ldb_module_oom(ac
->module
);
2931 ret
= ldb_msg_add(tmp_msg
, el
, 0);
2932 if (ret
!= LDB_SUCCESS
) {
2935 raw_uac
= ldb_msg_find_attr_as_uint(tmp_msg
,
2936 "userAccountControl",
2938 talloc_free(tmp_msg
);
2940 * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2941 * are only generated and not stored. We ignore them almost
2942 * completely, along with unknown bits and UF_SCRIPT.
2944 * The only exception is ACB_AUTOLOCK, which features in
2945 * clear_acb when the bit is cleared in this modify operation.
2947 * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2948 * ignored by clients and servers
2950 new_uac
= raw_uac
& UF_SETTABLE_BITS
;
2952 /* Fetch the old "userAccountControl" and "objectClass" */
2953 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
, attrs
,
2954 DSDB_FLAG_NEXT_MODULE
, ac
->req
);
2955 if (ret
!= LDB_SUCCESS
) {
2958 old_uac
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "userAccountControl", 0);
2960 return ldb_operr(ldb
);
2962 old_uac_computed
= ldb_msg_find_attr_as_uint(res
->msgs
[0],
2963 "msDS-User-Account-Control-Computed", 0);
2964 old_lockoutTime
= ldb_msg_find_attr_as_int64(res
->msgs
[0],
2966 old_is_critical
= ldb_msg_find_attr_as_bool(res
->msgs
[0],
2967 "isCriticalSystemObject", 0);
2969 * When we do not have objectclass "computer" we cannot
2970 * switch to a workstation or (RO)DC
2972 el
= ldb_msg_find_element(res
->msgs
[0], "objectClass");
2974 return ldb_operr(ldb
);
2976 computer_val
= data_blob_string_const("computer");
2977 val
= ldb_msg_find_val(el
, &computer_val
);
2979 is_computer_objectclass
= true;
2982 old_ufa
= old_uac
& UF_ACCOUNT_TYPE_MASK
;
2983 old_atype
= ds_uf2atype(old_ufa
);
2984 old_pgrid
= ds_uf2prim_group_rid(old_uac
);
2986 new_ufa
= new_uac
& UF_ACCOUNT_TYPE_MASK
;
2989 * "userAccountControl" = 0 or missing one of the
2990 * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2991 * 3.1.1.8.10 point 8
2993 new_ufa
= UF_NORMAL_ACCOUNT
;
2996 sid
= samdb_result_dom_sid(res
, res
->msgs
[0], "objectSid");
2998 return ldb_module_operr(ac
->module
);
3001 ret
= samldb_check_user_account_control_rules(ac
, sid
,
3005 is_computer_objectclass
);
3006 if (ret
!= LDB_SUCCESS
) {
3010 new_atype
= ds_uf2atype(new_ufa
);
3011 new_pgrid
= ds_uf2prim_group_rid(new_uac
);
3013 clear_uac
= (old_uac
| old_uac_computed
) & ~raw_uac
;
3016 case UF_NORMAL_ACCOUNT
:
3017 new_is_critical
= old_is_critical
;
3020 case UF_INTERDOMAIN_TRUST_ACCOUNT
:
3021 new_is_critical
= true;
3024 case UF_WORKSTATION_TRUST_ACCOUNT
:
3025 new_is_critical
= false;
3026 if (new_uac
& UF_PARTIAL_SECRETS_ACCOUNT
) {
3027 new_is_critical
= true;
3031 case UF_SERVER_TRUST_ACCOUNT
:
3032 new_is_critical
= true;
3036 ldb_asprintf_errstring(ldb
,
3037 "%08X: samldb: invalid userAccountControl[0x%08X]",
3038 W_ERROR_V(WERR_INVALID_PARAMETER
), raw_uac
);
3039 return LDB_ERR_OTHER
;
3042 if (old_atype
!= new_atype
) {
3043 ret
= samdb_msg_append_uint(ldb
, ac
->msg
, ac
->msg
,
3044 "sAMAccountType", new_atype
,
3045 LDB_FLAG_MOD_REPLACE
);
3046 if (ret
!= LDB_SUCCESS
) {
3051 /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
3052 if ((clear_uac
& UF_LOCKOUT
) && (old_lockoutTime
!= 0)) {
3053 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
3054 ldb_msg_remove_attr(ac
->msg
, "lockoutTime");
3055 ret
= samdb_msg_append_uint64(ldb
, ac
->msg
, ac
->msg
, "lockoutTime",
3056 (NTTIME
)0, LDB_FLAG_MOD_REPLACE
);
3057 if (ret
!= LDB_SUCCESS
) {
3063 * "isCriticalSystemObject" might be set/changed
3065 * Even a change from UF_NORMAL_ACCOUNT (implicitly FALSE) to
3066 * UF_WORKSTATION_TRUST_ACCOUNT (actually FALSE) triggers
3067 * creating the attribute.
3069 if (old_is_critical
!= new_is_critical
|| old_atype
!= new_atype
) {
3070 ret
= ldb_msg_append_string(ac
->msg
, "isCriticalSystemObject",
3071 new_is_critical
? "TRUE": "FALSE",
3072 LDB_FLAG_MOD_REPLACE
);
3073 if (ret
!= LDB_SUCCESS
) {
3078 if (!ldb_msg_find_element(ac
->msg
, "primaryGroupID") &&
3079 (old_pgrid
!= new_pgrid
)) {
3080 /* Older AD deployments don't know about the RODC group */
3081 if (new_pgrid
== DOMAIN_RID_READONLY_DCS
) {
3082 ret
= samldb_prim_group_tester(ac
, new_pgrid
);
3083 if (ret
!= LDB_SUCCESS
) {
3088 ret
= samdb_msg_append_uint(ldb
, ac
->msg
, ac
->msg
,
3089 "primaryGroupID", new_pgrid
,
3090 LDB_FLAG_MOD_REPLACE
);
3091 if (ret
!= LDB_SUCCESS
) {
3096 /* Propagate eventual "userAccountControl" attribute changes */
3097 if (old_uac
!= new_uac
) {
3098 char *tempstr
= talloc_asprintf(ac
->msg
, "%d",
3100 if (tempstr
== NULL
) {
3101 return ldb_module_oom(ac
->module
);
3104 ret
= ldb_msg_add_empty(ac
->msg
,
3105 "userAccountControl",
3106 LDB_FLAG_MOD_REPLACE
,
3108 el
->values
= talloc(ac
->msg
, struct ldb_val
);
3110 el
->values
[0].data
= (uint8_t *) tempstr
;
3111 el
->values
[0].length
= strlen(tempstr
);
3113 ldb_msg_remove_attr(ac
->msg
, "userAccountControl");
3119 static int samldb_check_pwd_last_set_acl(struct samldb_ctx
*ac
,
3120 struct dom_sid
*sid
)
3122 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3124 struct security_token
*user_token
= NULL
;
3125 struct security_descriptor
*domain_sd
= NULL
;
3126 struct ldb_dn
*domain_dn
= ldb_get_default_basedn(ldb_module_get_ctx(ac
->module
));
3127 const char *operation
= "";
3128 const struct dsdb_class
*objectclass
= NULL
;
3130 if (dsdb_module_am_system(ac
->module
)) {
3134 switch (ac
->req
->operation
) {
3139 operation
= "modify";
3142 return ldb_module_operr(ac
->module
);
3145 user_token
= acl_user_token(ac
->module
);
3146 if (user_token
== NULL
) {
3147 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
3150 ret
= samldb_get_domain_secdesc_and_oc(ac
, &domain_sd
, &objectclass
);
3151 if (ret
!= LDB_SUCCESS
) {
3154 ret
= acl_check_extended_right(ac
,
3160 GUID_DRS_UNEXPIRE_PASSWORD
,
3161 SEC_ADS_CONTROL_ACCESS
,
3163 if (ret
!= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
3167 ldb_debug_set(ldb
, LDB_DEBUG_WARNING
,
3169 "Setting pwdLastSet to -1 requires the "
3170 "Unexpire-Password right that was not given "
3171 "on the Domain object",
3173 ldb_dn_get_linearized(ac
->msg
->dn
));
3174 dsdb_acl_debug(domain_sd
, user_token
,
3175 domain_dn
, true, 10);
3181 * This function is called on LDB modify operations. It performs some additions/
3182 * replaces on the current LDB message when "pwdLastSet" changes.
3184 static int samldb_pwd_last_set_change(struct samldb_ctx
*ac
)
3186 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3187 NTTIME last_set
= 0;
3188 struct ldb_message_element
*el
= NULL
;
3189 struct ldb_message
*tmp_msg
= NULL
;
3190 struct dom_sid
*self_sid
= NULL
;
3192 struct ldb_result
*res
= NULL
;
3193 const char * const attrs
[] = {
3198 ret
= dsdb_get_expected_new_values(ac
,
3202 ac
->req
->operation
);
3203 if (ret
!= LDB_SUCCESS
) {
3207 if (el
== NULL
|| el
->num_values
== 0) {
3208 ldb_asprintf_errstring(ldb
,
3209 "%08X: samldb: 'pwdLastSet' can't be deleted!",
3210 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
3211 return LDB_ERR_UNWILLING_TO_PERFORM
;
3214 /* Create a temporary message for fetching the "userAccountControl" */
3215 tmp_msg
= ldb_msg_new(ac
->msg
);
3216 if (tmp_msg
== NULL
) {
3217 return ldb_module_oom(ac
->module
);
3219 ret
= ldb_msg_add(tmp_msg
, el
, 0);
3220 if (ret
!= LDB_SUCCESS
) {
3223 last_set
= samdb_result_nttime(tmp_msg
, "pwdLastSet", 0);
3224 talloc_free(tmp_msg
);
3227 * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
3229 if (last_set
!= UINT64_MAX
) {
3233 /* Fetch the "objectSid" */
3234 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
, attrs
,
3235 DSDB_FLAG_NEXT_MODULE
, ac
->req
);
3236 if (ret
!= LDB_SUCCESS
) {
3239 self_sid
= samdb_result_dom_sid(res
, res
->msgs
[0], "objectSid");
3240 if (self_sid
== NULL
) {
3241 return ldb_module_operr(ac
->module
);
3244 ret
= samldb_check_pwd_last_set_acl(ac
, self_sid
);
3245 if (ret
!= LDB_SUCCESS
) {
3252 static int samldb_lockout_time(struct samldb_ctx
*ac
)
3254 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3256 struct ldb_message_element
*el
;
3257 struct ldb_message
*tmp_msg
;
3260 ret
= dsdb_get_expected_new_values(ac
,
3264 ac
->req
->operation
);
3265 if (ret
!= LDB_SUCCESS
) {
3269 if (el
== NULL
|| el
->num_values
== 0) {
3270 ldb_asprintf_errstring(ldb
,
3271 "%08X: samldb: 'lockoutTime' can't be deleted!",
3272 W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION
));
3273 return LDB_ERR_UNWILLING_TO_PERFORM
;
3276 /* Create a temporary message for fetching the "lockoutTime" */
3277 tmp_msg
= ldb_msg_new(ac
->msg
);
3278 if (tmp_msg
== NULL
) {
3279 return ldb_module_oom(ac
->module
);
3281 ret
= ldb_msg_add(tmp_msg
, el
, 0);
3282 if (ret
!= LDB_SUCCESS
) {
3285 lockoutTime
= ldb_msg_find_attr_as_int64(tmp_msg
,
3288 talloc_free(tmp_msg
);
3290 if (lockoutTime
!= 0) {
3294 /* lockoutTime == 0 resets badPwdCount */
3295 ldb_msg_remove_attr(ac
->msg
, "badPwdCount");
3296 ret
= samdb_msg_append_int(ldb
, ac
->msg
, ac
->msg
,
3298 LDB_FLAG_MOD_REPLACE
);
3299 if (ret
!= LDB_SUCCESS
) {
3306 static int samldb_group_type_change(struct samldb_ctx
*ac
)
3308 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3309 uint32_t group_type
, old_group_type
, account_type
;
3310 struct ldb_message_element
*el
;
3311 struct ldb_message
*tmp_msg
;
3313 struct ldb_result
*res
;
3314 const char * const attrs
[] = { "groupType", NULL
};
3316 ret
= dsdb_get_expected_new_values(ac
,
3320 ac
->req
->operation
);
3321 if (ret
!= LDB_SUCCESS
) {
3326 /* we are not affected */
3330 /* Create a temporary message for fetching the "groupType" */
3331 tmp_msg
= ldb_msg_new(ac
->msg
);
3332 if (tmp_msg
== NULL
) {
3333 return ldb_module_oom(ac
->module
);
3335 ret
= ldb_msg_add(tmp_msg
, el
, 0);
3336 if (ret
!= LDB_SUCCESS
) {
3339 group_type
= ldb_msg_find_attr_as_uint(tmp_msg
, "groupType", 0);
3340 talloc_free(tmp_msg
);
3342 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
, attrs
,
3343 DSDB_FLAG_NEXT_MODULE
|
3344 DSDB_SEARCH_SHOW_DELETED
, ac
->req
);
3345 if (ret
!= LDB_SUCCESS
) {
3348 old_group_type
= ldb_msg_find_attr_as_uint(res
->msgs
[0], "groupType", 0);
3349 if (old_group_type
== 0) {
3350 return ldb_operr(ldb
);
3353 /* Group type switching isn't so easy as it seems: We can only
3354 * change in this directions: global <-> universal <-> local
3355 * On each step also the group type itself
3356 * (security/distribution) is variable. */
3358 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_PROVISION_OID
) == NULL
) {
3359 switch (group_type
) {
3360 case GTYPE_SECURITY_GLOBAL_GROUP
:
3361 case GTYPE_DISTRIBUTION_GLOBAL_GROUP
:
3362 /* change to "universal" allowed */
3363 if ((old_group_type
== GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
) ||
3364 (old_group_type
== GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP
)) {
3365 ldb_set_errstring(ldb
,
3366 "samldb: Change from security/distribution local group forbidden!");
3367 return LDB_ERR_UNWILLING_TO_PERFORM
;
3371 case GTYPE_SECURITY_UNIVERSAL_GROUP
:
3372 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP
:
3373 /* each change allowed */
3375 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
:
3376 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP
:
3377 /* change to "universal" allowed */
3378 if ((old_group_type
== GTYPE_SECURITY_GLOBAL_GROUP
) ||
3379 (old_group_type
== GTYPE_DISTRIBUTION_GLOBAL_GROUP
)) {
3380 ldb_set_errstring(ldb
,
3381 "samldb: Change from security/distribution global group forbidden!");
3382 return LDB_ERR_UNWILLING_TO_PERFORM
;
3386 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
:
3388 /* we don't allow this "groupType" values */
3389 return LDB_ERR_UNWILLING_TO_PERFORM
;
3394 account_type
= ds_gtype2atype(group_type
);
3395 if (account_type
== 0) {
3396 ldb_set_errstring(ldb
, "samldb: Unrecognized account type!");
3397 return LDB_ERR_UNWILLING_TO_PERFORM
;
3399 ret
= samdb_msg_append_uint(ldb
, ac
->msg
, ac
->msg
, "sAMAccountType",
3400 account_type
, LDB_FLAG_MOD_REPLACE
);
3401 if (ret
!= LDB_SUCCESS
) {
3408 static int samldb_member_check(struct samldb_ctx
*ac
)
3410 const char * const attrs
[] = { "objectSid", NULL
};
3411 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3412 struct ldb_message_element
*el
;
3413 struct ldb_dn
*member_dn
;
3414 struct dom_sid
*sid
;
3415 struct ldb_result
*res
;
3416 struct dom_sid
*group_sid
;
3420 /* Fetch information from the existing object */
3422 ret
= dsdb_module_search(ac
->module
, ac
, &res
, ac
->msg
->dn
, LDB_SCOPE_BASE
, attrs
,
3423 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
, ac
->req
, NULL
);
3424 if (ret
!= LDB_SUCCESS
) {
3427 if (res
->count
!= 1) {
3428 return ldb_operr(ldb
);
3431 group_sid
= samdb_result_dom_sid(res
, res
->msgs
[0], "objectSid");
3432 if (group_sid
== NULL
) {
3433 return ldb_operr(ldb
);
3436 /* We've to walk over all modification entries and consider the "member"
3438 for (i
= 0; i
< ac
->msg
->num_elements
; i
++) {
3439 if (ldb_attr_cmp(ac
->msg
->elements
[i
].name
, "member") != 0) {
3443 el
= &ac
->msg
->elements
[i
];
3444 for (j
= 0; j
< el
->num_values
; j
++) {
3445 struct ldb_result
*group_res
;
3446 const char *group_attrs
[] = { "primaryGroupID" , NULL
};
3447 uint32_t prim_group_rid
;
3449 if (LDB_FLAG_MOD_TYPE(el
->flags
) == LDB_FLAG_MOD_DELETE
) {
3450 /* Deletes will be handled in
3451 * repl_meta_data, and deletes not
3452 * matching a member will return
3453 * LDB_ERR_UNWILLING_TO_PERFORM
3458 member_dn
= ldb_dn_from_ldb_val(ac
, ldb
,
3460 if (!ldb_dn_validate(member_dn
)) {
3461 return ldb_operr(ldb
);
3464 /* Denies to add "member"s to groups which are primary
3465 * ones for them - in this case return
3466 * ERR_ENTRY_ALREADY_EXISTS. */
3468 ret
= dsdb_module_search_dn(ac
->module
, ac
, &group_res
,
3469 member_dn
, group_attrs
,
3470 DSDB_FLAG_NEXT_MODULE
, ac
->req
);
3471 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
3472 /* member DN doesn't exist yet */
3475 if (ret
!= LDB_SUCCESS
) {
3478 prim_group_rid
= ldb_msg_find_attr_as_uint(group_res
->msgs
[0], "primaryGroupID", (uint32_t)-1);
3479 if (prim_group_rid
== (uint32_t) -1) {
3480 /* the member hasn't to be a user account ->
3481 * therefore no check needed in this case. */
3485 sid
= dom_sid_add_rid(ac
, samdb_domain_sid(ldb
),
3488 return ldb_operr(ldb
);
3491 if (dom_sid_equal(group_sid
, sid
)) {
3492 ldb_asprintf_errstring(ldb
,
3493 "samldb: member %s already set via primaryGroupID %u",
3494 ldb_dn_get_linearized(member_dn
), prim_group_rid
);
3495 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
3505 /* SAM objects have special rules regarding the "description" attribute on
3506 * modify operations. */
3507 static int samldb_description_check(struct samldb_ctx
*ac
, bool *modified
)
3509 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
3510 const char * const attrs
[] = { "objectClass", "description", NULL
};
3511 struct ldb_result
*res
;
3515 /* Fetch information from the existing object */
3516 ret
= dsdb_module_search(ac
->module
, ac
, &res
, ac
->msg
->dn
, LDB_SCOPE_BASE
, attrs
,
3517 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
, ac
->req
,
3518 "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
3519 if (ret
!= LDB_SUCCESS
) {
3520 /* don't treat it specially ... let normal error codes
3521 happen from other places */
3522 ldb_reset_err_string(ldb
);
3525 if (res
->count
== 0) {
3526 /* we didn't match the filter */
3531 /* We've to walk over all modification entries and consider the
3532 * "description" ones. */
3533 for (i
= 0; i
< ac
->msg
->num_elements
; i
++) {
3534 if (ldb_attr_cmp(ac
->msg
->elements
[i
].name
, "description") == 0) {
3535 ac
->msg
->elements
[i
].flags
|= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK
;
3545 #define SPN_ALIAS_NONE 0
3546 #define SPN_ALIAS_LINK 1
3547 #define SPN_ALIAS_TARGET 2
3549 static int find_spn_aliases(struct ldb_context
*ldb
,
3550 TALLOC_CTX
*mem_ctx
,
3551 const char *service_class
,
3557 * If you change the way this works, you should also look at changing
3558 * LDB_lookup_spn_alias() in source4/dsdb/samdb/cracknames.c, which
3559 * does some of the same work.
3561 * In particular, note that sPNMappings are resolved on a first come,
3562 * first served basis. For example, if we have
3568 * then 'ldap', 'cifs', and 'host' will resolve to 'host', and
3569 * 'alerter' will resolve to 'cifs'.
3571 * If this resolution method is made more complicated, then the
3572 * cracknames function should also be changed.
3577 struct ldb_result
*res
= NULL
;
3578 struct ldb_message_element
*spnmappings
= NULL
;
3579 TALLOC_CTX
*tmp_ctx
= NULL
;
3580 struct ldb_dn
*service_dn
= NULL
;
3582 const char *attrs
[] = {
3587 *direction
= SPN_ALIAS_NONE
;
3589 tmp_ctx
= talloc_new(mem_ctx
);
3590 if (tmp_ctx
== NULL
) {
3591 return ldb_oom(ldb
);
3594 service_dn
= ldb_dn_new(
3596 "CN=Directory Service,CN=Windows NT,CN=Services");
3597 if (service_dn
== NULL
) {
3598 talloc_free(tmp_ctx
);
3599 return ldb_oom(ldb
);
3602 ok
= ldb_dn_add_base(service_dn
, ldb_get_config_basedn(ldb
));
3604 talloc_free(tmp_ctx
);
3605 return LDB_ERR_OPERATIONS_ERROR
;
3608 ret
= ldb_search(ldb
, tmp_ctx
, &res
, service_dn
, LDB_SCOPE_BASE
,
3609 attrs
, "(objectClass=nTDSService)");
3611 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
3612 DBG_WARNING("sPNMappings not found.\n");
3613 talloc_free(tmp_ctx
);
3617 spnmappings
= ldb_msg_find_element(res
->msgs
[0], "sPNMappings");
3618 if (spnmappings
== NULL
|| spnmappings
->num_values
== 0) {
3619 DBG_WARNING("no sPNMappings attribute\n");
3620 talloc_free(tmp_ctx
);
3621 return LDB_ERR_NO_SUCH_OBJECT
;
3625 for (i
= 0; i
< spnmappings
->num_values
; i
++) {
3627 char *mapping
= talloc_strndup(
3629 (char *)spnmappings
->values
[i
].data
,
3630 spnmappings
->values
[i
].length
);
3631 if (mapping
== NULL
) {
3632 talloc_free(tmp_ctx
);
3633 return ldb_oom(ldb
);
3636 p
= strchr(mapping
, '=');
3638 talloc_free(tmp_ctx
);
3639 return LDB_ERR_ALIAS_PROBLEM
;
3644 if (strcasecmp(mapping
, service_class
) == 0) {
3646 * We need to return the reverse aliases for this one.
3648 * typically, this means the service_class is "host"
3649 * and the mapping is "host=alerter,appmgmt,cisvc,..",
3650 * so we get "alerter", "appmgmt", etc in the list of
3654 /* There is one more field than there are commas */
3657 for (j
= 0; p
[j
] != '\0'; j
++) {
3663 *aliases
= talloc_array(mem_ctx
, char*, n
);
3664 if (*aliases
== NULL
) {
3665 talloc_free(tmp_ctx
);
3666 return ldb_oom(ldb
);
3669 talloc_steal(mem_ctx
, mapping
);
3670 for (j
= 0; j
< n
; j
++) {
3674 talloc_free(tmp_ctx
);
3675 *direction
= SPN_ALIAS_LINK
;
3679 * We need to look along the list to see if service_class is
3680 * there; if so, we return a list of one item (probably "host").
3689 if (strcasecmp(str
, service_class
) == 0) {
3690 *aliases
= talloc_array(mem_ctx
, char*, 1);
3691 if (*aliases
== NULL
) {
3692 talloc_free(tmp_ctx
);
3693 return ldb_oom(ldb
);
3696 (*aliases
)[0] = mapping
;
3697 talloc_steal(mem_ctx
, mapping
);
3698 talloc_free(tmp_ctx
);
3699 *direction
= SPN_ALIAS_TARGET
;
3702 } while (p
!= NULL
);
3704 DBG_INFO("no sPNMappings alias for '%s'\n", service_class
);
3705 talloc_free(tmp_ctx
);
3712 static int get_spn_dn(struct ldb_context
*ldb
,
3713 TALLOC_CTX
*tmp_ctx
,
3714 const char *candidate
,
3718 const char *empty_attrs
[] = { NULL
};
3719 struct ldb_message
*msg
= NULL
;
3720 struct ldb_dn
*base_dn
= ldb_get_default_basedn(ldb
);
3722 const char *enc_candidate
= NULL
;
3726 enc_candidate
= ldb_binary_encode_string(tmp_ctx
, candidate
);
3727 if (enc_candidate
== NULL
) {
3728 return ldb_operr(ldb
);
3731 ret
= dsdb_search_one(ldb
,
3738 "(servicePrincipalName=%s)",
3740 if (ret
!= LDB_SUCCESS
) {
3748 static int check_spn_write_rights(struct ldb_context
*ldb
,
3749 TALLOC_CTX
*mem_ctx
,
3754 struct ldb_message
*msg
= NULL
;
3755 struct ldb_message_element
*del_el
= NULL
;
3756 struct ldb_message_element
*add_el
= NULL
;
3757 struct ldb_val val
= {
3758 .data
= discard_const_p(uint8_t, spn
),
3759 .length
= strlen(spn
)
3762 msg
= ldb_msg_new(mem_ctx
);
3764 return ldb_oom(ldb
);
3768 ret
= ldb_msg_add_empty(msg
,
3769 "servicePrincipalName",
3770 LDB_FLAG_MOD_DELETE
,
3772 if (ret
!= LDB_SUCCESS
) {
3777 del_el
->values
= talloc_array(msg
->elements
, struct ldb_val
, 1);
3778 if (del_el
->values
== NULL
) {
3783 del_el
->values
[0] = val
;
3784 del_el
->num_values
= 1;
3786 ret
= ldb_msg_add_empty(msg
,
3787 "servicePrincipalName",
3790 if (ret
!= LDB_SUCCESS
) {
3795 add_el
->values
= talloc_array(msg
->elements
, struct ldb_val
, 1);
3796 if (add_el
->values
== NULL
) {
3801 add_el
->values
[0] = val
;
3802 add_el
->num_values
= 1;
3804 ret
= ldb_modify(ldb
, msg
);
3805 if (ret
== LDB_ERR_NO_SUCH_ATTRIBUTE
) {
3806 DBG_ERR("hmm I think we're OK, but not sure\n");
3807 } else if (ret
!= LDB_SUCCESS
) {
3808 DBG_ERR("SPN write rights check failed with %d\n", ret
);
3817 static int check_spn_alias_collision(struct ldb_context
*ldb
,
3818 TALLOC_CTX
*mem_ctx
,
3820 struct ldb_dn
*target_dn
)
3823 char *service_class
= NULL
;
3824 char *spn_tail
= NULL
;
3826 char **aliases
= NULL
;
3827 size_t n_aliases
= 0;
3829 TALLOC_CTX
*tmp_ctx
= NULL
;
3830 const char *target_dnstr
= ldb_dn_get_linearized(target_dn
);
3833 tmp_ctx
= talloc_new(mem_ctx
);
3834 if (tmp_ctx
== NULL
) {
3835 return ldb_oom(ldb
);
3839 * "dns/example.com/xxx" gives
3840 * service_class = "dns"
3841 * spn_tail = "example.com/xxx"
3843 p
= strchr(spn
, '/');
3846 talloc_free(tmp_ctx
);
3847 return ldb_error(ldb
,
3848 LDB_ERR_OPERATIONS_ERROR
,
3849 "malformed servicePrincipalName");
3853 service_class
= talloc_strndup(tmp_ctx
, spn
, len
);
3854 if (service_class
== NULL
) {
3855 talloc_free(tmp_ctx
);
3856 return ldb_oom(ldb
);
3860 ret
= find_spn_aliases(ldb
,
3866 if (ret
!= LDB_SUCCESS
) {
3867 talloc_free(tmp_ctx
);
3872 * we have the list of aliases, and now we need to combined them with
3873 * spn_tail and see if we can find the SPN.
3875 for (i
= 0; i
< n_aliases
; i
++) {
3876 struct ldb_dn
*colliding_dn
= NULL
;
3877 const char *colliding_dnstr
= NULL
;
3879 char *candidate
= talloc_asprintf(tmp_ctx
,
3883 if (candidate
== NULL
) {
3884 talloc_free(tmp_ctx
);
3885 return ldb_oom(ldb
);
3888 ret
= get_spn_dn(ldb
, tmp_ctx
, candidate
, &colliding_dn
);
3889 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
3890 DBG_DEBUG("SPN alias '%s' not found (good)\n",
3892 talloc_free(candidate
);
3895 if (ret
!= LDB_SUCCESS
) {
3896 DBG_ERR("SPN '%s' search error %d\n", candidate
, ret
);
3897 talloc_free(tmp_ctx
);
3901 target_dnstr
= ldb_dn_get_linearized(target_dn
);
3903 * We have found an existing SPN that matches the alias. That
3904 * is OK only if it is on the object we are trying to add to,
3905 * or if the SPN on the other side is a more generic alias for
3906 * this one and we also have rights to modify it.
3908 * That is, we can put "host/X" and "cifs/X" on the same
3909 * object, but not on different objects, unless we put the
3910 * host/X on first, and could also change that object when we
3911 * add cifs/X. It is forbidden to add the objects in the other
3914 * The rationale for this is that adding "cifs/X" effectively
3915 * changes "host/X" by diverting traffic. If "host/X" can be
3916 * added after "cifs/X", a sneaky person could get "cifs/X" in
3917 * first, making "host/X" have less effect than intended.
3919 * Note: we also can't have "host/X" and "Host/X" on the same
3920 * object, but that is not relevant here.
3923 ret
= ldb_dn_compare(colliding_dn
, target_dn
);
3925 colliding_dnstr
= ldb_dn_get_linearized(colliding_dn
);
3926 DBG_ERR("trying to add SPN '%s' on '%s' when '%s' is "
3933 if (link_direction
== SPN_ALIAS_LINK
) {
3934 /* we don't allow host/X if there is a
3936 talloc_free(tmp_ctx
);
3937 return LDB_ERR_CONSTRAINT_VIOLATION
;
3939 ret
= check_spn_write_rights(ldb
,
3943 if (ret
!= LDB_SUCCESS
) {
3944 DBG_ERR("SPN '%s' is on '%s' so '%s' can't be "
3950 talloc_free(tmp_ctx
);
3951 ldb_asprintf_errstring(ldb
,
3952 "samldb: spn[%s] would cause a conflict",
3954 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
3957 DBG_INFO("SPNs '%s' and '%s' alias both on '%s'\n",
3958 candidate
, spn
, target_dnstr
);
3960 talloc_free(candidate
);
3963 talloc_free(tmp_ctx
);
3967 static int check_spn_direct_collision(struct ldb_context
*ldb
,
3968 TALLOC_CTX
*mem_ctx
,
3970 struct ldb_dn
*target_dn
)
3973 TALLOC_CTX
*tmp_ctx
= NULL
;
3974 struct ldb_dn
*colliding_dn
= NULL
;
3975 const char *target_dnstr
= NULL
;
3976 const char *colliding_dnstr
= NULL
;
3978 tmp_ctx
= talloc_new(mem_ctx
);
3979 if (tmp_ctx
== NULL
) {
3980 return ldb_oom(ldb
);
3983 ret
= get_spn_dn(ldb
, tmp_ctx
, spn
, &colliding_dn
);
3984 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
3985 DBG_DEBUG("SPN '%s' not found (good)\n", spn
);
3986 talloc_free(tmp_ctx
);
3989 if (ret
!= LDB_SUCCESS
) {
3990 DBG_ERR("SPN '%s' search error %d\n", spn
, ret
);
3991 talloc_free(tmp_ctx
);
3992 if (ret
== LDB_ERR_COMPARE_TRUE
) {
3994 * COMPARE_TRUE has special meaning here and we don't
3995 * want to return it by mistake.
3997 ret
= LDB_ERR_OPERATIONS_ERROR
;
4002 * We have found this exact SPN. This is mostly harmless (depend on
4003 * ADD vs REPLACE) when the spn is being put on the object that
4004 * already has, so we let it through to succeed or fail as some other
4007 target_dnstr
= ldb_dn_get_linearized(target_dn
);
4008 ret
= ldb_dn_compare(colliding_dn
, target_dn
);
4010 colliding_dnstr
= ldb_dn_get_linearized(colliding_dn
);
4011 DBG_ERR("SPN '%s' is on '%s' so it can't be "
4016 ldb_asprintf_errstring(ldb
,
4017 "samldb: spn[%s] would cause a conflict",
4019 talloc_free(tmp_ctx
);
4020 return LDB_ERR_CONSTRAINT_VIOLATION
;
4023 DBG_INFO("SPN '%s' is already on '%s'\n",
4025 talloc_free(tmp_ctx
);
4026 return LDB_ERR_COMPARE_TRUE
;
4030 static int count_spn_components(struct ldb_val val
)
4033 * a 3 part servicePrincipalName has two slashes, like
4034 * ldap/example.com/DomainDNSZones.example.com.
4036 * In krb5_parse_name_flags() we don't count "\/" as a slash (i.e.
4037 * escaped by a backslash), but this is not the behaviour of Windows
4038 * on setting a servicePrincipalName -- slashes are counted regardless
4041 * Accordingly, here we ignore backslashes. This will reject
4042 * multi-slash SPNs that krb5_parse_name_flags() would accept, and
4043 * allow ones in the form "a\/b" that it won't parse.
4047 for (i
= 0; i
< val
.length
; i
++) {
4048 char c
= val
.data
[i
];
4052 /* at this point we don't care */
4061 /* Check that "servicePrincipalName" changes do not introduce a collision
4063 static int samldb_spn_uniqueness_check(struct samldb_ctx
*ac
,
4064 struct ldb_message_element
*spn_el
)
4066 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
4068 const char *spn
= NULL
;
4070 TALLOC_CTX
*tmp_ctx
= talloc_new(ac
->msg
);
4071 if (tmp_ctx
== NULL
) {
4072 return ldb_oom(ldb
);
4075 for (i
= 0; i
< spn_el
->num_values
; i
++) {
4077 spn
= (char *)spn_el
->values
[i
].data
;
4079 n_components
= count_spn_components(spn_el
->values
[i
]);
4080 if (n_components
> 3 || n_components
< 2) {
4081 ldb_asprintf_errstring(ldb
,
4082 "samldb: spn[%s] invalid with %u components",
4084 talloc_free(tmp_ctx
);
4085 return LDB_ERR_CONSTRAINT_VIOLATION
;
4088 ret
= check_spn_direct_collision(ldb
,
4092 if (ret
== LDB_ERR_COMPARE_TRUE
) {
4093 DBG_INFO("SPN %s re-added to the same object\n", spn
);
4096 if (ret
!= LDB_SUCCESS
) {
4097 DBG_ERR("SPN %s failed direct uniqueness check\n", spn
);
4098 talloc_free(tmp_ctx
);
4102 ret
= check_spn_alias_collision(ldb
,
4107 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
4108 /* we have no sPNMappings, hence no aliases */
4111 if (ret
!= LDB_SUCCESS
) {
4112 DBG_ERR("SPN %s failed alias uniqueness check\n", spn
);
4113 talloc_free(tmp_ctx
);
4116 DBG_INFO("SPN %s seems to be unique\n", spn
);
4119 talloc_free(tmp_ctx
);
4125 /* This trigger adapts the "servicePrincipalName" attributes if the
4126 * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
4127 static int samldb_service_principal_names_change(struct samldb_ctx
*ac
)
4129 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
4130 struct ldb_message_element
*el
= NULL
, *el2
= NULL
;
4131 struct ldb_message
*msg
;
4132 const char * const attrs
[] = { "servicePrincipalName", NULL
};
4133 struct ldb_result
*res
;
4134 const char *dns_hostname
= NULL
, *old_dns_hostname
= NULL
,
4135 *sam_accountname
= NULL
, *old_sam_accountname
= NULL
;
4139 ret
= dsdb_get_expected_new_values(ac
,
4143 ac
->req
->operation
);
4144 if (ret
!= LDB_SUCCESS
) {
4147 ret
= dsdb_get_expected_new_values(ac
,
4151 ac
->req
->operation
);
4152 if (ret
!= LDB_SUCCESS
) {
4155 if ((el
== NULL
) && (el2
== NULL
)) {
4156 /* we are not affected */
4160 /* Create a temporary message for fetching the "dNSHostName" */
4162 const char *dns_attrs
[] = { "dNSHostName", NULL
};
4163 msg
= ldb_msg_new(ac
->msg
);
4165 return ldb_module_oom(ac
->module
);
4167 ret
= ldb_msg_add(msg
, el
, 0);
4168 if (ret
!= LDB_SUCCESS
) {
4171 dns_hostname
= talloc_strdup(ac
,
4172 ldb_msg_find_attr_as_string(msg
, "dNSHostName", NULL
));
4173 if (dns_hostname
== NULL
) {
4174 return ldb_module_oom(ac
->module
);
4179 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
,
4180 dns_attrs
, DSDB_FLAG_NEXT_MODULE
, ac
->req
);
4181 if (ret
== LDB_SUCCESS
) {
4182 old_dns_hostname
= ldb_msg_find_attr_as_string(res
->msgs
[0], "dNSHostName", NULL
);
4186 /* Create a temporary message for fetching the "sAMAccountName" */
4188 char *tempstr
, *tempstr2
= NULL
;
4189 const char *acct_attrs
[] = { "sAMAccountName", NULL
};
4191 msg
= ldb_msg_new(ac
->msg
);
4193 return ldb_module_oom(ac
->module
);
4195 ret
= ldb_msg_add(msg
, el2
, 0);
4196 if (ret
!= LDB_SUCCESS
) {
4199 tempstr
= talloc_strdup(ac
,
4200 ldb_msg_find_attr_as_string(msg
, "sAMAccountName", NULL
));
4203 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->msg
->dn
, acct_attrs
,
4204 DSDB_FLAG_NEXT_MODULE
, ac
->req
);
4205 if (ret
== LDB_SUCCESS
) {
4206 tempstr2
= talloc_strdup(ac
,
4207 ldb_msg_find_attr_as_string(res
->msgs
[0],
4208 "sAMAccountName", NULL
));
4212 /* The "sAMAccountName" needs some additional trimming: we need
4213 * to remove the trailing "$"s if they exist. */
4214 if ((tempstr
!= NULL
) && (tempstr
[0] != '\0') &&
4215 (tempstr
[strlen(tempstr
) - 1] == '$')) {
4216 tempstr
[strlen(tempstr
) - 1] = '\0';
4218 if ((tempstr2
!= NULL
) && (tempstr2
[0] != '\0') &&
4219 (tempstr2
[strlen(tempstr2
) - 1] == '$')) {
4220 tempstr2
[strlen(tempstr2
) - 1] = '\0';
4222 sam_accountname
= tempstr
;
4223 old_sam_accountname
= tempstr2
;
4226 if (old_dns_hostname
== NULL
) {
4227 /* we cannot change when the old name is unknown */
4228 dns_hostname
= NULL
;
4230 if ((old_dns_hostname
!= NULL
) && (dns_hostname
!= NULL
) &&
4231 (strcasecmp_m(old_dns_hostname
, dns_hostname
) == 0)) {
4232 /* The "dNSHostName" didn't change */
4233 dns_hostname
= NULL
;
4236 if (old_sam_accountname
== NULL
) {
4237 /* we cannot change when the old name is unknown */
4238 sam_accountname
= NULL
;
4240 if ((old_sam_accountname
!= NULL
) && (sam_accountname
!= NULL
) &&
4241 (strcasecmp_m(old_sam_accountname
, sam_accountname
) == 0)) {
4242 /* The "sAMAccountName" didn't change */
4243 sam_accountname
= NULL
;
4246 if ((dns_hostname
== NULL
) && (sam_accountname
== NULL
)) {
4247 /* Well, there are information missing (old name(s)) or the
4248 * names didn't change. We've nothing to do and can exit here */
4253 * Potential "servicePrincipalName" changes in the same request have
4254 * to be handled before the update (Windows behaviour).
4256 * We extract the SPN changes into a new message and run it through
4257 * the stack from this module, so that it subjects them to the SPN
4258 * checks we have here.
4260 el
= ldb_msg_find_element(ac
->msg
, "servicePrincipalName");
4262 msg
= ldb_msg_new(ac
->msg
);
4264 return ldb_module_oom(ac
->module
);
4266 msg
->dn
= ac
->msg
->dn
;
4269 ret
= ldb_msg_add(msg
, el
, el
->flags
);
4270 if (ret
!= LDB_SUCCESS
) {
4274 ldb_msg_remove_element(ac
->msg
, el
);
4276 el
= ldb_msg_find_element(ac
->msg
,
4277 "servicePrincipalName");
4278 } while (el
!= NULL
);
4280 ret
= dsdb_module_modify(ac
->module
, msg
,
4281 DSDB_FLAG_OWN_MODULE
, ac
->req
);
4282 if (ret
!= LDB_SUCCESS
) {
4288 /* Fetch the "servicePrincipalName"s if any */
4289 ret
= dsdb_module_search(ac
->module
, ac
, &res
, ac
->msg
->dn
, LDB_SCOPE_BASE
, attrs
,
4290 DSDB_FLAG_NEXT_MODULE
, ac
->req
, NULL
);
4291 if (ret
!= LDB_SUCCESS
) {
4294 if ((res
->count
!= 1) || (res
->msgs
[0]->num_elements
> 1)) {
4295 return ldb_operr(ldb
);
4298 if (res
->msgs
[0]->num_elements
== 1) {
4300 * Yes, we do have "servicePrincipalName"s. First we update them
4301 * locally, that means we do always substitute the current
4302 * "dNSHostName" with the new one and/or "sAMAccountName"
4303 * without "$" with the new one and then we append the
4304 * modified "servicePrincipalName"s as a message element
4305 * replace to the modification request (Windows behaviour). We
4306 * need also to make sure that the values remain case-
4307 * insensitively unique.
4310 ret
= ldb_msg_add_empty(ac
->msg
, "servicePrincipalName",
4311 LDB_FLAG_MOD_REPLACE
, &el
);
4312 if (ret
!= LDB_SUCCESS
) {
4316 for (i
= 0; i
< res
->msgs
[0]->elements
[0].num_values
; i
++) {
4317 char *old_str
, *new_str
;
4320 struct ldb_val
*vals
;
4324 res
->msgs
[0]->elements
[0].values
[i
].data
;
4326 new_str
= talloc_strdup(ac
->msg
,
4327 strtok_r(old_str
, "/", &pos
));
4328 if (new_str
== NULL
) {
4329 return ldb_module_oom(ac
->module
);
4332 while ((tok
= strtok_r(NULL
, "/", &pos
)) != NULL
) {
4333 if ((dns_hostname
!= NULL
) &&
4334 (strcasecmp_m(tok
, old_dns_hostname
) == 0)) {
4337 if ((sam_accountname
!= NULL
) &&
4338 (strcasecmp_m(tok
, old_sam_accountname
) == 0)) {
4339 tok
= sam_accountname
;
4342 new_str
= talloc_asprintf(ac
->msg
, "%s/%s",
4344 if (new_str
== NULL
) {
4345 return ldb_module_oom(ac
->module
);
4349 /* Uniqueness check */
4350 for (j
= 0; (!found
) && (j
< el
->num_values
); j
++) {
4351 if (strcasecmp_m((char *)el
->values
[j
].data
,
4361 * append the new "servicePrincipalName" -
4362 * code derived from ldb_msg_add_value().
4364 * Open coded to make it clear that we must
4365 * append to the MOD_REPLACE el created above.
4367 vals
= talloc_realloc(ac
->msg
, el
->values
,
4369 el
->num_values
+ 1);
4371 return ldb_module_oom(ac
->module
);
4374 el
->values
[el
->num_values
] = data_blob_string_const(new_str
);
4384 /* This checks the "fSMORoleOwner" attributes */
4385 static int samldb_fsmo_role_owner_check(struct samldb_ctx
*ac
)
4387 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
4388 const char * const no_attrs
[] = { NULL
};
4389 struct ldb_message_element
*el
;
4390 struct ldb_message
*tmp_msg
;
4391 struct ldb_dn
*res_dn
;
4392 struct ldb_result
*res
;
4394 ret
= dsdb_get_expected_new_values(ac
,
4398 ac
->req
->operation
);
4399 if (ret
!= LDB_SUCCESS
) {
4404 /* we are not affected */
4407 if (el
->num_values
!= 1) {
4408 goto choose_error_code
;
4411 /* Create a temporary message for fetching the "fSMORoleOwner" */
4412 tmp_msg
= ldb_msg_new(ac
->msg
);
4413 if (tmp_msg
== NULL
) {
4414 return ldb_module_oom(ac
->module
);
4416 ret
= ldb_msg_add(tmp_msg
, el
, 0);
4417 if (ret
!= LDB_SUCCESS
) {
4420 res_dn
= ldb_msg_find_attr_as_dn(ldb
, ac
, tmp_msg
, "fSMORoleOwner");
4421 talloc_free(tmp_msg
);
4423 if (res_dn
== NULL
) {
4424 ldb_set_errstring(ldb
,
4425 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
4426 goto choose_error_code
;
4429 /* Fetched DN has to reference a "nTDSDSA" entry */
4430 ret
= dsdb_module_search(ac
->module
, ac
, &res
, res_dn
, LDB_SCOPE_BASE
,
4432 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
,
4433 ac
->req
, "(objectClass=nTDSDSA)");
4434 if (ret
!= LDB_SUCCESS
) {
4437 if (res
->count
!= 1) {
4438 ldb_set_errstring(ldb
,
4439 "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
4440 return LDB_ERR_UNWILLING_TO_PERFORM
;
4448 /* this is just how it is */
4449 if (ac
->req
->operation
== LDB_ADD
) {
4450 return LDB_ERR_CONSTRAINT_VIOLATION
;
4452 return LDB_ERR_UNWILLING_TO_PERFORM
;
4457 * Return zero if the number of zero bits in the address (looking from low to
4458 * high) is equal to or greater than the length minus the mask. Otherwise it
4461 static int check_cidr_zero_bits(uint8_t *address
, unsigned int len
,
4464 /* <address> is an integer in big-endian form, <len> bits long. All
4465 bits between <mask> and <len> must be zero. */
4467 unsigned int byte_len
;
4468 unsigned int byte_mask
;
4469 unsigned int bit_mask
;
4471 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
4472 address
[0], address
[1], address
[2], address
[3],
4474 } else if (len
== 128){
4475 DBG_INFO("Looking at address "
4476 "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
4477 "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
4478 address
[0], address
[1], address
[2], address
[3],
4479 address
[4], address
[5], address
[6], address
[7],
4480 address
[8], address
[9], address
[10], address
[11],
4481 address
[12], address
[13], address
[14], address
[15],
4486 DBG_INFO("mask %u is too big (> %u)\n", mask
, len
);
4490 /* single address subnet.
4491 * In IPv4 all 255s is invalid by the bitmask != address rule
4492 * in MS-ADTS. IPv6 does not suffer.
4495 if (address
[0] == 255 &&
4496 address
[1] == 255 &&
4497 address
[2] == 255 &&
4506 byte_mask
= mask
/ 8;
4508 for (i
= byte_len
- 1; i
> byte_mask
; i
--){
4509 DBG_DEBUG("checking byte %d %02x\n", i
, address
[i
]);
4510 if (address
[i
] != 0){
4514 bit_mask
= (1 << (8 - (mask
& 7))) - 1;
4515 DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask
, address
[byte_mask
],
4516 bit_mask
& address
[byte_mask
]);
4517 if (address
[byte_mask
] & bit_mask
){
4521 /* According to MS-ADTS, the mask can't exactly equal the bitmask for
4522 * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
4523 * because the bitmask implied by "/17" is 255.255.80.0.
4525 * The bit_mask used in the previous check is the complement of what
4528 if (len
== 32 && address
[byte_mask
] == (uint8_t)~bit_mask
){
4530 for (i
= 0; i
< byte_mask
; i
++){
4531 if (address
[i
] != 255){
4545 static int check_address_roundtrip(const char *address
, int family
,
4546 const uint8_t *address_bytes
,
4547 char *buffer
, int buffer_len
)
4550 * Check that the address is in the canonical RFC5952 format for IPv6,
4551 * and lacks extra leading zeros for each dotted decimal for IPv4.
4552 * Handily this is what inet_ntop() gives you.
4554 const char *address_redux
= inet_ntop(family
, address_bytes
,
4555 buffer
, buffer_len
);
4556 if (address_redux
== NULL
){
4557 DBG_INFO("Address round trip %s failed unexpectedly"
4558 " with errno %d\n", address
, errno
);
4561 if (strcasecmp(address
, address_redux
) != 0){
4562 DBG_INFO("Address %s round trips to %s; fail!\n",
4563 address
, address_redux
);
4564 /* If the address family is IPv6, and the address is in a
4568 if (strchr(address_redux
, '.') != NULL
){
4569 DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
4570 "lying in a range that was once used for "
4571 "IPv4 embedding (that is, it might also be "
4572 "represented as '%s').\n", address
,
4583 * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
4584 * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
4585 * CIDR address range without saying so explicitly. Here we follow the CIDR
4588 * Return 0 on success, -1 on error.
4590 static int verify_cidr(const char *cidr
)
4592 char *address
= NULL
, *slash
= NULL
;
4593 bool has_colon
, has_dot
;
4596 uint8_t *address_bytes
= NULL
;
4597 char *address_redux
= NULL
;
4598 unsigned int address_len
;
4599 TALLOC_CTX
*frame
= NULL
;
4602 DBG_DEBUG("CIDR is %s\n", cidr
);
4603 frame
= talloc_stackframe();
4604 address
= talloc_strdup(frame
, cidr
);
4605 if (address
== NULL
){
4609 /* there must be a '/' */
4610 slash
= strchr(address
, '/');
4614 /* terminate the address for strchr, inet_pton */
4617 mask
= smb_strtoul(slash
+ 1, NULL
, 10, &error
, SMB_STR_FULL_STR_CONV
);
4619 DBG_INFO("Windows does not like the zero mask, "
4620 "so nor do we: %s\n", cidr
);
4625 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr
);
4629 address_bytes
= talloc_size(frame
, sizeof(struct in6_addr
));
4630 if (address_bytes
== NULL
){
4634 address_redux
= talloc_size(frame
, INET6_ADDRSTRLEN
);
4635 if (address_redux
== NULL
){
4639 DBG_INFO("found address %s, mask %lu\n", address
, mask
);
4640 has_colon
= (strchr(address
, ':') == NULL
) ? false : true;
4641 has_dot
= (strchr(address
, '.') == NULL
) ? false : true;
4642 if (has_dot
&& has_colon
){
4643 /* This seems to be an IPv4 address embedded in IPv6, which is
4644 icky. We don't support it. */
4645 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
4648 } else if (has_colon
){ /* looks like IPv6 */
4649 res
= inet_pton(AF_INET6
, address
, address_bytes
);
4651 DBG_INFO("Address in %s fails to parse as IPv6\n", cidr
);
4655 if (check_address_roundtrip(address
, AF_INET6
, address_bytes
,
4656 address_redux
, INET6_ADDRSTRLEN
)){
4659 } else if (has_dot
) {
4660 /* looks like IPv4 */
4661 if (strcmp(address
, "0.0.0.0") == 0){
4662 DBG_INFO("Windows does not like the zero IPv4 address, "
4666 res
= inet_pton(AF_INET
, address
, address_bytes
);
4668 DBG_INFO("Address in %s fails to parse as IPv4\n", cidr
);
4673 if (check_address_roundtrip(address
, AF_INET
, address_bytes
,
4674 address_redux
, INET_ADDRSTRLEN
)){
4678 /* This doesn't look like an IP address at all. */
4682 ret
= check_cidr_zero_bits(address_bytes
, address_len
, mask
);
4691 static int samldb_verify_subnet(struct samldb_ctx
*ac
, struct ldb_dn
*dn
)
4693 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
4694 const char *cidr
= NULL
;
4695 const struct ldb_val
*rdn_value
= NULL
;
4697 rdn_value
= ldb_dn_get_rdn_val(dn
);
4698 if (rdn_value
== NULL
) {
4699 ldb_set_errstring(ldb
, "samldb: ldb_dn_get_rdn_val "
4701 return LDB_ERR_UNWILLING_TO_PERFORM
;
4704 cidr
= ldb_dn_escape_value(ac
, *rdn_value
);
4705 DBG_INFO("looking at cidr '%s'\n", cidr
);
4707 ldb_set_errstring(ldb
,
4708 "samldb: adding an empty subnet cidr seems wrong");
4709 return LDB_ERR_UNWILLING_TO_PERFORM
;
4712 if (verify_cidr(cidr
)){
4713 ldb_set_errstring(ldb
,
4714 "samldb: subnet value is invalid");
4715 return LDB_ERR_INVALID_DN_SYNTAX
;
4721 static char *refer_if_rodc(struct ldb_context
*ldb
, struct ldb_request
*req
,
4725 struct loadparm_context
*lp_ctx
;
4730 if (ldb_request_get_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
) ||
4731 ldb_request_get_control(req
, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA
)) {
4735 ret
= samdb_rodc(ldb
, &rodc
);
4736 if (ret
!= LDB_SUCCESS
) {
4737 DEBUG(4, (__location__
": unable to tell if we are an RODC\n"));
4742 const char *domain
= NULL
;
4743 struct ldb_dn
*fsmo_role_dn
;
4744 struct ldb_dn
*role_owner_dn
;
4745 ldb_set_errstring(ldb
, "RODC modify is forbidden!");
4746 lp_ctx
= talloc_get_type(ldb_get_opaque(ldb
, "loadparm"),
4747 struct loadparm_context
);
4749 err
= dsdb_get_fsmo_role_info(req
, ldb
, DREPL_PDC_MASTER
,
4750 &fsmo_role_dn
, &role_owner_dn
);
4751 if (W_ERROR_IS_OK(err
)) {
4752 struct ldb_dn
*server_dn
= ldb_dn_copy(req
, role_owner_dn
);
4753 if (server_dn
!= NULL
) {
4754 ldb_dn_remove_child_components(server_dn
, 1);
4756 domain
= samdb_dn_to_dnshostname(ldb
, req
,
4760 if (domain
== NULL
) {
4761 domain
= lpcfg_dnsdomain(lp_ctx
);
4763 referral
= talloc_asprintf(req
,
4766 ldb_dn_get_linearized(dn
));
4774 * Restrict all access to sensitive attributes.
4776 * We don't want to even inspect the values, so we can use the same
4777 * routine for ADD and MODIFY.
4781 static int samldb_check_sensitive_attributes(struct samldb_ctx
*ac
)
4783 struct ldb_message_element
*el
= NULL
;
4784 struct security_token
*user_token
= NULL
;
4787 if (dsdb_module_am_system(ac
->module
)) {
4791 user_token
= acl_user_token(ac
->module
);
4792 if (user_token
== NULL
) {
4793 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
4796 el
= ldb_msg_find_element(ac
->msg
, "sidHistory");
4799 * sidHistory is restricted to the (not implemented
4800 * yet in Samba) DsAddSidHistory call (direct LDB access is
4801 * as SYSTEM so will bypass this).
4803 * If you want to modify this, say to merge domains,
4804 * directly modify the sam.ldb as root.
4806 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
4808 "(entry %s) cannot be created "
4809 "or changed over LDAP!",
4810 ldb_dn_get_linearized(ac
->msg
->dn
));
4811 return LDB_ERR_UNWILLING_TO_PERFORM
;
4814 el
= ldb_msg_find_element(ac
->msg
, "msDS-SecondaryKrbTgtNumber");
4816 struct security_descriptor
*domain_sd
;
4817 const struct dsdb_class
*objectclass
= NULL
;
4819 * msDS-SecondaryKrbTgtNumber allows the creator to
4820 * become an RODC, this is trusted as an RODC
4823 ret
= samldb_get_domain_secdesc_and_oc(ac
, &domain_sd
, &objectclass
);
4824 if (ret
!= LDB_SUCCESS
) {
4827 ret
= acl_check_extended_right(ac
,
4833 GUID_DRS_DS_INSTALL_REPLICA
,
4834 SEC_ADS_CONTROL_ACCESS
,
4836 if (ret
!= LDB_SUCCESS
) {
4837 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
4838 "msDS-SecondaryKrbTgtNumber "
4839 "(entry %s) cannot be created "
4840 "or changed without "
4841 "DS-Install-Replica extended right!",
4842 ldb_dn_get_linearized(ac
->msg
->dn
));
4847 el
= ldb_msg_find_element(ac
->msg
, "msDS-AllowedToDelegateTo");
4850 * msDS-AllowedToDelegateTo is incredibly powerful,
4851 * given that it allows a server to become ANY USER on
4852 * the target server only listed by SPN so needs to be
4853 * protected just as the userAccountControl
4854 * UF_TRUSTED_FOR_DELEGATION is.
4857 bool have_priv
= security_token_has_privilege(user_token
,
4858 SEC_PRIV_ENABLE_DELEGATION
);
4859 if (have_priv
== false) {
4860 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
4861 "msDS-AllowedToDelegateTo "
4862 "(entry %s) cannot be created "
4863 "or changed without SePrivEnableDelegation!",
4864 ldb_dn_get_linearized(ac
->msg
->dn
));
4865 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
4871 static int samldb_add(struct ldb_module
*module
, struct ldb_request
*req
)
4873 struct ldb_context
*ldb
;
4874 struct samldb_ctx
*ac
;
4875 struct ldb_message_element
*el
;
4877 char *referral
= NULL
;
4879 ldb
= ldb_module_get_ctx(module
);
4880 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "samldb_add\n");
4882 /* do not manipulate our control entries */
4883 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
4884 return ldb_next_request(module
, req
);
4887 referral
= refer_if_rodc(ldb
, req
, req
->op
.add
.message
->dn
);
4888 if (referral
!= NULL
) {
4889 ret
= ldb_module_send_referral(req
, referral
);
4893 el
= ldb_msg_find_element(req
->op
.add
.message
, "userParameters");
4894 if (el
!= NULL
&& ldb_req_is_untrusted(req
)) {
4895 const char *reason
= "samldb_add: "
4896 "setting userParameters is not supported over LDAP, "
4897 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
4898 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "%s", reason
);
4899 return ldb_error(ldb
, LDB_ERR_CONSTRAINT_VIOLATION
, reason
);
4902 ac
= samldb_ctx_init(module
, req
);
4904 return ldb_operr(ldb
);
4907 /* build the new msg */
4908 ac
->msg
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
4909 if (ac
->msg
== NULL
) {
4911 ldb_debug(ldb
, LDB_DEBUG_FATAL
,
4912 "samldb_add: ldb_msg_copy_shallow failed!\n");
4913 return ldb_operr(ldb
);
4916 ret
= samldb_check_sensitive_attributes(ac
);
4917 if (ret
!= LDB_SUCCESS
) {
4922 el
= ldb_msg_find_element(ac
->msg
, "fSMORoleOwner");
4924 ret
= samldb_fsmo_role_owner_check(ac
);
4925 if (ret
!= LDB_SUCCESS
) {
4930 el
= ldb_msg_find_element(ac
->msg
, "servicePrincipalName");
4933 * We need to check whether the SPN collides with an existing
4934 * one (anywhere) including via aliases.
4936 ret
= samldb_spn_uniqueness_check(ac
, el
);
4937 if (ret
!= LDB_SUCCESS
) {
4942 if (samdb_find_attribute(ldb
, ac
->msg
,
4943 "objectclass", "user") != NULL
) {
4944 ac
->type
= SAMLDB_TYPE_USER
;
4946 ret
= samldb_prim_group_trigger(ac
);
4947 if (ret
!= LDB_SUCCESS
) {
4951 ret
= samldb_objectclass_trigger(ac
);
4952 if (ret
!= LDB_SUCCESS
) {
4956 return samldb_fill_object(ac
);
4959 if (samdb_find_attribute(ldb
, ac
->msg
,
4960 "objectclass", "group") != NULL
) {
4961 ac
->type
= SAMLDB_TYPE_GROUP
;
4963 ret
= samldb_objectclass_trigger(ac
);
4964 if (ret
!= LDB_SUCCESS
) {
4968 return samldb_fill_object(ac
);
4971 /* perhaps a foreignSecurityPrincipal? */
4972 if (samdb_find_attribute(ldb
, ac
->msg
,
4974 "foreignSecurityPrincipal") != NULL
) {
4975 return samldb_fill_foreignSecurityPrincipal_object(ac
);
4978 if (samdb_find_attribute(ldb
, ac
->msg
,
4979 "objectclass", "classSchema") != NULL
) {
4980 ac
->type
= SAMLDB_TYPE_CLASS
;
4982 /* If in provision, these checks are too slow to do */
4983 if (!ldb_request_get_control(req
, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID
)) {
4984 ret
= samldb_schema_governsid_valid_check(ac
);
4985 if (ret
!= LDB_SUCCESS
) {
4990 ret
= samldb_schema_ldapdisplayname_valid_check(ac
);
4991 if (ret
!= LDB_SUCCESS
) {
4995 ret
= samldb_schema_info_update(ac
);
4996 if (ret
!= LDB_SUCCESS
) {
5001 return samldb_fill_object(ac
);
5004 if (samdb_find_attribute(ldb
, ac
->msg
,
5005 "objectclass", "attributeSchema") != NULL
) {
5006 ac
->type
= SAMLDB_TYPE_ATTRIBUTE
;
5008 /* If in provision, these checks are too slow to do */
5009 if (!ldb_request_get_control(req
, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID
)) {
5010 ret
= samldb_schema_attributeid_valid_check(ac
);
5011 if (ret
!= LDB_SUCCESS
) {
5015 ret
= samldb_schema_add_handle_linkid(ac
);
5016 if (ret
!= LDB_SUCCESS
) {
5020 ret
= samldb_schema_add_handle_mapiid(ac
);
5021 if (ret
!= LDB_SUCCESS
) {
5026 ret
= samldb_schema_ldapdisplayname_valid_check(ac
);
5027 if (ret
!= LDB_SUCCESS
) {
5031 ret
= samldb_schema_info_update(ac
);
5032 if (ret
!= LDB_SUCCESS
) {
5037 return samldb_fill_object(ac
);
5040 if (samdb_find_attribute(ldb
, ac
->msg
,
5041 "objectclass", "subnet") != NULL
) {
5042 ret
= samldb_verify_subnet(ac
, ac
->msg
->dn
);
5043 if (ret
!= LDB_SUCCESS
) {
5047 /* We are just checking the value is valid, and there are no
5048 values to fill in. */
5053 /* nothing matched, go on */
5054 return ldb_next_request(module
, req
);
5058 static int samldb_modify(struct ldb_module
*module
, struct ldb_request
*req
)
5060 struct ldb_context
*ldb
;
5061 struct samldb_ctx
*ac
;
5062 struct ldb_message_element
*el
, *el2
;
5063 struct ldb_control
*is_undelete
;
5064 bool modified
= false;
5067 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
5068 /* do not manipulate our control entries */
5069 return ldb_next_request(module
, req
);
5072 ldb
= ldb_module_get_ctx(module
);
5075 * we are going to need some special handling if in Undelete call.
5076 * Since tombstone_reanimate module will restore certain attributes,
5077 * we need to relax checks for: sAMAccountType, primaryGroupID
5079 is_undelete
= ldb_request_get_control(req
, DSDB_CONTROL_RESTORE_TOMBSTONE_OID
);
5081 /* make sure that "objectSid" is not specified */
5082 el
= ldb_msg_find_element(req
->op
.mod
.message
, "objectSid");
5084 if (ldb_request_get_control(req
, LDB_CONTROL_PROVISION_OID
) == NULL
) {
5085 ldb_set_errstring(ldb
,
5086 "samldb: objectSid must not be specified!");
5087 return LDB_ERR_UNWILLING_TO_PERFORM
;
5090 if (is_undelete
== NULL
) {
5091 /* make sure that "sAMAccountType" is not specified */
5092 el
= ldb_msg_find_element(req
->op
.mod
.message
, "sAMAccountType");
5094 ldb_set_errstring(ldb
,
5095 "samldb: sAMAccountType must not be specified!");
5096 return LDB_ERR_UNWILLING_TO_PERFORM
;
5099 /* make sure that "isCriticalSystemObject" is not specified */
5100 el
= ldb_msg_find_element(req
->op
.mod
.message
, "isCriticalSystemObject");
5102 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
) == NULL
) {
5103 ldb_set_errstring(ldb
,
5104 "samldb: isCriticalSystemObject must not be specified!");
5105 return LDB_ERR_UNWILLING_TO_PERFORM
;
5109 /* msDS-IntId is not allowed to be modified
5110 * except when modification comes from replication */
5111 if (ldb_msg_find_element(req
->op
.mod
.message
, "msDS-IntId")) {
5112 if (!ldb_request_get_control(req
,
5113 DSDB_CONTROL_REPLICATED_UPDATE_OID
)) {
5114 return LDB_ERR_CONSTRAINT_VIOLATION
;
5118 el
= ldb_msg_find_element(req
->op
.mod
.message
, "userParameters");
5119 if (el
!= NULL
&& ldb_req_is_untrusted(req
)) {
5120 const char *reason
= "samldb: "
5121 "setting userParameters is not supported over LDAP, "
5122 "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
5123 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "%s", reason
);
5124 return ldb_error(ldb
, LDB_ERR_CONSTRAINT_VIOLATION
, reason
);
5127 ac
= samldb_ctx_init(module
, req
);
5129 return ldb_operr(ldb
);
5132 /* build the new msg */
5133 ac
->msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
5134 if (ac
->msg
== NULL
) {
5136 ldb_debug(ldb
, LDB_DEBUG_FATAL
,
5137 "samldb_modify: ldb_msg_copy_shallow failed!\n");
5138 return ldb_operr(ldb
);
5141 ret
= samldb_check_sensitive_attributes(ac
);
5142 if (ret
!= LDB_SUCCESS
) {
5147 if (is_undelete
== NULL
) {
5148 el
= ldb_msg_find_element(ac
->msg
, "primaryGroupID");
5150 ret
= samldb_prim_group_trigger(ac
);
5151 if (ret
!= LDB_SUCCESS
) {
5157 el
= ldb_msg_find_element(ac
->msg
, "userAccountControl");
5160 ret
= samldb_user_account_control_change(ac
);
5161 if (ret
!= LDB_SUCCESS
) {
5166 el
= ldb_msg_find_element(ac
->msg
, "pwdLastSet");
5169 ret
= samldb_pwd_last_set_change(ac
);
5170 if (ret
!= LDB_SUCCESS
) {
5175 el
= ldb_msg_find_element(ac
->msg
, "lockoutTime");
5178 ret
= samldb_lockout_time(ac
);
5179 if (ret
!= LDB_SUCCESS
) {
5184 el
= ldb_msg_find_element(ac
->msg
, "groupType");
5187 ret
= samldb_group_type_change(ac
);
5188 if (ret
!= LDB_SUCCESS
) {
5193 el
= ldb_msg_find_element(ac
->msg
, "sAMAccountName");
5195 uint32_t user_account_control
;
5196 struct ldb_result
*res
= NULL
;
5197 const char * const attrs
[] = { "userAccountControl",
5200 ret
= dsdb_module_search_dn(ac
->module
,
5205 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
,
5207 if (ret
!= LDB_SUCCESS
) {
5210 user_account_control
5211 = ldb_msg_find_attr_as_uint(res
->msgs
[0],
5212 "userAccountControl",
5215 if ((user_account_control
5216 & UF_TRUST_ACCOUNT_MASK
) != 0) {
5217 ac
->need_trailing_dollar
= true;
5219 } else if (samdb_find_attribute(ldb
,
5224 ac
->need_trailing_dollar
= true;
5227 ret
= samldb_sam_accountname_valid_check(ac
);
5228 if (ret
!= LDB_SUCCESS
) {
5233 el
= ldb_msg_find_element(ac
->msg
, "userPrincipalName");
5235 ret
= samldb_sam_account_upn_clash(ac
);
5236 if (ret
!= LDB_SUCCESS
) {
5242 el
= ldb_msg_find_element(ac
->msg
, "ldapDisplayName");
5244 ret
= samldb_schema_ldapdisplayname_valid_check(ac
);
5245 if (ret
!= LDB_SUCCESS
) {
5250 el
= ldb_msg_find_element(ac
->msg
, "attributeID");
5252 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
5253 "Once set, attributeID values may not be modified");
5254 return LDB_ERR_CONSTRAINT_VIOLATION
;
5257 el
= ldb_msg_find_element(ac
->msg
, "governsID");
5259 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
5260 "Once set, governsID values may not be modified");
5261 return LDB_ERR_CONSTRAINT_VIOLATION
;
5264 el
= ldb_msg_find_element(ac
->msg
, "member");
5266 struct ldb_control
*fix_link_sid_ctrl
= NULL
;
5268 fix_link_sid_ctrl
= ldb_request_get_control(ac
->req
,
5269 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID
);
5270 if (fix_link_sid_ctrl
== NULL
) {
5271 ret
= samldb_member_check(ac
);
5272 if (ret
!= LDB_SUCCESS
) {
5278 el
= ldb_msg_find_element(ac
->msg
, "description");
5280 ret
= samldb_description_check(ac
, &modified
);
5281 if (ret
!= LDB_SUCCESS
) {
5286 el
= ldb_msg_find_element(ac
->msg
, "dNSHostName");
5287 el2
= ldb_msg_find_element(ac
->msg
, "sAMAccountName");
5288 if ((el
!= NULL
) || (el2
!= NULL
)) {
5291 * samldb_service_principal_names_change() might add SPN
5292 * changes to the request, so this must come before the SPN
5293 * uniqueness check below.
5295 * Note we ALSO have to do the SPN uniqueness check inside
5296 * samldb_service_principal_names_change(), because it does a
5297 * subrequest to do requested SPN modifications *before* its
5298 * automatic ones are added.
5300 ret
= samldb_service_principal_names_change(ac
);
5301 if (ret
!= LDB_SUCCESS
) {
5306 el
= ldb_msg_find_element(ac
->msg
, "servicePrincipalName");
5309 * We need to check whether the SPN collides with an existing
5310 * one (anywhere) including via aliases.
5313 ret
= samldb_spn_uniqueness_check(ac
, el
);
5314 if (ret
!= LDB_SUCCESS
) {
5319 el
= ldb_msg_find_element(ac
->msg
, "fSMORoleOwner");
5321 ret
= samldb_fsmo_role_owner_check(ac
);
5322 if (ret
!= LDB_SUCCESS
) {
5328 struct ldb_request
*child_req
;
5330 /* Now perform the real modifications as a child request */
5331 ret
= ldb_build_mod_req(&child_req
, ldb
, ac
,
5334 req
, dsdb_next_callback
,
5336 LDB_REQ_SET_LOCATION(child_req
);
5337 if (ret
!= LDB_SUCCESS
) {
5341 return ldb_next_request(module
, child_req
);
5346 /* no change which interests us, go on */
5347 return ldb_next_request(module
, req
);
5352 static int samldb_prim_group_users_check(struct samldb_ctx
*ac
)
5354 struct ldb_context
*ldb
;
5355 struct dom_sid
*sid
;
5359 struct ldb_result
*res
= NULL
;
5360 struct ldb_result
*res_users
= NULL
;
5361 const char * const attrs
[] = { "objectSid", "isDeleted", NULL
};
5362 const char * const noattrs
[] = { NULL
};
5364 ldb
= ldb_module_get_ctx(ac
->module
);
5366 /* Finds out the SID/RID of the SAM object */
5367 ret
= dsdb_module_search_dn(ac
->module
, ac
, &res
, ac
->req
->op
.del
.dn
,
5369 DSDB_FLAG_NEXT_MODULE
| DSDB_SEARCH_SHOW_DELETED
,
5371 if (ret
!= LDB_SUCCESS
) {
5375 if (ldb_msg_check_string_attribute(res
->msgs
[0], "isDeleted", "TRUE")) {
5379 sid
= samdb_result_dom_sid(ac
, res
->msgs
[0], "objectSid");
5381 /* No SID - it might not be a SAM object - therefore ok */
5384 status
= dom_sid_split_rid(ac
, sid
, NULL
, &rid
);
5385 if (!NT_STATUS_IS_OK(status
)) {
5386 return ldb_operr(ldb
);
5389 /* Special object (security principal?) */
5392 /* do not allow deletion of well-known sids */
5393 if (rid
< DSDB_SAMDB_MINIMUM_ALLOWED_RID
&&
5394 (ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
) == NULL
)) {
5395 return LDB_ERR_OTHER
;
5398 /* Deny delete requests from groups which are primary ones */
5399 ret
= dsdb_module_search(ac
->module
, ac
, &res_users
,
5400 ldb_get_default_basedn(ldb
),
5401 LDB_SCOPE_SUBTREE
, noattrs
,
5402 DSDB_FLAG_NEXT_MODULE
,
5404 "(&(primaryGroupID=%u)(objectClass=user))", rid
);
5405 if (ret
!= LDB_SUCCESS
) {
5408 if (res_users
->count
> 0) {
5409 ldb_asprintf_errstring(ldb_module_get_ctx(ac
->module
),
5410 "Refusing to delete %s, as it "
5411 "is still the primaryGroupID "
5413 ldb_dn_get_linearized(res
->msgs
[0]->dn
),
5417 * Yes, this seems very wrong, but we have a test
5418 * for this exact error code in sam.py
5420 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
5426 static int samldb_delete(struct ldb_module
*module
, struct ldb_request
*req
)
5428 struct samldb_ctx
*ac
;
5429 char *referral
= NULL
;
5431 struct ldb_context
*ldb
;
5433 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
5434 /* do not manipulate our control entries */
5435 return ldb_next_request(module
, req
);
5438 ldb
= ldb_module_get_ctx(module
);
5440 referral
= refer_if_rodc(ldb
, req
, req
->op
.del
.dn
);
5441 if (referral
!= NULL
) {
5442 ret
= ldb_module_send_referral(req
, referral
);
5446 ac
= samldb_ctx_init(module
, req
);
5448 return ldb_operr(ldb_module_get_ctx(module
));
5451 ret
= samldb_prim_group_users_check(ac
);
5452 if (ret
!= LDB_SUCCESS
) {
5458 return ldb_next_request(module
, req
);
5463 static int check_rename_constraints(struct ldb_message
*msg
,
5464 struct samldb_ctx
*ac
,
5465 struct ldb_dn
*olddn
, struct ldb_dn
*newdn
)
5467 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
5468 struct ldb_dn
*dn1
, *dn2
, *nc_root
;
5469 int32_t systemFlags
;
5470 bool move_op
= false;
5471 bool rename_op
= false;
5474 /* Skip the checks if old and new DN are the same, or if we have the
5475 * relax control specified or if the returned objects is already
5476 * deleted and needs only to be moved for consistency. */
5478 if (ldb_dn_compare(olddn
, newdn
) == 0) {
5481 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
) != NULL
) {
5485 if (ldb_msg_find_attr_as_bool(msg
, "isDeleted", false)) {
5487 * check originating request if we are supposed
5488 * to "see" this record in first place.
5490 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_SHOW_DELETED_OID
) == NULL
) {
5491 return LDB_ERR_NO_SUCH_OBJECT
;
5493 return LDB_ERR_UNWILLING_TO_PERFORM
;
5496 /* Objects under CN=System */
5498 dn1
= samdb_system_container_dn(ldb
, ac
);
5499 if (dn1
== NULL
) return ldb_oom(ldb
);
5501 if ((ldb_dn_compare_base(dn1
, olddn
) == 0) &&
5502 (ldb_dn_compare_base(dn1
, newdn
) != 0)) {
5504 ldb_asprintf_errstring(ldb
,
5505 "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
5506 ldb_dn_get_linearized(olddn
));
5507 return LDB_ERR_OTHER
;
5514 if ((samdb_find_attribute(ldb
, msg
, "objectClass", "secret") != NULL
) ||
5515 (samdb_find_attribute(ldb
, msg
, "objectClass", "trustedDomain") != NULL
)) {
5516 ldb_asprintf_errstring(ldb
,
5517 "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
5518 ldb_dn_get_linearized(olddn
));
5519 return LDB_ERR_UNWILLING_TO_PERFORM
;
5522 /* subnet objects */
5523 if (samdb_find_attribute(ldb
, msg
, "objectclass", "subnet") != NULL
) {
5524 ret
= samldb_verify_subnet(ac
, newdn
);
5525 if (ret
!= LDB_SUCCESS
) {
5532 dn1
= ldb_dn_get_parent(ac
, olddn
);
5533 if (dn1
== NULL
) return ldb_oom(ldb
);
5534 dn2
= ldb_dn_get_parent(ac
, newdn
);
5535 if (dn2
== NULL
) return ldb_oom(ldb
);
5537 if (ldb_dn_compare(dn1
, dn2
) == 0) {
5546 systemFlags
= ldb_msg_find_attr_as_int(msg
, "systemFlags", 0);
5548 /* Fetch name context */
5550 ret
= dsdb_find_nc_root(ldb
, ac
, olddn
, &nc_root
);
5551 if (ret
!= LDB_SUCCESS
) {
5555 if (ldb_dn_compare(nc_root
, ldb_get_schema_basedn(ldb
)) == 0) {
5557 ldb_asprintf_errstring(ldb
,
5558 "subtree_rename: Cannot move %s within schema partition",
5559 ldb_dn_get_linearized(olddn
));
5560 return LDB_ERR_UNWILLING_TO_PERFORM
;
5563 (systemFlags
& SYSTEM_FLAG_SCHEMA_BASE_OBJECT
) != 0) {
5564 ldb_asprintf_errstring(ldb
,
5565 "subtree_rename: Cannot rename %s within schema partition",
5566 ldb_dn_get_linearized(olddn
));
5567 return LDB_ERR_UNWILLING_TO_PERFORM
;
5569 } else if (ldb_dn_compare(nc_root
, ldb_get_config_basedn(ldb
)) == 0) {
5571 (systemFlags
& SYSTEM_FLAG_CONFIG_ALLOW_MOVE
) == 0) {
5572 /* Here we have to do more: control the
5573 * "ALLOW_LIMITED_MOVE" flag. This means that the
5574 * grand-grand-parents of two objects have to be equal
5575 * in order to perform the move (this is used for
5576 * moving "server" objects in the "sites" container). */
5578 systemFlags
& SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
;
5581 dn1
= ldb_dn_copy(ac
, olddn
);
5582 if (dn1
== NULL
) return ldb_oom(ldb
);
5583 dn2
= ldb_dn_copy(ac
, newdn
);
5584 if (dn2
== NULL
) return ldb_oom(ldb
);
5586 limited_move
&= ldb_dn_remove_child_components(dn1
, 3);
5587 limited_move
&= ldb_dn_remove_child_components(dn2
, 3);
5588 limited_move
&= ldb_dn_compare(dn1
, dn2
) == 0;
5595 && ldb_request_get_control(ac
->req
, DSDB_CONTROL_RESTORE_TOMBSTONE_OID
) == NULL
) {
5596 ldb_asprintf_errstring(ldb
,
5597 "subtree_rename: Cannot move %s to %s in config partition",
5598 ldb_dn_get_linearized(olddn
), ldb_dn_get_linearized(newdn
));
5599 return LDB_ERR_UNWILLING_TO_PERFORM
;
5603 (systemFlags
& SYSTEM_FLAG_CONFIG_ALLOW_RENAME
) == 0) {
5604 ldb_asprintf_errstring(ldb
,
5605 "subtree_rename: Cannot rename %s to %s within config partition",
5606 ldb_dn_get_linearized(olddn
), ldb_dn_get_linearized(newdn
));
5607 return LDB_ERR_UNWILLING_TO_PERFORM
;
5609 } else if (ldb_dn_compare(nc_root
, ldb_get_default_basedn(ldb
)) == 0) {
5611 (systemFlags
& SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE
) != 0) {
5612 ldb_asprintf_errstring(ldb
,
5613 "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
5614 ldb_dn_get_linearized(olddn
), ldb_dn_get_linearized(newdn
));
5615 return LDB_ERR_UNWILLING_TO_PERFORM
;
5618 (systemFlags
& SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME
) != 0) {
5619 ldb_asprintf_errstring(ldb
,
5620 "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
5621 ldb_dn_get_linearized(olddn
), ldb_dn_get_linearized(newdn
));
5622 return LDB_ERR_UNWILLING_TO_PERFORM
;
5626 talloc_free(nc_root
);
5632 static int samldb_rename_search_base_callback(struct ldb_request
*req
,
5633 struct ldb_reply
*ares
)
5635 struct samldb_ctx
*ac
;
5638 ac
= talloc_get_type(req
->context
, struct samldb_ctx
);
5641 return ldb_module_done(ac
->req
, NULL
, NULL
,
5642 LDB_ERR_OPERATIONS_ERROR
);
5644 if (ares
->error
!= LDB_SUCCESS
) {
5645 return ldb_module_done(ac
->req
, ares
->controls
,
5646 ares
->response
, ares
->error
);
5649 switch (ares
->type
) {
5650 case LDB_REPLY_ENTRY
:
5652 * This is the root entry of the originating move
5653 * respectively rename request. It has been already
5654 * stored in the list using "subtree_rename_search()".
5655 * Only this one is subject to constraint checking.
5657 ret
= check_rename_constraints(ares
->message
, ac
,
5658 ac
->req
->op
.rename
.olddn
,
5659 ac
->req
->op
.rename
.newdn
);
5660 if (ret
!= LDB_SUCCESS
) {
5661 return ldb_module_done(ac
->req
, NULL
, NULL
,
5666 case LDB_REPLY_REFERRAL
:
5670 case LDB_REPLY_DONE
:
5673 * Great, no problem with the rename, so go ahead as
5674 * if we never were here
5676 ret
= ldb_next_request(ac
->module
, ac
->req
);
5687 static int samldb_rename(struct ldb_module
*module
, struct ldb_request
*req
)
5689 struct ldb_context
*ldb
;
5690 static const char * const attrs
[] = { "objectClass", "systemFlags",
5691 "isDeleted", NULL
};
5692 struct ldb_request
*search_req
;
5693 struct samldb_ctx
*ac
;
5696 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) { /* do not manipulate our control entries */
5697 return ldb_next_request(module
, req
);
5700 ldb
= ldb_module_get_ctx(module
);
5702 ac
= samldb_ctx_init(module
, req
);
5704 return ldb_oom(ldb
);
5707 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
5708 req
->op
.rename
.olddn
,
5714 samldb_rename_search_base_callback
,
5716 LDB_REQ_SET_LOCATION(search_req
);
5717 if (ret
!= LDB_SUCCESS
) {
5721 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_RECYCLED_OID
,
5723 if (ret
!= LDB_SUCCESS
) {
5727 return ldb_next_request(ac
->module
, search_req
);
5732 static int samldb_extended_allocate_rid_pool(struct ldb_module
*module
, struct ldb_request
*req
)
5734 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
5735 struct dsdb_fsmo_extended_op
*exop
;
5738 exop
= talloc_get_type(req
->op
.extended
.data
,
5739 struct dsdb_fsmo_extended_op
);
5741 ldb_set_errstring(ldb
,
5742 "samldb_extended_allocate_rid_pool: invalid extended data");
5743 return LDB_ERR_PROTOCOL_ERROR
;
5746 ret
= ridalloc_allocate_rid_pool_fsmo(module
, exop
, req
);
5747 if (ret
!= LDB_SUCCESS
) {
5751 return ldb_module_done(req
, NULL
, NULL
, LDB_SUCCESS
);
5754 static int samldb_extended_allocate_rid(struct ldb_module
*module
, struct ldb_request
*req
)
5756 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
5757 struct dsdb_extended_allocate_rid
*exop
;
5760 exop
= talloc_get_type(req
->op
.extended
.data
,
5761 struct dsdb_extended_allocate_rid
);
5763 ldb_set_errstring(ldb
,
5764 "samldb_extended_allocate_rid: invalid extended data");
5765 return LDB_ERR_PROTOCOL_ERROR
;
5768 ret
= ridalloc_allocate_rid(module
, &exop
->rid
, req
);
5769 if (ret
!= LDB_SUCCESS
) {
5773 return ldb_module_done(req
, NULL
, NULL
, LDB_SUCCESS
);
5776 static int samldb_extended_create_own_rid_set(struct ldb_module
*module
, struct ldb_request
*req
)
5778 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
5782 if (req
->op
.extended
.data
!= NULL
) {
5783 ldb_set_errstring(ldb
,
5784 "samldb_extended_create_own_rid_set: invalid extended data (should be NULL)");
5785 return LDB_ERR_PROTOCOL_ERROR
;
5788 ret
= ridalloc_create_own_rid_set(module
, req
,
5790 if (ret
!= LDB_SUCCESS
) {
5794 return ldb_module_done(req
, NULL
, NULL
, LDB_SUCCESS
);
5797 static int samldb_extended(struct ldb_module
*module
, struct ldb_request
*req
)
5799 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_ALLOCATE_RID_POOL
) == 0) {
5800 return samldb_extended_allocate_rid_pool(module
, req
);
5803 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_ALLOCATE_RID
) == 0) {
5804 return samldb_extended_allocate_rid(module
, req
);
5807 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_CREATE_OWN_RID_SET
) == 0) {
5808 return samldb_extended_create_own_rid_set(module
, req
);
5811 return ldb_next_request(module
, req
);
5815 static const struct ldb_module_ops ldb_samldb_module_ops
= {
5818 .modify
= samldb_modify
,
5819 .del
= samldb_delete
,
5820 .rename
= samldb_rename
,
5821 .extended
= samldb_extended
5825 int ldb_samldb_module_init(const char *version
)
5827 LDB_MODULE_CHECK_VERSION(version
);
5828 return ldb_register_module(&ldb_samldb_module_ops
);