2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "system/filesys.h"
43 #include "lib/util/tsort.h"
44 #include "dsdb/common/util.h"
45 #include "lib/socket/socket.h"
46 #include "librpc/gen_ndr/irpc.h"
47 #include "libds/common/flag_mapping.h"
48 #include "lib/util/access.h"
49 #include "lib/util/util_str_hex.h"
50 #include "lib/util/sys_rw_data.h"
51 #include "libcli/util/ntstatus.h"
52 #include "lib/util/smb_strtox.h"
58 * This included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
59 * dsdb_request_add_controls()
61 #include "dsdb/samdb/ldb_modules/util.h"
63 /* default is 30 minutes: -1e7 * 30 * 60 */
64 #define DEFAULT_OBSERVATION_WINDOW -18000000000
67 search the sam for the specified attributes in a specific domain, filter on
68 objectSid being in domain_sid.
70 int samdb_search_domain(struct ldb_context *sam_ldb,
72 struct ldb_dn *basedn,
73 struct ldb_message ***res,
74 const char * const *attrs,
75 const struct dom_sid *domain_sid,
76 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
82 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
83 res, attrs, format, ap);
89 struct dom_sid *entry_sid;
91 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
93 if ((entry_sid == NULL) ||
94 (!dom_sid_in_domain(domain_sid, entry_sid))) {
95 /* Delete that entry from the result set */
96 (*res)[i] = (*res)[count-1];
98 talloc_free(entry_sid);
101 talloc_free(entry_sid);
109 search the sam for a single string attribute in exactly 1 record
111 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
113 struct ldb_dn *basedn,
114 const char *attr_name,
115 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
118 const char *attrs[2] = { NULL, NULL };
119 struct ldb_message **res = NULL;
121 attrs[0] = attr_name;
123 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
125 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
126 attr_name, format, count));
133 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
137 search the sam for a single string attribute in exactly 1 record
139 const char *samdb_search_string(struct ldb_context *sam_ldb,
141 struct ldb_dn *basedn,
142 const char *attr_name,
143 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
148 va_start(ap, format);
149 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
155 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
157 struct ldb_dn *basedn,
158 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
162 struct ldb_message **res = NULL;
165 va_start(ap, format);
166 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
169 if (count != 1) return NULL;
171 ret = talloc_steal(mem_ctx, res[0]->dn);
178 search the sam for a dom_sid attribute in exactly 1 record
180 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
182 struct ldb_dn *basedn,
183 const char *attr_name,
184 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
188 struct ldb_message **res;
189 const char *attrs[2] = { NULL, NULL };
192 attrs[0] = attr_name;
194 va_start(ap, format);
195 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
198 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
199 attr_name, format, count));
205 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
211 search the sam for a single integer attribute in exactly 1 record
213 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
215 unsigned int default_value,
216 struct ldb_dn *basedn,
217 const char *attr_name,
218 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
222 struct ldb_message **res;
223 const char *attrs[2] = { NULL, NULL };
225 attrs[0] = attr_name;
227 va_start(ap, format);
228 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
232 return default_value;
235 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
239 search the sam for a single signed 64 bit integer attribute in exactly 1 record
241 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
243 int64_t default_value,
244 struct ldb_dn *basedn,
245 const char *attr_name,
246 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
250 struct ldb_message **res;
251 const char *attrs[2] = { NULL, NULL };
253 attrs[0] = attr_name;
255 va_start(ap, format);
256 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
260 return default_value;
263 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
267 search the sam for multipe records each giving a single string attribute
268 return the number of matches, or -1 on error
270 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
272 struct ldb_dn *basedn,
274 const char *attr_name,
275 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
279 const char *attrs[2] = { NULL, NULL };
280 struct ldb_message **res = NULL;
282 attrs[0] = attr_name;
284 va_start(ap, format);
285 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
292 /* make sure its single valued */
293 for (i=0;i<count;i++) {
294 if (res[i]->num_elements != 1) {
295 DEBUG(1,("samdb: search for %s %s not single valued\n",
302 *strs = talloc_array(mem_ctx, const char *, count+1);
308 for (i=0;i<count;i++) {
309 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
311 (*strs)[count] = NULL;
316 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
317 const char *attr, struct ldb_dn *default_value)
319 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
321 return default_value;
327 pull a rid from a objectSid in a result set.
329 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
330 const char *attr, uint32_t default_value)
335 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
337 return default_value;
339 rid = sid->sub_auths[sid->num_auths-1];
345 pull a dom_sid structure from a objectSid in a result set.
347 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
351 const struct ldb_val *v;
353 v = ldb_msg_find_ldb_val(msg, attr);
357 sid = talloc(mem_ctx, struct dom_sid);
361 ret = sid_parse(v->data, v->length, sid);
370 pull a guid structure from a objectGUID in a result set.
372 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
374 const struct ldb_val *v;
378 v = ldb_msg_find_ldb_val(msg, attr);
379 if (!v) return GUID_zero();
381 status = GUID_from_ndr_blob(v, &guid);
382 if (!NT_STATUS_IS_OK(status)) {
390 pull a sid prefix from a objectSid in a result set.
391 this is used to find the domain sid for a user
393 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
396 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
397 if (!sid || sid->num_auths < 1) return NULL;
403 pull a NTTIME in a result set.
405 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
406 NTTIME default_value)
408 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
412 * Windows stores 0 for lastLogoff.
413 * But when a MS DC return the lastLogoff (as Logoff Time)
414 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
415 * cause windows 2008 and newer version to fail for SMB requests
417 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
419 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
422 ret = 0x7FFFFFFFFFFFFFFFULL;
428 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
429 * indicate an account doesn't expire.
431 * When Windows initially creates an account, it sets
432 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
433 * when changing from an account having a specific expiration date to
434 * that account never expiring, it sets accountExpires = 0.
436 * Consolidate that logic here to allow clearer logic for account expiry in
437 * the rest of the code.
439 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
441 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
445 ret = 0x7FFFFFFFFFFFFFFFULL;
451 construct the allow_password_change field from the PwdLastSet attribute and the
452 domain password settings
454 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
456 struct ldb_dn *domain_dn,
457 struct ldb_message *msg,
460 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
463 if (attr_time == 0) {
467 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
469 /* yes, this is a -= not a += as minPwdAge is stored as the negative
470 of the number of 100-nano-seconds */
471 attr_time -= minPwdAge;
477 pull a samr_Password structutre from a result set.
479 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
481 struct samr_Password *hash = NULL;
482 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
483 if (val && (val->length >= sizeof(hash->hash))) {
484 hash = talloc(mem_ctx, struct samr_Password);
485 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
491 pull an array of samr_Password structures from a result set.
493 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
494 const char *attr, struct samr_Password **hashes)
496 unsigned int count, i;
497 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
503 count = val->length / 16;
508 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
513 for (i=0;i<count;i++) {
514 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
520 NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
521 struct loadparm_context *lp_ctx,
522 struct ldb_message *msg,
524 struct samr_Password **lm_pwd,
525 struct samr_Password **nt_pwd)
527 struct samr_Password *lmPwdHash, *ntPwdHash;
531 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
535 *nt_pwd = &ntPwdHash[idx];
539 /* Ensure that if we have turned off LM
540 * authentication, that we never use the LM hash, even
542 if (lpcfg_lanman_auth(lp_ctx)) {
544 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
548 *lm_pwd = &lmPwdHash[idx];
557 NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
558 struct loadparm_context *lp_ctx,
559 const struct ldb_message *msg,
560 struct samr_Password **lm_pwd,
561 struct samr_Password **nt_pwd)
563 struct samr_Password *lmPwdHash, *ntPwdHash;
567 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
570 } else if (num_nt > 1) {
571 return NT_STATUS_INTERNAL_DB_CORRUPTION;
573 *nt_pwd = &ntPwdHash[0];
577 /* Ensure that if we have turned off LM
578 * authentication, that we never use the LM hash, even
580 if (lpcfg_lanman_auth(lp_ctx)) {
582 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
585 } else if (num_lm > 1) {
586 return NT_STATUS_INTERNAL_DB_CORRUPTION;
588 *lm_pwd = &lmPwdHash[0];
597 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
598 struct loadparm_context *lp_ctx,
599 const struct ldb_message *msg,
600 struct samr_Password **lm_pwd,
601 struct samr_Password **nt_pwd)
605 acct_flags = samdb_result_acct_flags(msg,
606 "msDS-User-Account-Control-Computed");
607 /* Quit if the account was locked out. */
608 if (acct_flags & ACB_AUTOLOCK) {
609 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
610 ldb_dn_get_linearized(msg->dn)));
611 return NT_STATUS_ACCOUNT_LOCKED_OUT;
614 return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
619 pull a samr_LogonHours structutre from a result set.
621 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
623 struct samr_LogonHours hours;
624 size_t units_per_week = 168;
625 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
630 units_per_week = val->length * 8;
633 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
637 hours.units_per_week = units_per_week;
638 memset(hours.bits, 0xFF, units_per_week/8);
640 memcpy(hours.bits, val->data, val->length);
647 pull a set of account_flags from a result set.
649 Naturally, this requires that userAccountControl and
650 (if not null) the attributes 'attr' be already
653 uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
655 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
656 uint32_t attr_flags = 0;
657 uint32_t acct_flags = ds_uf2acb(userAccountControl);
659 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
660 if (attr_flags == UF_ACCOUNTDISABLE) {
661 DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
662 ldb_dn_get_linearized(msg->dn)));
664 acct_flags |= ds_uf2acb(attr_flags);
670 NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
671 struct ldb_message *msg,
673 struct lsa_BinaryString *s)
676 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
684 if ((val->length % 2) != 0) {
686 * If the on-disk data is not even in length, we know
687 * it is corrupt, and can not be safely pushed. We
688 * would either truncate, send either a un-initilaised
689 * byte or send a forced zero byte
691 return NT_STATUS_INTERNAL_DB_CORRUPTION;
694 s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
696 return NT_STATUS_NO_MEMORY;
698 s->length = s->size = val->length;
700 /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
701 for (i = 0; i < s->length / 2; i++) {
702 s->array[i] = SVAL(val->data, i * 2);
708 /* Find an attribute, with a particular value */
710 /* The current callers of this function expect a very specific
711 * behaviour: In particular, objectClass subclass equivalence is not
712 * wanted. This means that we should not lookup the schema for the
713 * comparison function */
714 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
715 const struct ldb_message *msg,
716 const char *name, const char *value)
719 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
725 for (i=0;i<el->num_values;i++) {
726 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
734 static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
735 struct ldb_message *msg,
737 const char *set_value,
742 struct ldb_message_element *el;
744 SMB_ASSERT(attr_flags != 0);
746 el = ldb_msg_find_element(msg, name);
755 ret = ldb_msg_add_empty(msg, name,
758 if (ret != LDB_SUCCESS) {
762 if (set_value != NULL) {
763 ret = ldb_msg_add_string(msg, name, set_value);
764 if (ret != LDB_SUCCESS) {
775 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
777 return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
781 add a dom_sid element to a message
783 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, const struct dom_sid *sid)
787 enum ndr_err_code ndr_err;
789 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
791 (ndr_push_flags_fn_t)ndr_push_dom_sid);
792 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
793 return ldb_operr(sam_ldb);
795 return ldb_msg_add_value(msg, attr_name, &v, NULL);
800 add a delete element operation to a message
802 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
803 const char *attr_name)
805 /* we use an empty replace rather than a delete, as it allows for
806 dsdb_replace() to be used everywhere */
807 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
811 add an add attribute value to a message or enhance an existing attribute
812 which has the same name and the add flag set.
814 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
815 struct ldb_message *msg, const char *attr_name,
818 struct ldb_message_element *el;
819 struct ldb_val val, *vals;
825 v = talloc_strdup(mem_ctx, value);
827 return ldb_oom(sam_ldb);
830 val.data = (uint8_t *) v;
831 val.length = strlen(v);
833 if (val.length == 0) {
834 /* allow empty strings as non-existent attributes */
838 for (i = 0; i < msg->num_elements; i++) {
839 el = &msg->elements[i];
840 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
841 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
847 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
849 if (ret != LDB_SUCCESS) {
854 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
857 return ldb_oom(sam_ldb);
860 el->values[el->num_values] = val;
867 add a delete attribute value to a message or enhance an existing attribute
868 which has the same name and the delete flag set.
870 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
871 struct ldb_message *msg, const char *attr_name,
874 struct ldb_message_element *el;
875 struct ldb_val val, *vals;
881 v = talloc_strdup(mem_ctx, value);
883 return ldb_oom(sam_ldb);
886 val.data = (uint8_t *) v;
887 val.length = strlen(v);
889 if (val.length == 0) {
890 /* allow empty strings as non-existent attributes */
894 for (i = 0; i < msg->num_elements; i++) {
895 el = &msg->elements[i];
896 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
897 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
903 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
905 if (ret != LDB_SUCCESS) {
910 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
913 return ldb_oom(sam_ldb);
916 el->values[el->num_values] = val;
923 add a int element to a message
925 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
926 const char *attr_name, int v)
928 const char *s = talloc_asprintf(mem_ctx, "%d", v);
930 return ldb_oom(sam_ldb);
932 return ldb_msg_add_string(msg, attr_name, s);
936 * Add an unsigned int element to a message
938 * The issue here is that we have not yet first cast to int32_t explicitly,
939 * before we cast to an signed int to printf() into the %d or cast to a
940 * int64_t before we then cast to a long long to printf into a %lld.
942 * There are *no* unsigned integers in Active Directory LDAP, even the RID
943 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
944 * (See the schema, and the syntax definitions in schema_syntax.c).
947 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948 const char *attr_name, unsigned int v)
950 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
954 add a (signed) int64_t element to a message
956 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
957 const char *attr_name, int64_t v)
959 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
961 return ldb_oom(sam_ldb);
963 return ldb_msg_add_string(msg, attr_name, s);
967 * Add an unsigned int64_t (uint64_t) element to a message
969 * The issue here is that we have not yet first cast to int32_t explicitly,
970 * before we cast to an signed int to printf() into the %d or cast to a
971 * int64_t before we then cast to a long long to printf into a %lld.
973 * There are *no* unsigned integers in Active Directory LDAP, even the RID
974 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
975 * (See the schema, and the syntax definitions in schema_syntax.c).
978 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
979 const char *attr_name, uint64_t v)
981 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
985 add a samr_Password element to a message
987 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
988 const char *attr_name, const struct samr_Password *hash)
991 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
993 return ldb_oom(sam_ldb);
996 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1000 add a samr_Password array to a message
1002 int samdb_msg_add_hashes(struct ldb_context *ldb,
1003 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1004 const char *attr_name, struct samr_Password *hashes,
1009 val.data = talloc_array_size(mem_ctx, 16, count);
1010 val.length = count*16;
1012 return ldb_oom(ldb);
1014 for (i=0;i<count;i++) {
1015 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1017 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1021 add a acct_flags element to a message
1023 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1024 const char *attr_name, uint32_t v)
1026 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1030 add a logon_hours element to a message
1032 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1033 const char *attr_name, struct samr_LogonHours *hours)
1036 val.length = hours->units_per_week / 8;
1037 val.data = hours->bits;
1038 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1042 add a parameters element to a message
1044 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1045 const char *attr_name, struct lsa_BinaryString *parameters)
1049 if ((parameters->length % 2) != 0) {
1050 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1053 val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1054 if (val.data == NULL) {
1055 return LDB_ERR_OPERATIONS_ERROR;
1057 val.length = parameters->length;
1058 for (i = 0; i < parameters->length / 2; i++) {
1060 * The on-disk format needs to be in the 'network'
1061 * format, parmeters->array is a uint16_t array of
1062 * length parameters->length / 2
1064 SSVAL(val.data, i * 2, parameters->array[i]);
1066 return ldb_msg_add_steal_value(msg, attr_name, &val);
1070 * Sets an unsigned int element in a message
1072 * The issue here is that we have not yet first cast to int32_t explicitly,
1073 * before we cast to an signed int to printf() into the %d or cast to a
1074 * int64_t before we then cast to a long long to printf into a %lld.
1076 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1077 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1078 * (See the schema, and the syntax definitions in schema_syntax.c).
1081 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1082 struct ldb_message *msg, const char *attr_name,
1085 struct ldb_message_element *el;
1087 el = ldb_msg_find_element(msg, attr_name);
1091 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1095 * Handle ldb_request in transaction
1097 int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1098 struct ldb_request *req)
1102 ret = ldb_transaction_start(sam_ldb);
1103 if (ret != LDB_SUCCESS) {
1107 ret = ldb_request(sam_ldb, req);
1108 if (ret == LDB_SUCCESS) {
1109 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1112 if (ret == LDB_SUCCESS) {
1113 return ldb_transaction_commit(sam_ldb);
1115 ldb_transaction_cancel(sam_ldb);
1121 return a default security descriptor
1123 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1125 struct security_descriptor *sd;
1127 sd = security_descriptor_initialise(mem_ctx);
1132 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1134 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1135 struct ldb_dn *aggregate_dn;
1140 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1141 if (!aggregate_dn) {
1144 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1147 return aggregate_dn;
1150 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1152 struct ldb_dn *new_dn;
1154 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1155 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1156 talloc_free(new_dn);
1162 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1164 struct ldb_dn *new_dn;
1166 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1167 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1168 talloc_free(new_dn);
1174 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1176 struct ldb_dn *new_dn;
1178 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1179 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1180 talloc_free(new_dn);
1187 work out the domain sid for the current open ldb
1189 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1191 TALLOC_CTX *tmp_ctx;
1192 const struct dom_sid *domain_sid;
1193 const char *attrs[] = {
1197 struct ldb_result *res;
1200 /* see if we have a cached copy */
1201 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1206 tmp_ctx = talloc_new(ldb);
1207 if (tmp_ctx == NULL) {
1211 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1213 if (ret != LDB_SUCCESS) {
1217 if (res->count != 1) {
1221 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1222 if (domain_sid == NULL) {
1226 /* cache the domain_sid in the ldb */
1227 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1231 talloc_steal(ldb, domain_sid);
1232 talloc_free(tmp_ctx);
1237 talloc_free(tmp_ctx);
1242 get domain sid from cache
1244 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1246 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1249 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1251 TALLOC_CTX *tmp_ctx;
1252 struct dom_sid *dom_sid_new;
1253 struct dom_sid *dom_sid_old;
1255 /* see if we have a cached copy */
1256 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1257 "cache.domain_sid"), struct dom_sid);
1259 tmp_ctx = talloc_new(ldb);
1260 if (tmp_ctx == NULL) {
1264 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1269 /* cache the domain_sid in the ldb */
1270 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1274 talloc_steal(ldb, dom_sid_new);
1275 talloc_free(tmp_ctx);
1276 talloc_free(dom_sid_old);
1281 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1282 talloc_free(tmp_ctx);
1287 work out the domain guid for the current open ldb
1289 const struct GUID *samdb_domain_guid(struct ldb_context *ldb)
1291 TALLOC_CTX *tmp_ctx = NULL;
1292 struct GUID *domain_guid = NULL;
1293 const char *attrs[] = {
1297 struct ldb_result *res = NULL;
1300 /* see if we have a cached copy */
1301 domain_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.domain_guid");
1306 tmp_ctx = talloc_new(ldb);
1307 if (tmp_ctx == NULL) {
1311 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectGUID=*");
1312 if (ret != LDB_SUCCESS) {
1316 if (res->count != 1) {
1320 domain_guid = talloc(tmp_ctx, struct GUID);
1321 if (domain_guid == NULL) {
1324 *domain_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1326 /* cache the domain_sid in the ldb */
1327 if (ldb_set_opaque(ldb, "cache.domain_guid", domain_guid) != LDB_SUCCESS) {
1331 talloc_steal(ldb, domain_guid);
1332 talloc_free(tmp_ctx);
1337 talloc_free(tmp_ctx);
1341 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1343 TALLOC_CTX *tmp_ctx;
1344 struct ldb_dn *ntds_settings_dn_new;
1345 struct ldb_dn *ntds_settings_dn_old;
1347 /* see if we have a forced copy from provision */
1348 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1349 "forced.ntds_settings_dn"), struct ldb_dn);
1351 tmp_ctx = talloc_new(ldb);
1352 if (tmp_ctx == NULL) {
1356 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1357 if (!ntds_settings_dn_new) {
1361 /* set the DN in the ldb to avoid lookups during provision */
1362 if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1366 talloc_steal(ldb, ntds_settings_dn_new);
1367 talloc_free(tmp_ctx);
1368 talloc_free(ntds_settings_dn_old);
1373 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1374 talloc_free(tmp_ctx);
1379 work out the ntds settings dn for the current open ldb
1381 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1383 TALLOC_CTX *tmp_ctx;
1384 const char *root_attrs[] = { "dsServiceName", NULL };
1386 struct ldb_result *root_res;
1387 struct ldb_dn *settings_dn;
1389 /* see if we have a cached copy */
1390 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1392 return ldb_dn_copy(mem_ctx, settings_dn);
1395 tmp_ctx = talloc_new(mem_ctx);
1396 if (tmp_ctx == NULL) {
1400 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1401 if (ret != LDB_SUCCESS) {
1402 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1403 ldb_errstring(ldb)));
1407 if (root_res->count != 1) {
1411 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1413 /* note that we do not cache the DN here, as that would mean
1414 * we could not handle server renames at runtime. Only
1415 * provision sets up forced.ntds_settings_dn */
1417 talloc_steal(mem_ctx, settings_dn);
1418 talloc_free(tmp_ctx);
1423 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1424 talloc_free(tmp_ctx);
1429 work out the ntds settings invocationID/objectGUID for the current open ldb
1431 static const struct GUID *samdb_ntds_GUID(struct ldb_context *ldb,
1432 const char *attribute,
1433 const char *cache_name)
1435 TALLOC_CTX *tmp_ctx;
1436 const char *attrs[] = { attribute, NULL };
1438 struct ldb_result *res;
1439 struct GUID *ntds_guid;
1440 struct ldb_dn *ntds_settings_dn = NULL;
1441 const char *errstr = NULL;
1443 /* see if we have a cached copy */
1444 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1445 if (ntds_guid != NULL) {
1449 tmp_ctx = talloc_new(ldb);
1450 if (tmp_ctx == NULL) {
1454 ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
1455 if (ntds_settings_dn == NULL) {
1456 errstr = "samdb_ntds_settings_dn() returned NULL";
1460 ret = ldb_search(ldb, tmp_ctx, &res, ntds_settings_dn,
1461 LDB_SCOPE_BASE, attrs, NULL);
1463 errstr = ldb_errstring(ldb);
1467 if (res->count != 1) {
1468 errstr = "incorrect number of results from base search";
1472 ntds_guid = talloc(tmp_ctx, struct GUID);
1473 if (ntds_guid == NULL) {
1477 *ntds_guid = samdb_result_guid(res->msgs[0], attribute);
1479 if (GUID_all_zero(ntds_guid)) {
1480 if (ldb_msg_find_ldb_val(res->msgs[0], attribute)) {
1481 errstr = "failed to find the GUID attribute";
1483 errstr = "failed to parse the GUID";
1488 /* cache the domain_sid in the ldb */
1489 if (ldb_set_opaque(ldb, cache_name, ntds_guid) != LDB_SUCCESS) {
1490 errstr = "ldb_set_opaque() failed";
1494 talloc_steal(ldb, ntds_guid);
1495 talloc_free(tmp_ctx);
1500 DBG_WARNING("Failed to find our own NTDS Settings %s in the ldb: %s!\n",
1502 talloc_free(tmp_ctx);
1507 work out the ntds settings objectGUID for the current open ldb
1509 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1511 return samdb_ntds_GUID(ldb, "objectGUID", "cache.ntds_guid");
1515 work out the ntds settings invocationId for the current open ldb
1517 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1519 return samdb_ntds_GUID(ldb, "invocationId", "cache.invocation_id");
1522 static bool samdb_set_ntds_GUID(struct ldb_context *ldb,
1523 const struct GUID *ntds_guid_in,
1524 const char *attribute,
1525 const char *cache_name)
1527 TALLOC_CTX *tmp_ctx;
1528 struct GUID *ntds_guid_new;
1529 struct GUID *ntds_guid_old;
1531 /* see if we have a cached copy */
1532 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1534 tmp_ctx = talloc_new(ldb);
1535 if (tmp_ctx == NULL) {
1539 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1540 if (!ntds_guid_new) {
1544 *ntds_guid_new = *ntds_guid_in;
1546 /* cache the domain_sid in the ldb */
1547 if (ldb_set_opaque(ldb, cache_name, ntds_guid_new) != LDB_SUCCESS) {
1551 talloc_steal(ldb, ntds_guid_new);
1552 talloc_free(tmp_ctx);
1553 talloc_free(ntds_guid_old);
1558 DBG_WARNING("Failed to set our own cached %s in the ldb!\n",
1560 talloc_free(tmp_ctx);
1564 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1566 return samdb_set_ntds_GUID(ldb,
1572 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1574 return samdb_set_ntds_GUID(ldb,
1577 "cache.invocation_id");
1581 work out the server dn for the current open ldb
1583 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1585 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1590 dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1591 talloc_free(tmp_ctx);
1597 work out the server dn for the current open ldb
1599 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1601 struct ldb_dn *server_dn;
1602 struct ldb_dn *servers_dn;
1603 struct ldb_dn *server_site_dn;
1605 /* TODO: there must be a saner way to do this!! */
1606 server_dn = samdb_server_dn(ldb, mem_ctx);
1607 if (!server_dn) return NULL;
1609 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1610 talloc_free(server_dn);
1611 if (!servers_dn) return NULL;
1613 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1614 talloc_free(servers_dn);
1616 return server_site_dn;
1620 find the site name from a computers DN record
1622 int samdb_find_site_for_computer(struct ldb_context *ldb,
1623 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1624 const char **site_name)
1628 const struct ldb_val *rdn_val;
1632 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1633 if (ret != LDB_SUCCESS) {
1637 if (!ldb_dn_remove_child_components(dn, 2)) {
1639 return LDB_ERR_INVALID_DN_SYNTAX;
1642 rdn_val = ldb_dn_get_rdn_val(dn);
1643 if (rdn_val == NULL) {
1644 return LDB_ERR_OPERATIONS_ERROR;
1647 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1650 return LDB_ERR_OPERATIONS_ERROR;
1656 find the NTDS GUID from a computers DN record
1658 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1659 struct GUID *ntds_guid)
1664 *ntds_guid = GUID_zero();
1666 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1667 if (ret != LDB_SUCCESS) {
1671 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1673 return LDB_ERR_OPERATIONS_ERROR;
1676 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1682 find a 'reference' DN that points at another object
1683 (eg. serverReference, rIDManagerReference etc)
1685 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1686 const char *attribute, struct ldb_dn **dn)
1688 const char *attrs[2];
1689 struct ldb_result *res;
1692 attrs[0] = attribute;
1695 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1696 if (ret != LDB_SUCCESS) {
1697 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1698 ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1702 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1704 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1705 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1706 ldb_dn_get_linearized(base));
1708 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1709 ldb_dn_get_linearized(base));
1712 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1720 find if a DN (must have GUID component!) is our ntdsDsa
1722 int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1725 struct GUID dn_guid;
1726 const struct GUID *our_ntds_guid;
1727 status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1728 if (!NT_STATUS_IS_OK(status)) {
1729 return LDB_ERR_OPERATIONS_ERROR;
1732 our_ntds_guid = samdb_ntds_objectGUID(ldb);
1733 if (!our_ntds_guid) {
1734 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1735 return LDB_ERR_OPERATIONS_ERROR;
1738 *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1743 find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1745 int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1746 const char *attribute, bool *is_ntdsa)
1749 struct ldb_dn *referenced_dn;
1750 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1751 if (tmp_ctx == NULL) {
1752 return LDB_ERR_OPERATIONS_ERROR;
1754 ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1755 if (ret != LDB_SUCCESS) {
1756 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1760 ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1762 talloc_free(tmp_ctx);
1767 find our machine account via the serverReference attribute in the
1770 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1772 struct ldb_dn *server_dn;
1775 server_dn = samdb_server_dn(ldb, mem_ctx);
1776 if (server_dn == NULL) {
1777 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
1780 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1781 talloc_free(server_dn);
1787 find the RID Manager$ DN via the rIDManagerReference attribute in the
1790 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1792 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1793 "rIDManagerReference", dn);
1797 find the RID Set DN via the rIDSetReferences attribute in our
1800 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1802 struct ldb_dn *server_ref_dn = NULL;
1805 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1806 if (ret != LDB_SUCCESS) {
1809 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1810 talloc_free(server_ref_dn);
1814 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1816 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1823 return (const char *) val->data;
1827 * Finds the client site by using the client's IP address.
1828 * The "subnet_name" returns the name of the subnet if parameter != NULL
1830 * Has a Windows-based fallback to provide the only site available, or an empty
1831 * string if there are multiple sites.
1833 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1834 const char *ip_address, char **subnet_name,
1837 const char *attrs[] = { "cn", "siteObject", NULL };
1838 struct ldb_dn *sites_container_dn = NULL;
1839 struct ldb_dn *subnets_dn = NULL;
1840 struct ldb_dn *sites_dn = NULL;
1841 struct ldb_result *res = NULL;
1842 const struct ldb_val *val = NULL;
1843 const char *site_name = NULL;
1844 const char *l_subnet_name = NULL;
1845 const char *allow_list[2] = { NULL, NULL };
1846 unsigned int i, count;
1850 * if we don't have a client ip e.g. ncalrpc
1851 * the server site is the client site
1853 if (ip_address == NULL) {
1854 return samdb_server_site_name(ldb, mem_ctx);
1857 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1858 if (sites_container_dn == NULL) {
1862 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1863 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1867 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1869 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1871 } else if (ret != LDB_SUCCESS) {
1877 for (i = 0; i < count; i++) {
1878 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1881 allow_list[0] = l_subnet_name;
1883 if (allow_access_nolog(NULL, allow_list, "", ip_address)) {
1884 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1887 if (sites_dn == NULL) {
1888 /* No reference, maybe another subnet matches */
1892 /* "val" cannot be NULL here since "sites_dn" != NULL */
1893 val = ldb_dn_get_rdn_val(sites_dn);
1894 site_name = talloc_strdup(mem_ctx,
1895 (const char *) val->data);
1897 TALLOC_FREE(sites_dn);
1903 if (site_name == NULL && fallback) {
1904 /* This is the Windows Server fallback rule: when no subnet
1905 * exists and we have only one site available then use it (it
1906 * is for sure the same as our server site). If more sites do
1907 * exist then we don't know which one to use and set the site
1910 ret = dsdb_domain_count(
1916 "(objectClass=site)");
1917 if (ret != LDB_SUCCESS) {
1921 site_name = samdb_server_site_name(ldb, mem_ctx);
1923 site_name = talloc_strdup(mem_ctx, "");
1925 l_subnet_name = NULL;
1928 if (subnet_name != NULL) {
1929 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1933 TALLOC_FREE(sites_container_dn);
1934 TALLOC_FREE(subnets_dn);
1941 work out if we are the PDC for the domain of the current open ldb
1943 bool samdb_is_pdc(struct ldb_context *ldb)
1948 ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner",
1950 if (ret != LDB_SUCCESS) {
1951 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n",
1952 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1953 ldb_errstring(ldb)));
1961 work out if we are a Global Catalog server for the domain of the current open ldb
1963 bool samdb_is_gc(struct ldb_context *ldb)
1965 uint32_t options = 0;
1966 if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
1969 return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
1972 /* Find a domain object in the parents of a particular DN. */
1973 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1974 struct ldb_dn **parent_dn, const char **errstring)
1976 TALLOC_CTX *local_ctx;
1977 struct ldb_dn *sdn = dn;
1978 struct ldb_result *res = NULL;
1979 int ret = LDB_SUCCESS;
1980 const char *attrs[] = { NULL };
1982 local_ctx = talloc_new(mem_ctx);
1983 if (local_ctx == NULL) return ldb_oom(ldb);
1985 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1986 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1987 "(|(objectClass=domain)(objectClass=builtinDomain))");
1988 if (ret == LDB_SUCCESS) {
1989 if (res->count == 1) {
1997 if (ret != LDB_SUCCESS) {
1998 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1999 ldb_dn_get_linearized(dn),
2000 ldb_dn_get_linearized(sdn),
2001 ldb_errstring(ldb));
2002 talloc_free(local_ctx);
2005 /* should never be true with 'ret=LDB_SUCCESS', here to satisfy clang */
2007 talloc_free(local_ctx);
2008 return LDB_ERR_OTHER;
2010 if (res->count != 1) {
2011 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2012 ldb_dn_get_linearized(dn));
2013 DEBUG(0,(__location__ ": %s\n", *errstring));
2014 talloc_free(local_ctx);
2015 return LDB_ERR_CONSTRAINT_VIOLATION;
2018 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2019 talloc_free(local_ctx);
2023 static void pwd_timeout_debug(struct tevent_context *unused1,
2024 struct tevent_timer *unused2,
2025 struct timeval unused3,
2028 DEBUG(0, ("WARNING: check_password_complexity: password script "
2029 "took more than 1 second to run\n"));
2034 * Performs checks on a user password (plaintext UNIX format - attribute
2035 * "password"). The remaining parameters have to be extracted from the domain
2038 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2040 enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
2041 struct loadparm_context *lp_ctx,
2042 const char *account_name,
2043 const char *user_principal_name,
2044 const char *full_name,
2045 const DATA_BLOB *utf8_blob,
2046 const uint32_t pwdProperties,
2047 const uint32_t minPwdLength)
2049 const struct loadparm_substitution *lp_sub =
2050 lpcfg_noop_substitution();
2051 char *password_script = NULL;
2052 const char *utf8_pw = (const char *)utf8_blob->data;
2055 * This looks strange because it is.
2057 * The check for the number of characters in the password
2058 * should clearly not be against the byte length, or else a
2059 * single UTF8 character would count for more than one.
2061 * We have chosen to use the number of 16-bit units that the
2062 * password encodes to as the measure of length. This is not
2063 * the same as the number of codepoints, if a password
2064 * contains a character beyond the Basic Multilingual Plane
2065 * (above 65535) it will count for more than one "character".
2068 size_t password_characters_roughly = strlen_m(utf8_pw);
2070 /* checks if the "minPwdLength" property is satisfied */
2071 if (minPwdLength > password_characters_roughly) {
2072 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2075 /* We might not be asked to check the password complexity */
2076 if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2077 return SAMR_VALIDATION_STATUS_SUCCESS;
2080 if (password_characters_roughly == 0) {
2081 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2084 password_script = lpcfg_check_password_script(lp_ctx, lp_sub, mem_ctx);
2085 if (password_script != NULL && *password_script != '\0') {
2088 ssize_t nwritten = 0;
2089 struct tevent_context *event_ctx = NULL;
2090 struct tevent_req *req = NULL;
2092 const char * const cmd[4] = {
2098 event_ctx = tevent_context_init(mem_ctx);
2099 if (event_ctx == NULL) {
2100 TALLOC_FREE(password_script);
2101 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2104 /* Gives a warning after 1 second, terminates after 10 */
2105 tevent_add_timer(event_ctx, event_ctx,
2106 tevent_timeval_current_ofs(1, 0),
2107 pwd_timeout_debug, NULL);
2109 check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", account_name, 1);
2110 if (check_ret != 0) {
2111 TALLOC_FREE(password_script);
2112 TALLOC_FREE(event_ctx);
2113 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2115 if (user_principal_name != NULL) {
2116 check_ret = setenv("SAMBA_CPS_USER_PRINCIPAL_NAME",
2117 user_principal_name, 1);
2119 unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2121 if (check_ret != 0) {
2122 TALLOC_FREE(password_script);
2123 TALLOC_FREE(event_ctx);
2124 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2126 if (full_name != NULL) {
2127 check_ret = setenv("SAMBA_CPS_FULL_NAME", full_name, 1);
2129 unsetenv("SAMBA_CPS_FULL_NAME");
2131 if (check_ret != 0) {
2132 TALLOC_FREE(password_script);
2133 TALLOC_FREE(event_ctx);
2134 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2137 req = samba_runcmd_send(event_ctx, event_ctx,
2138 tevent_timeval_current_ofs(10, 0),
2139 100, 100, cmd, NULL);
2140 unsetenv("SAMBA_CPS_ACCOUNT_NAME");
2141 unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2142 unsetenv("SAMBA_CPS_FULL_NAME");
2144 TALLOC_FREE(password_script);
2145 TALLOC_FREE(event_ctx);
2146 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2149 cps_stdin = samba_runcmd_export_stdin(req);
2151 nwritten = write_data(
2152 cps_stdin, utf8_blob->data, utf8_blob->length);
2153 if (nwritten == -1) {
2155 TALLOC_FREE(password_script);
2156 TALLOC_FREE(event_ctx);
2157 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2162 if (!tevent_req_poll(req, event_ctx)) {
2163 TALLOC_FREE(password_script);
2164 TALLOC_FREE(event_ctx);
2165 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2168 check_ret = samba_runcmd_recv(req, &error);
2169 TALLOC_FREE(event_ctx);
2171 if (error == ETIMEDOUT) {
2172 DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
2173 TALLOC_FREE(password_script);
2174 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2176 DEBUG(5,("check_password_complexity: check password script (%s) "
2177 "returned [%d]\n", password_script, check_ret));
2179 if (check_ret != 0) {
2180 DEBUG(1,("check_password_complexity: "
2181 "check password script said new password is not good "
2183 TALLOC_FREE(password_script);
2184 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2187 TALLOC_FREE(password_script);
2188 return SAMR_VALIDATION_STATUS_SUCCESS;
2191 TALLOC_FREE(password_script);
2194 * Here are the standard AD password quality rules, which we
2195 * run after the script.
2198 if (!check_password_quality(utf8_pw)) {
2199 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2202 return SAMR_VALIDATION_STATUS_SUCCESS;
2206 * Callback for "samdb_set_password" password change
2208 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2213 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2216 if (ares->error != LDB_SUCCESS) {
2218 req->context = talloc_steal(req,
2219 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2221 return ldb_request_done(req, ret);
2224 if (ares->type != LDB_REPLY_DONE) {
2226 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2229 req->context = talloc_steal(req,
2230 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2232 return ldb_request_done(req, LDB_SUCCESS);
2236 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2237 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2238 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2239 * user change or not. The "rejectReason" gives some more information if the
2242 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2243 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2245 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2246 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2247 const DATA_BLOB *new_password,
2248 const struct samr_Password *lmNewHash,
2249 const struct samr_Password *ntNewHash,
2250 const struct samr_Password *lmOldHash,
2251 const struct samr_Password *ntOldHash,
2252 enum samPwdChangeReason *reject_reason,
2253 struct samr_DomInfo1 **_dominfo,
2254 bool permit_interdomain_trust)
2256 struct ldb_message *msg;
2257 struct ldb_message_element *el;
2258 struct ldb_request *req;
2259 struct dsdb_control_password_change_status *pwd_stat = NULL;
2261 bool hash_values = false;
2262 NTSTATUS status = NT_STATUS_OK;
2264 #define CHECK_RET(x) \
2265 if (x != LDB_SUCCESS) { \
2267 return NT_STATUS_NO_MEMORY; \
2270 msg = ldb_msg_new(mem_ctx);
2272 return NT_STATUS_NO_MEMORY;
2275 if ((new_password != NULL)
2276 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2277 /* we have the password as plaintext UTF16 */
2278 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2279 new_password, NULL));
2280 el = ldb_msg_find_element(msg, "clearTextPassword");
2281 el->flags = LDB_FLAG_MOD_REPLACE;
2282 } else if ((new_password == NULL)
2283 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2284 /* we have a password as LM and/or NT hash */
2285 if (lmNewHash != NULL) {
2286 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2287 "dBCSPwd", lmNewHash));
2288 el = ldb_msg_find_element(msg, "dBCSPwd");
2289 el->flags = LDB_FLAG_MOD_REPLACE;
2291 if (ntNewHash != NULL) {
2292 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2293 "unicodePwd", ntNewHash));
2294 el = ldb_msg_find_element(msg, "unicodePwd");
2295 el->flags = LDB_FLAG_MOD_REPLACE;
2299 /* the password wasn't specified correctly */
2301 return NT_STATUS_INVALID_PARAMETER;
2304 /* build modify request */
2305 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2306 samdb_set_password_callback, NULL);
2307 if (ret != LDB_SUCCESS) {
2309 return NT_STATUS_NO_MEMORY;
2312 /* A password change operation */
2313 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2314 struct dsdb_control_password_change *change;
2316 change = talloc(req, struct dsdb_control_password_change);
2317 if (change == NULL) {
2320 return NT_STATUS_NO_MEMORY;
2323 change->old_nt_pwd_hash = ntOldHash;
2324 change->old_lm_pwd_hash = lmOldHash;
2326 ret = ldb_request_add_control(req,
2327 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2329 if (ret != LDB_SUCCESS) {
2332 return NT_STATUS_NO_MEMORY;
2336 ret = ldb_request_add_control(req,
2337 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2339 if (ret != LDB_SUCCESS) {
2342 return NT_STATUS_NO_MEMORY;
2345 if (permit_interdomain_trust) {
2346 ret = ldb_request_add_control(req,
2347 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2349 if (ret != LDB_SUCCESS) {
2352 return NT_STATUS_NO_MEMORY;
2355 ret = ldb_request_add_control(req,
2356 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2358 if (ret != LDB_SUCCESS) {
2361 return NT_STATUS_NO_MEMORY;
2364 ret = dsdb_autotransaction_request(ldb, req);
2366 if (req->context != NULL) {
2367 struct ldb_control *control = talloc_get_type_abort(req->context,
2368 struct ldb_control);
2369 pwd_stat = talloc_get_type_abort(control->data,
2370 struct dsdb_control_password_change_status);
2371 talloc_steal(mem_ctx, pwd_stat);
2377 /* Sets the domain info (if requested) */
2378 if (_dominfo != NULL) {
2379 struct samr_DomInfo1 *dominfo;
2381 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2382 if (dominfo == NULL) {
2383 return NT_STATUS_NO_MEMORY;
2386 if (pwd_stat != NULL) {
2387 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2388 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2389 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2390 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2391 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2394 *_dominfo = dominfo;
2397 if (reject_reason != NULL) {
2398 if (pwd_stat != NULL) {
2399 *reject_reason = pwd_stat->reject_reason;
2401 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2405 if (pwd_stat != NULL) {
2406 talloc_free(pwd_stat);
2409 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2410 const char *errmsg = ldb_errstring(ldb);
2411 char *endptr = NULL;
2412 WERROR werr = WERR_GEN_FAILURE;
2413 status = NT_STATUS_UNSUCCESSFUL;
2414 if (errmsg != NULL) {
2415 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2416 DBG_WARNING("%s\n", errmsg);
2418 if (endptr != errmsg) {
2419 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2420 status = NT_STATUS_WRONG_PASSWORD;
2422 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2423 status = NT_STATUS_PASSWORD_RESTRICTION;
2426 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2427 /* don't let the caller know if an account doesn't exist */
2428 status = NT_STATUS_WRONG_PASSWORD;
2429 } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2430 status = NT_STATUS_ACCESS_DENIED;
2431 } else if (ret != LDB_SUCCESS) {
2432 DEBUG(1, ("Failed to set password on %s: %s\n",
2433 ldb_dn_get_linearized(user_dn),
2434 ldb_errstring(ldb)));
2435 status = NT_STATUS_UNSUCCESSFUL;
2441 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2442 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2443 const DATA_BLOB *new_password,
2444 const struct samr_Password *lmNewHash,
2445 const struct samr_Password *ntNewHash,
2446 const struct samr_Password *lmOldHash,
2447 const struct samr_Password *ntOldHash,
2448 enum samPwdChangeReason *reject_reason,
2449 struct samr_DomInfo1 **_dominfo)
2451 return samdb_set_password_internal(ldb, mem_ctx,
2454 lmNewHash, ntNewHash,
2455 lmOldHash, ntOldHash,
2456 reject_reason, _dominfo,
2457 false); /* reject trusts */
2461 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2462 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2463 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2464 * user change or not. The "rejectReason" gives some more information if the
2467 * This wrapper function for "samdb_set_password" takes a SID as input rather
2470 * This call encapsulates a new LDB transaction for changing the password;
2471 * therefore the user hasn't to start a new one.
2473 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2474 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2475 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2476 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2478 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2479 const struct dom_sid *user_sid,
2480 const uint32_t *new_version, /* optional for trusts */
2481 const DATA_BLOB *new_password,
2482 const struct samr_Password *lmNewHash,
2483 const struct samr_Password *ntNewHash,
2484 const struct samr_Password *lmOldHash,
2485 const struct samr_Password *ntOldHash,
2486 enum samPwdChangeReason *reject_reason,
2487 struct samr_DomInfo1 **_dominfo)
2489 TALLOC_CTX *frame = talloc_stackframe();
2491 const char * const user_attrs[] = {
2492 "userAccountControl",
2496 struct ldb_message *user_msg = NULL;
2500 ret = ldb_transaction_start(ldb);
2501 if (ret != LDB_SUCCESS) {
2502 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2504 return NT_STATUS_TRANSACTION_ABORTED;
2507 ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2508 LDB_SCOPE_SUBTREE, user_attrs, 0,
2509 "(&(objectSid=%s)(objectClass=user))",
2510 ldap_encode_ndr_dom_sid(frame, user_sid));
2511 if (ret != LDB_SUCCESS) {
2512 ldb_transaction_cancel(ldb);
2513 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2514 "returning NO_SUCH_USER\n",
2515 dom_sid_string(frame, user_sid),
2516 ldb_strerror(ret), ldb_errstring(ldb)));
2518 return NT_STATUS_NO_SUCH_USER;
2521 uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2522 if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2523 ldb_transaction_cancel(ldb);
2524 DEBUG(1, ("samdb_set_password_sid: invalid "
2525 "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2526 "returning NO_SUCH_USER\n",
2527 (unsigned)uac, dom_sid_string(frame, user_sid),
2528 ldb_dn_get_linearized(user_msg->dn)));
2530 return NT_STATUS_NO_SUCH_USER;
2533 if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2534 const char * const tdo_attrs[] = {
2535 "trustAuthIncoming",
2539 struct ldb_message *tdo_msg = NULL;
2540 const char *account_name = NULL;
2541 uint32_t trust_direction;
2543 const struct ldb_val *old_val = NULL;
2544 struct trustAuthInOutBlob old_blob = {
2547 uint32_t old_version = 0;
2548 struct AuthenticationInformation *old_version_a = NULL;
2549 uint32_t _new_version = 0;
2550 struct trustAuthInOutBlob new_blob = {
2553 struct ldb_val new_val = {
2556 struct timeval tv = timeval_current();
2557 NTTIME now = timeval_to_nttime(&tv);
2558 enum ndr_err_code ndr_err;
2560 if (new_password == NULL && ntNewHash == NULL) {
2561 ldb_transaction_cancel(ldb);
2562 DEBUG(1, ("samdb_set_password_sid: "
2563 "no new password provided "
2564 "sAMAccountName for SID[%s] DN[%s], "
2565 "returning INVALID_PARAMETER\n",
2566 dom_sid_string(frame, user_sid),
2567 ldb_dn_get_linearized(user_msg->dn)));
2569 return NT_STATUS_INVALID_PARAMETER;
2572 if (new_password != NULL && ntNewHash != NULL) {
2573 ldb_transaction_cancel(ldb);
2574 DEBUG(1, ("samdb_set_password_sid: "
2575 "two new passwords provided "
2576 "sAMAccountName for SID[%s] DN[%s], "
2577 "returning INVALID_PARAMETER\n",
2578 dom_sid_string(frame, user_sid),
2579 ldb_dn_get_linearized(user_msg->dn)));
2581 return NT_STATUS_INVALID_PARAMETER;
2584 if (new_password != NULL && (new_password->length % 2)) {
2585 ldb_transaction_cancel(ldb);
2586 DEBUG(2, ("samdb_set_password_sid: "
2587 "invalid utf16 length (%zu) "
2588 "sAMAccountName for SID[%s] DN[%s], "
2589 "returning WRONG_PASSWORD\n",
2590 new_password->length,
2591 dom_sid_string(frame, user_sid),
2592 ldb_dn_get_linearized(user_msg->dn)));
2594 return NT_STATUS_WRONG_PASSWORD;
2597 if (new_password != NULL && new_password->length >= 500) {
2598 ldb_transaction_cancel(ldb);
2599 DEBUG(2, ("samdb_set_password_sid: "
2600 "utf16 password too long (%zu) "
2601 "sAMAccountName for SID[%s] DN[%s], "
2602 "returning WRONG_PASSWORD\n",
2603 new_password->length,
2604 dom_sid_string(frame, user_sid),
2605 ldb_dn_get_linearized(user_msg->dn)));
2607 return NT_STATUS_WRONG_PASSWORD;
2610 account_name = ldb_msg_find_attr_as_string(user_msg,
2611 "sAMAccountName", NULL);
2612 if (account_name == NULL) {
2613 ldb_transaction_cancel(ldb);
2614 DEBUG(1, ("samdb_set_password_sid: missing "
2615 "sAMAccountName for SID[%s] DN[%s], "
2616 "returning NO_SUCH_USER\n",
2617 dom_sid_string(frame, user_sid),
2618 ldb_dn_get_linearized(user_msg->dn)));
2620 return NT_STATUS_NO_SUCH_USER;
2623 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2628 if (!NT_STATUS_IS_OK(nt_status)) {
2629 ldb_transaction_cancel(ldb);
2630 DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2631 "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2632 "returning INTERNAL_DB_CORRUPTION\n",
2633 nt_errstr(nt_status), account_name,
2634 dom_sid_string(frame, user_sid),
2635 ldb_dn_get_linearized(user_msg->dn)));
2637 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2640 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2641 "trustDirection", 0);
2642 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2643 ldb_transaction_cancel(ldb);
2644 DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2645 "not inbound for sAMAccountName[%s] "
2647 "returning INTERNAL_DB_CORRUPTION\n",
2648 (unsigned)trust_direction,
2650 ldb_dn_get_linearized(user_msg->dn),
2651 ldb_dn_get_linearized(tdo_msg->dn)));
2653 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2656 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2657 if (old_val != NULL) {
2658 ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2659 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2660 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2661 ldb_transaction_cancel(ldb);
2662 DEBUG(1, ("samdb_set_password_sid: "
2663 "failed(%s) to parse "
2664 "trustAuthOutgoing sAMAccountName[%s] "
2666 "returning INTERNAL_DB_CORRUPTION\n",
2667 ndr_map_error2string(ndr_err),
2669 ldb_dn_get_linearized(user_msg->dn),
2670 ldb_dn_get_linearized(tdo_msg->dn)));
2673 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2677 for (i = old_blob.current.count; i > 0; i--) {
2678 struct AuthenticationInformation *a =
2679 &old_blob.current.array[i - 1];
2681 switch (a->AuthType) {
2682 case TRUST_AUTH_TYPE_NONE:
2683 if (i == old_blob.current.count) {
2685 * remove TRUST_AUTH_TYPE_NONE at the
2688 old_blob.current.count--;
2692 case TRUST_AUTH_TYPE_VERSION:
2694 old_version = a->AuthInfo.version.version;
2697 case TRUST_AUTH_TYPE_CLEAR:
2700 case TRUST_AUTH_TYPE_NT4OWF:
2705 if (new_version == NULL) {
2707 new_version = &_new_version;
2710 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2711 old_version_a->LastUpdateTime = now;
2712 old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2715 new_blob.count = MAX(old_blob.current.count, 2);
2716 new_blob.current.array = talloc_zero_array(frame,
2717 struct AuthenticationInformation,
2719 if (new_blob.current.array == NULL) {
2720 ldb_transaction_cancel(ldb);
2722 return NT_STATUS_NO_MEMORY;
2724 new_blob.previous.array = talloc_zero_array(frame,
2725 struct AuthenticationInformation,
2727 if (new_blob.current.array == NULL) {
2728 ldb_transaction_cancel(ldb);
2730 return NT_STATUS_NO_MEMORY;
2733 for (i = 0; i < old_blob.current.count; i++) {
2734 struct AuthenticationInformation *o =
2735 &old_blob.current.array[i];
2736 struct AuthenticationInformation *p =
2737 &new_blob.previous.array[i];
2740 new_blob.previous.count++;
2742 for (; i < new_blob.count; i++) {
2743 struct AuthenticationInformation *pi =
2744 &new_blob.previous.array[i];
2748 * new_blob.previous is still empty so
2749 * we'll do new_blob.previous = new_blob.current
2755 pi->LastUpdateTime = now;
2756 pi->AuthType = TRUST_AUTH_TYPE_NONE;
2757 new_blob.previous.count++;
2760 for (i = 0; i < new_blob.count; i++) {
2761 struct AuthenticationInformation *ci =
2762 &new_blob.current.array[i];
2764 ci->LastUpdateTime = now;
2767 if (ntNewHash != NULL) {
2768 ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2769 ci->AuthInfo.nt4owf.password = *ntNewHash;
2773 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2774 ci->AuthInfo.clear.size = new_password->length;
2775 ci->AuthInfo.clear.password = new_password->data;
2778 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2779 ci->AuthInfo.version.version = *new_version;
2782 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2786 new_blob.current.count++;
2789 if (new_blob.previous.count == 0) {
2790 TALLOC_FREE(new_blob.previous.array);
2791 new_blob.previous = new_blob.current;
2794 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2795 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2796 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2797 ldb_transaction_cancel(ldb);
2798 DEBUG(1, ("samdb_set_password_sid: "
2799 "failed(%s) to generate "
2800 "trustAuthOutgoing sAMAccountName[%s] "
2802 "returning UNSUCCESSFUL\n",
2803 ndr_map_error2string(ndr_err),
2805 ldb_dn_get_linearized(user_msg->dn),
2806 ldb_dn_get_linearized(tdo_msg->dn)));
2808 return NT_STATUS_UNSUCCESSFUL;
2811 tdo_msg->num_elements = 0;
2812 TALLOC_FREE(tdo_msg->elements);
2814 ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
2815 LDB_FLAG_MOD_REPLACE, NULL);
2816 if (ret != LDB_SUCCESS) {
2817 ldb_transaction_cancel(ldb);
2819 return NT_STATUS_NO_MEMORY;
2821 ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
2823 if (ret != LDB_SUCCESS) {
2824 ldb_transaction_cancel(ldb);
2826 return NT_STATUS_NO_MEMORY;
2829 ret = ldb_modify(ldb, tdo_msg);
2830 if (ret != LDB_SUCCESS) {
2831 nt_status = dsdb_ldb_err_to_ntstatus(ret);
2832 ldb_transaction_cancel(ldb);
2833 DEBUG(1, ("samdb_set_password_sid: "
2834 "failed to replace "
2835 "trustAuthOutgoing sAMAccountName[%s] "
2839 ldb_dn_get_linearized(user_msg->dn),
2840 ldb_dn_get_linearized(tdo_msg->dn),
2841 nt_errstr(nt_status), ldb_errstring(ldb)));
2847 nt_status = samdb_set_password_internal(ldb, mem_ctx,
2850 lmNewHash, ntNewHash,
2851 lmOldHash, ntOldHash,
2852 reject_reason, _dominfo,
2853 true); /* permit trusts */
2854 if (!NT_STATUS_IS_OK(nt_status)) {
2855 ldb_transaction_cancel(ldb);
2860 ret = ldb_transaction_commit(ldb);
2861 if (ret != LDB_SUCCESS) {
2862 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2863 ldb_dn_get_linearized(user_msg->dn),
2864 ldb_errstring(ldb)));
2866 return NT_STATUS_TRANSACTION_ABORTED;
2870 return NT_STATUS_OK;
2874 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2875 struct dom_sid *sid, struct ldb_dn **ret_dn)
2877 struct ldb_message *msg;
2878 struct ldb_dn *basedn = NULL;
2882 sidstr = dom_sid_string(mem_ctx, sid);
2883 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2885 /* We might have to create a ForeignSecurityPrincipal, even if this user
2886 * is in our own domain */
2888 msg = ldb_msg_new(sidstr);
2890 talloc_free(sidstr);
2891 return NT_STATUS_NO_MEMORY;
2894 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2895 ldb_get_default_basedn(sam_ctx),
2896 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2898 if (ret != LDB_SUCCESS) {
2899 DEBUG(0, ("Failed to find DN for "
2900 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2901 talloc_free(sidstr);
2902 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2905 /* add core elements to the ldb_message for the alias */
2907 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2908 talloc_free(sidstr);
2909 return NT_STATUS_NO_MEMORY;
2912 ret = ldb_msg_add_string(msg, "objectClass",
2913 "foreignSecurityPrincipal");
2914 if (ret != LDB_SUCCESS) {
2915 talloc_free(sidstr);
2916 return NT_STATUS_NO_MEMORY;
2919 /* create the alias */
2920 ret = ldb_add(sam_ctx, msg);
2921 if (ret != LDB_SUCCESS) {
2922 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2924 ldb_dn_get_linearized(msg->dn),
2925 ldb_errstring(sam_ctx)));
2926 talloc_free(sidstr);
2927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2930 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2931 talloc_free(sidstr);
2933 return NT_STATUS_OK;
2938 Find the DN of a domain, assuming it to be a dotted.dns name
2941 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2944 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2945 const char *binary_encoded;
2946 const char * const *split_realm;
2953 split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
2955 talloc_free(tmp_ctx);
2958 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2959 for (i=0; split_realm[i]; i++) {
2960 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2961 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2962 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2963 binary_encoded, ldb_dn_get_linearized(dn)));
2964 talloc_free(tmp_ctx);
2968 if (!ldb_dn_validate(dn)) {
2969 DEBUG(2, ("Failed to validated DN %s\n",
2970 ldb_dn_get_linearized(dn)));
2971 talloc_free(tmp_ctx);
2974 talloc_free(tmp_ctx);
2980 Find the DNS equivalent of a DN, in dotted DNS form
2982 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
2984 int i, num_components = ldb_dn_get_comp_num(dn);
2985 char *dns_name = talloc_strdup(mem_ctx, "");
2986 if (dns_name == NULL) {
2990 for (i=0; i<num_components; i++) {
2991 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
2994 talloc_free(dns_name);
2997 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
2998 (int)v->length, (int)v->length, (char *)v->data);
3000 talloc_free(dns_name);
3006 /* remove the last '.' */
3007 if (dns_name[0] != 0) {
3008 dns_name[strlen(dns_name)-1] = 0;
3015 Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
3016 name is based on the forest DNS name
3018 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
3019 TALLOC_CTX *mem_ctx,
3020 const struct GUID *ntds_guid)
3022 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3023 const char *guid_str;
3024 struct ldb_dn *forest_dn;
3025 const char *dnsforest;
3028 guid_str = GUID_string(tmp_ctx, ntds_guid);
3029 if (guid_str == NULL) {
3030 talloc_free(tmp_ctx);
3033 forest_dn = ldb_get_root_basedn(samdb);
3034 if (forest_dn == NULL) {
3035 talloc_free(tmp_ctx);
3038 dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
3039 if (dnsforest == NULL) {
3040 talloc_free(tmp_ctx);
3043 ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
3044 talloc_free(tmp_ctx);
3050 Find the DN of a domain, be it the netbios or DNS name
3052 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
3053 const char *domain_name)
3055 const char * const domain_ref_attrs[] = {
3058 const char * const domain_ref2_attrs[] = {
3061 struct ldb_result *res_domain_ref;
3062 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
3063 /* find the domain's DN */
3064 int ret_domain = ldb_search(ldb, mem_ctx,
3066 samdb_partitions_dn(ldb, mem_ctx),
3069 "(&(nETBIOSName=%s)(objectclass=crossRef))",
3071 if (ret_domain != LDB_SUCCESS) {
3075 if (res_domain_ref->count == 0) {
3076 ret_domain = ldb_search(ldb, mem_ctx,
3078 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
3081 "(objectclass=domain)");
3082 if (ret_domain != LDB_SUCCESS) {
3086 if (res_domain_ref->count == 1) {
3087 return res_domain_ref->msgs[0]->dn;
3092 if (res_domain_ref->count > 1) {
3093 DEBUG(0,("Found %d records matching domain [%s]\n",
3094 ret_domain, domain_name));
3098 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3104 use a GUID to find a DN
3106 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
3107 TALLOC_CTX *mem_ctx,
3108 const struct GUID *guid,
3109 uint32_t dsdb_flags,
3113 struct ldb_result *res;
3114 const char *attrs[] = { NULL };
3115 char *guid_str = GUID_string(mem_ctx, guid);
3118 return ldb_operr(ldb);
3121 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3122 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3123 DSDB_SEARCH_SHOW_EXTENDED_DN |
3124 DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3125 "objectGUID=%s", guid_str);
3126 talloc_free(guid_str);
3127 if (ret != LDB_SUCCESS) {
3131 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3138 use a DN to find a GUID with a given attribute name
3140 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3141 struct ldb_dn *dn, const char *attribute,
3145 struct ldb_result *res = NULL;
3146 const char *attrs[2];
3147 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3149 attrs[0] = attribute;
3152 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3153 DSDB_SEARCH_SHOW_DELETED |
3154 DSDB_SEARCH_SHOW_RECYCLED);
3155 if (ret != LDB_SUCCESS) {
3156 talloc_free(tmp_ctx);
3161 talloc_free(tmp_ctx);
3162 return LDB_ERR_OTHER;
3164 if (res->count < 1) {
3165 talloc_free(tmp_ctx);
3166 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3168 *guid = samdb_result_guid(res->msgs[0], attribute);
3169 talloc_free(tmp_ctx);
3174 use a DN to find a GUID
3176 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3177 struct ldb_dn *dn, struct GUID *guid)
3179 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3185 adds the given GUID to the given ldb_message. This value is added
3186 for the given attr_name (may be either "objectGUID" or "parentGUID").
3188 int dsdb_msg_add_guid(struct ldb_message *msg,
3190 const char *attr_name)
3195 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
3197 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3198 if (!NT_STATUS_IS_OK(status)) {
3199 ret = LDB_ERR_OPERATIONS_ERROR;
3203 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3204 if (ret != LDB_SUCCESS) {
3205 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3213 talloc_free(tmp_ctx);
3220 use a DN to find a SID
3222 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
3223 struct ldb_dn *dn, struct dom_sid *sid)
3226 struct ldb_result *res = NULL;
3227 const char *attrs[] = { "objectSid", NULL };
3228 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3233 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3234 DSDB_SEARCH_SHOW_DELETED |
3235 DSDB_SEARCH_SHOW_RECYCLED);
3236 if (ret != LDB_SUCCESS) {
3237 talloc_free(tmp_ctx);
3241 talloc_free(tmp_ctx);
3242 return LDB_ERR_OTHER;
3244 if (res->count < 1) {
3245 talloc_free(tmp_ctx);
3246 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3248 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3250 talloc_free(tmp_ctx);
3251 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3254 talloc_free(tmp_ctx);
3259 use a SID to find a DN
3261 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3262 TALLOC_CTX *mem_ctx,
3263 struct dom_sid *sid, struct ldb_dn **dn)
3266 struct ldb_result *res;
3267 const char *attrs[] = { NULL };
3268 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3271 return ldb_operr(ldb);
3274 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3275 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3276 DSDB_SEARCH_SHOW_EXTENDED_DN |
3277 DSDB_SEARCH_ONE_ONLY,
3278 "objectSid=%s", sid_str);
3279 talloc_free(sid_str);
3280 if (ret != LDB_SUCCESS) {
3284 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3291 load a repsFromTo blob list for a given partition GUID
3292 attr must be "repsFrom" or "repsTo"
3294 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3295 const char *attr, struct repsFromToBlob **r, uint32_t *count)
3297 const char *attrs[] = { attr, NULL };
3298 struct ldb_result *res = NULL;
3299 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3301 struct ldb_message_element *el;
3307 ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3308 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3309 /* partition hasn't been replicated yet */
3312 if (ret != LDB_SUCCESS) {
3313 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3314 talloc_free(tmp_ctx);
3315 return WERR_DS_DRA_INTERNAL_ERROR;
3320 talloc_free(tmp_ctx);
3321 return WERR_DS_DRA_INTERNAL_ERROR;
3323 el = ldb_msg_find_element(res->msgs[0], attr);
3325 /* it's OK to be empty */
3326 talloc_free(tmp_ctx);
3330 *count = el->num_values;
3331 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3333 talloc_free(tmp_ctx);
3334 return WERR_DS_DRA_INTERNAL_ERROR;
3337 for (i=0; i<(*count); i++) {
3338 enum ndr_err_code ndr_err;
3339 ndr_err = ndr_pull_struct_blob(&el->values[i],
3342 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3343 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3344 talloc_free(tmp_ctx);
3345 return WERR_DS_DRA_INTERNAL_ERROR;
3349 talloc_free(tmp_ctx);
3355 save the repsFromTo blob list for a given partition GUID
3356 attr must be "repsFrom" or "repsTo"
3358 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3359 const char *attr, struct repsFromToBlob *r, uint32_t count)
3361 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3362 struct ldb_message *msg;
3363 struct ldb_message_element *el;
3366 msg = ldb_msg_new(tmp_ctx);
3368 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3372 el->values = talloc_array(msg, struct ldb_val, count);
3377 for (i=0; i<count; i++) {
3379 enum ndr_err_code ndr_err;
3381 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
3383 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3392 if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3393 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3397 talloc_free(tmp_ctx);
3402 talloc_free(tmp_ctx);
3403 return WERR_DS_DRA_INTERNAL_ERROR;
3408 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3409 object for a partition
3411 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3412 uint64_t *uSN, uint64_t *urgent_uSN)
3414 struct ldb_request *req;
3416 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3417 struct dsdb_control_current_partition *p_ctrl;
3418 struct ldb_result *res;
3420 res = talloc_zero(tmp_ctx, struct ldb_result);
3422 talloc_free(tmp_ctx);
3423 return ldb_oom(ldb);
3426 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3427 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3431 res, ldb_search_default_callback,
3433 if (ret != LDB_SUCCESS) {
3434 talloc_free(tmp_ctx);
3438 p_ctrl = talloc(req, struct dsdb_control_current_partition);
3439 if (p_ctrl == NULL) {
3440 talloc_free(tmp_ctx);
3441 return ldb_oom(ldb);
3443 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3446 ret = ldb_request_add_control(req,
3447 DSDB_CONTROL_CURRENT_PARTITION_OID,
3449 if (ret != LDB_SUCCESS) {
3450 talloc_free(tmp_ctx);
3454 /* Run the new request */
3455 ret = ldb_request(ldb, req);
3457 if (ret == LDB_SUCCESS) {
3458 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3461 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3462 /* it hasn't been created yet, which means
3463 an implicit value of zero */
3465 talloc_free(tmp_ctx);
3469 if (ret != LDB_SUCCESS) {
3470 talloc_free(tmp_ctx);
3474 if (res->count < 1) {
3480 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3482 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3486 talloc_free(tmp_ctx);
3491 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3492 const struct drsuapi_DsReplicaCursor2 *c2)
3494 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3497 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3498 const struct drsuapi_DsReplicaCursor *c2)
3500 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3505 see if a computer identified by its invocationId is a RODC
3507 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3509 /* 1) find the DN for this servers NTDSDSA object
3510 2) search for the msDS-isRODC attribute
3511 3) if not present then not a RODC
3512 4) if present and TRUE then is a RODC
3514 struct ldb_dn *config_dn;
3515 const char *attrs[] = { "msDS-isRODC", NULL };
3517 struct ldb_result *res;
3518 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3520 config_dn = ldb_get_config_basedn(sam_ctx);
3522 talloc_free(tmp_ctx);
3523 return ldb_operr(sam_ctx);
3526 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
3527 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
3529 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3531 talloc_free(tmp_ctx);
3535 if (ret != LDB_SUCCESS) {
3536 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
3537 GUID_string(tmp_ctx, objectGUID)));
3539 talloc_free(tmp_ctx);
3543 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
3544 *is_rodc = (ret == 1);
3546 talloc_free(tmp_ctx);
3552 see if we are a RODC
3554 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3556 const struct GUID *objectGUID;
3560 /* see if we have a cached copy */
3561 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3567 objectGUID = samdb_ntds_objectGUID(sam_ctx);
3569 return ldb_operr(sam_ctx);
3572 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3573 if (ret != LDB_SUCCESS) {
3577 cached = talloc(sam_ctx, bool);
3578 if (cached == NULL) {
3579 return ldb_oom(sam_ctx);
3583 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3584 if (ret != LDB_SUCCESS) {
3585 talloc_free(cached);
3586 return ldb_operr(sam_ctx);
3592 int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
3594 const char *_host_name = NULL;
3595 const char *attrs[] = { "dnsHostName", NULL };
3596 TALLOC_CTX *tmp_ctx = NULL;
3598 struct ldb_result *res = NULL;
3600 _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
3601 if (_host_name != NULL) {
3602 *host_name = _host_name;
3606 tmp_ctx = talloc_new(sam_ctx);
3608 ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
3610 if (res == NULL || res->count != 1 || ret != LDB_SUCCESS) {
3611 DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s",
3612 ldb_errstring(sam_ctx)));
3613 TALLOC_FREE(tmp_ctx);
3617 _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
3620 if (_host_name == NULL) {
3621 DEBUG(0, ("Failed to get dnsHostName from rootDSE"));
3622 TALLOC_FREE(tmp_ctx);
3623 return LDB_ERR_OPERATIONS_ERROR;
3625 ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
3626 discard_const_p(char *, _host_name));
3627 if (ret != LDB_SUCCESS) {
3628 TALLOC_FREE(tmp_ctx);
3629 return ldb_operr(sam_ctx);
3632 *host_name = talloc_steal(sam_ctx, _host_name);
3634 TALLOC_FREE(tmp_ctx);
3638 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3640 TALLOC_CTX *tmp_ctx;
3643 tmp_ctx = talloc_new(ldb);
3644 if (tmp_ctx == NULL) {
3648 cached = talloc(tmp_ctx, bool);
3654 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3658 talloc_steal(ldb, cached);
3659 talloc_free(tmp_ctx);
3663 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3664 talloc_free(tmp_ctx);
3670 * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3671 * flags are DS_NTDSSETTINGS_OPT_*
3673 int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3677 TALLOC_CTX *tmp_ctx;
3678 struct ldb_result *res;
3679 struct ldb_dn *site_dn;
3680 const char *attrs[] = { "options", NULL };
3682 tmp_ctx = talloc_new(ldb_ctx);
3683 if (tmp_ctx == NULL)
3686 /* Retrieve the site dn for the ldb that we
3687 * have open. This is our local site.
3689 site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3690 if (site_dn == NULL)
3693 /* Perform a one level (child) search from the local
3694 * site distinguided name. We're looking for the
3695 * "options" attribute within the nTDSSiteSettings
3698 rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
3699 LDB_SCOPE_ONELEVEL, attrs,
3700 "objectClass=nTDSSiteSettings");
3702 if (rc != LDB_SUCCESS || res->count != 1)
3705 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3707 talloc_free(tmp_ctx);
3712 DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
3713 talloc_free(tmp_ctx);
3714 return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
3718 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
3720 flags are DS_NTDS_OPTION_*
3722 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3724 TALLOC_CTX *tmp_ctx;
3725 const char *attrs[] = { "options", NULL };
3727 struct ldb_result *res;
3729 tmp_ctx = talloc_new(ldb);
3730 if (tmp_ctx == NULL) {
3734 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3735 if (ret != LDB_SUCCESS) {
3739 if (res->count != 1) {
3743 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3745 talloc_free(tmp_ctx);
3750 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3751 talloc_free(tmp_ctx);
3752 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3755 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3757 const char *attrs[] = { "objectCategory", NULL };
3759 struct ldb_result *res;
3761 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3762 if (ret != LDB_SUCCESS) {
3766 if (res->count != 1) {
3770 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3773 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3778 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3779 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3781 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3783 char **tokens, *ret;
3786 tokens = str_list_make(mem_ctx, cn, " -_");
3787 if (tokens == NULL || tokens[0] == NULL) {
3791 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3792 tokens[0][0] = tolower(tokens[0][0]);
3793 for (i = 1; tokens[i] != NULL; i++)
3794 tokens[i][0] = toupper(tokens[i][0]);
3796 ret = talloc_strdup(mem_ctx, tokens[0]);
3797 for (i = 1; tokens[i] != NULL; i++)
3798 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3800 talloc_free(tokens);
3806 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3808 int dsdb_functional_level(struct ldb_context *ldb)
3810 int *domainFunctionality =
3811 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3812 if (!domainFunctionality) {
3813 /* this is expected during initial provision */
3814 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3815 return DS_DOMAIN_FUNCTION_2000;
3817 return *domainFunctionality;
3821 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3823 int dsdb_forest_functional_level(struct ldb_context *ldb)
3825 int *forestFunctionality =
3826 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3827 if (!forestFunctionality) {
3828 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3829 return DS_DOMAIN_FUNCTION_2000;
3831 return *forestFunctionality;
3835 set a GUID in an extended DN structure
3837 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3843 status = GUID_to_ndr_blob(guid, dn, &v);
3844 if (!NT_STATUS_IS_OK(status)) {
3845 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3848 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3854 return a GUID from a extended DN structure
3856 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3858 const struct ldb_val *v;
3860 v = ldb_dn_get_extended_component(dn, component_name);
3862 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3865 return GUID_from_ndr_blob(v, guid);
3869 return a uint64_t from a extended DN structure
3871 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3873 const struct ldb_val *v;
3876 v = ldb_dn_get_extended_component(dn, component_name);
3878 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3881 /* Just check we don't allow the caller to fill our stack */
3882 if (v->length >= 64) {
3883 return NT_STATUS_INVALID_PARAMETER;
3885 char s[v->length+1];
3886 memcpy(s, v->data, v->length);
3889 *val = smb_strtoull(s, NULL, 0, &error, SMB_STR_STANDARD);
3891 return NT_STATUS_INVALID_PARAMETER;
3894 return NT_STATUS_OK;
3898 return a NTTIME from a extended DN structure
3900 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3902 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3906 return a uint32_t from a extended DN structure
3908 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3910 const struct ldb_val *v;
3913 v = ldb_dn_get_extended_component(dn, component_name);
3915 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3918 /* Just check we don't allow the caller to fill our stack */
3919 if (v->length >= 32) {
3920 return NT_STATUS_INVALID_PARAMETER;
3922 char s[v->length + 1];
3923 memcpy(s, v->data, v->length);
3925 *val = smb_strtoul(s, NULL, 0, &error, SMB_STR_STANDARD);
3927 return NT_STATUS_INVALID_PARAMETER;
3931 return NT_STATUS_OK;
3935 return a dom_sid from a extended DN structure
3937 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3939 const struct ldb_val *sid_blob;
3940 enum ndr_err_code ndr_err;
3942 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3944 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3947 ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
3948 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3949 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3950 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3954 return NT_STATUS_OK;
3959 return RMD_FLAGS directly from a ldb_dn
3960 returns 0 if not found
3962 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3964 uint32_t rmd_flags = 0;
3965 NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
3967 if (NT_STATUS_IS_OK(status)) {
3974 return RMD_FLAGS directly from a ldb_val for a DN
3975 returns 0 if RMD_FLAGS is not found
3977 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3984 if (val->length < 13) {
3987 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3991 flags = smb_strtoul(p+11, &end, 10, &error, SMB_STR_STANDARD);
3992 if (!end || *end != '>' || error != 0) {
3993 /* it must end in a > */
4000 return true if a ldb_val containing a DN in storage form is deleted
4002 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
4004 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
4008 return true if a ldb_val containing a DN in storage form is
4009 in the upgraded w2k3 linked attribute format
4011 bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
4013 return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
4017 return a DN for a wellknown GUID
4019 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
4020 struct ldb_dn *nc_root, const char *wk_guid,
4021 struct ldb_dn **wkguid_dn)
4023 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4024 const char *attrs[] = { NULL };
4027 struct ldb_result *res = NULL;
4029 /* construct the magic WKGUID DN */
4030 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
4031 wk_guid, ldb_dn_get_linearized(nc_root));
4033 talloc_free(tmp_ctx);
4034 return ldb_operr(samdb);
4037 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
4038 DSDB_SEARCH_SHOW_DELETED |
4039 DSDB_SEARCH_SHOW_RECYCLED);
4040 if (ret != LDB_SUCCESS) {
4041 talloc_free(tmp_ctx);
4044 /* fix clang warning */
4046 talloc_free(tmp_ctx);
4047 return LDB_ERR_OTHER;
4050 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
4051 talloc_free(tmp_ctx);
4056 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
4058 return ldb_dn_compare(*dn1, *dn2);
4062 find a NC root given a DN within the NC
4064 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
4065 struct ldb_dn **nc_root)
4067 const char *root_attrs[] = { "namingContexts", NULL };
4068 TALLOC_CTX *tmp_ctx;
4070 struct ldb_message_element *el;
4071 struct ldb_result *root_res;
4073 struct ldb_dn **nc_dns;
4075 tmp_ctx = talloc_new(samdb);
4076 if (tmp_ctx == NULL) {
4077 return ldb_oom(samdb);
4080 ret = ldb_search(samdb, tmp_ctx, &root_res,
4081 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
4082 if (ret != LDB_SUCCESS || root_res->count == 0) {
4083 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
4084 talloc_free(tmp_ctx);
4088 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
4089 if ((el == NULL) || (el->num_values < 3)) {
4090 struct ldb_message *tmp_msg;
4092 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
4094 /* This generates a temporary list of NCs in order to let the
4095 * provisioning work. */
4096 tmp_msg = ldb_msg_new(tmp_ctx);
4097 if (tmp_msg == NULL) {
4098 talloc_free(tmp_ctx);
4099 return ldb_oom(samdb);
4101 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4102 ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
4103 if (ret != LDB_SUCCESS) {
4104 talloc_free(tmp_ctx);
4107 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4108 ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
4109 if (ret != LDB_SUCCESS) {
4110 talloc_free(tmp_ctx);
4113 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4114 ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
4115 if (ret != LDB_SUCCESS) {
4116 talloc_free(tmp_ctx);
4119 el = &tmp_msg->elements[0];
4122 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
4124 talloc_free(tmp_ctx);
4125 return ldb_oom(samdb);
4128 for (i=0; i<el->num_values; i++) {
4129 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
4130 if (nc_dns[i] == NULL) {
4131 talloc_free(tmp_ctx);
4132 return ldb_operr(samdb);
4136 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
4138 for (i=0; i<el->num_values; i++) {
4139 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
4140 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
4141 talloc_free(tmp_ctx);
4146 talloc_free(tmp_ctx);
4147 return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4152 find the deleted objects DN for any object, by looking for the NC
4153 root, then looking up the wellknown GUID
4155 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
4156 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
4157 struct ldb_dn **do_dn)
4159 struct ldb_dn *nc_root;
4162 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
4163 if (ret != LDB_SUCCESS) {
4167 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
4168 talloc_free(nc_root);
4173 return the tombstoneLifetime, in days
4175 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
4178 dn = ldb_get_config_basedn(ldb);
4180 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4182 dn = ldb_dn_copy(ldb, dn);
4184 return ldb_operr(ldb);
4186 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
4187 be a wellknown GUID for this */
4188 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
4190 return ldb_operr(ldb);
4193 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
4199 compare a ldb_val to a string case insensitively
4201 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
4203 size_t len = strlen(s);
4205 if (len > v->length) return 1;
4206 ret = strncasecmp(s, (const char *)v->data, v->length);
4207 if (ret != 0) return ret;
4208 if (v->length > len && v->data[len] != 0) {
4216 load the UDV for a partition in v2 format
4217 The list is returned sorted, and with our local cursor added
4219 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4220 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
4222 static const char *attrs[] = { "replUpToDateVector", NULL };
4223 struct ldb_result *r = NULL;
4224 const struct ldb_val *ouv_value;
4227 uint64_t highest_usn = 0;
4228 const struct GUID *our_invocation_id;
4229 static const struct timeval tv1970;
4230 NTTIME nt1970 = timeval_to_nttime(&tv1970);
4232 ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
4233 if (ret != LDB_SUCCESS) {
4236 /* fix clang warning */
4238 return LDB_ERR_OTHER;
4240 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
4242 enum ndr_err_code ndr_err;
4243 struct replUpToDateVectorBlob ouv;
4245 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
4246 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4247 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4249 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4251 if (ouv.version != 2) {
4252 /* we always store as version 2, and
4253 * replUpToDateVector is not replicated
4255 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4258 *count = ouv.ctr.ctr2.count;
4259 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
4267 our_invocation_id = samdb_ntds_invocation_id(samdb);
4268 if (!our_invocation_id) {
4269 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
4270 talloc_free(*cursors);
4271 return ldb_operr(samdb);
4274 ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
4275 if (ret != LDB_SUCCESS) {
4276 /* nothing to add - this can happen after a vampire */
4277 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4281 for (i=0; i<*count; i++) {
4282 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
4283 (*cursors)[i].highest_usn = highest_usn;
4284 (*cursors)[i].last_sync_success = nt1970;
4285 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4290 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
4292 return ldb_oom(samdb);
4295 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
4296 (*cursors)[*count].highest_usn = highest_usn;
4297 (*cursors)[*count].last_sync_success = nt1970;
4300 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4306 load the UDV for a partition in version 1 format
4307 The list is returned sorted, and with our local cursor added
4309 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4310 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
4312 struct drsuapi_DsReplicaCursor2 *v2 = NULL;
4316 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
4317 if (ret != LDB_SUCCESS) {
4327 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
4328 if (*cursors == NULL) {
4330 return ldb_oom(samdb);
4333 for (i=0; i<*count; i++) {
4334 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
4335 (*cursors)[i].highest_usn = v2[i].highest_usn;
4342 add a set of controls to a ldb_request structure based on a set of
4343 flags. See util.h for a list of available flags
4345 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
4348 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
4349 struct ldb_search_options_control *options;
4350 /* Using the phantom root control allows us to search all partitions */
4351 options = talloc(req, struct ldb_search_options_control);
4352 if (options == NULL) {
4353 return LDB_ERR_OPERATIONS_ERROR;
4355 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4357 ret = ldb_request_add_control(req,
4358 LDB_CONTROL_SEARCH_OPTIONS_OID,
4360 if (ret != LDB_SUCCESS) {
4365 if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
4366 ret = ldb_request_add_control(req,
4367 DSDB_CONTROL_NO_GLOBAL_CATALOG,
4369 if (ret != LDB_SUCCESS) {
4374 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
4375 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
4376 if (ret != LDB_SUCCESS) {
4381 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
4382 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
4383 if (ret != LDB_SUCCESS) {
4388 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
4389 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
4390 if (ret != LDB_SUCCESS) {
4395 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
4396 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
4397 if (!extended_ctrl) {
4398 return LDB_ERR_OPERATIONS_ERROR;
4400 extended_ctrl->type = 1;
4402 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
4403 if (ret != LDB_SUCCESS) {
4408 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
4409 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
4410 if (ret != LDB_SUCCESS) {
4415 if (dsdb_flags & DSDB_MODIFY_RELAX) {
4416 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
4417 if (ret != LDB_SUCCESS) {
4422 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
4423 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
4424 if (ret != LDB_SUCCESS) {
4429 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
4430 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
4431 if (ret != LDB_SUCCESS) {
4436 if (dsdb_flags & DSDB_TREE_DELETE) {
4437 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
4438 if (ret != LDB_SUCCESS) {
4443 if (dsdb_flags & DSDB_PROVISION) {
4444 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
4445 if (ret != LDB_SUCCESS) {
4450 /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
4451 if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
4452 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
4453 if (ret != LDB_SUCCESS) {
4458 if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
4460 * This must not be critical, as it will only be
4461 * handled (and need to be handled) if the other
4462 * attributes in the request bring password_hash into
4465 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
4466 if (ret != LDB_SUCCESS) {
4471 if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
4472 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
4473 if (ret != LDB_SUCCESS) {
4478 if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
4479 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
4480 if (ret != LDB_SUCCESS) {
4485 if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
4486 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4487 if (ret != LDB_SUCCESS) {
4496 returns true if a control with the specified "oid" exists
4498 bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
4500 return (ldb_request_get_control(req, oid) != NULL);
4504 an add with a set of controls
4506 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
4507 uint32_t dsdb_flags)
4509 struct ldb_request *req;
4512 ret = ldb_build_add_req(&req, ldb, ldb,
4516 ldb_op_default_callback,
4519 if (ret != LDB_SUCCESS) return ret;
4521 ret = dsdb_request_add_controls(req, dsdb_flags);
4522 if (ret != LDB_SUCCESS) {
4527 ret = dsdb_autotransaction_request(ldb, req);
4534 a modify with a set of controls
4536 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
4537 uint32_t dsdb_flags)
4539 struct ldb_request *req;
4542 ret = ldb_build_mod_req(&req, ldb, ldb,
4546 ldb_op_default_callback,
4549 if (ret != LDB_SUCCESS) return ret;
4551 ret = dsdb_request_add_controls(req, dsdb_flags);
4552 if (ret != LDB_SUCCESS) {
4557 ret = dsdb_autotransaction_request(ldb, req);
4564 a delete with a set of flags
4566 int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
4567 uint32_t dsdb_flags)
4569 struct ldb_request *req;
4572 ret = ldb_build_del_req(&req, ldb, ldb,
4576 ldb_op_default_callback,
4579 if (ret != LDB_SUCCESS) return ret;
4581 ret = dsdb_request_add_controls(req, dsdb_flags);
4582 if (ret != LDB_SUCCESS) {
4587 ret = dsdb_autotransaction_request(ldb, req);
4594 like dsdb_modify() but set all the element flags to
4595 LDB_FLAG_MOD_REPLACE
4597 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
4601 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
4602 for (i=0;i<msg->num_elements;i++) {
4603 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4606 return dsdb_modify(ldb, msg, dsdb_flags);
4611 search for attrs on one DN, allowing for dsdb_flags controls
4613 int dsdb_search_dn(struct ldb_context *ldb,
4614 TALLOC_CTX *mem_ctx,
4615 struct ldb_result **_result,
4616 struct ldb_dn *basedn,
4617 const char * const *attrs,
4618 uint32_t dsdb_flags)
4621 struct ldb_request *req;
4622 struct ldb_result *res;
4624 res = talloc_zero(mem_ctx, struct ldb_result);
4626 return ldb_oom(ldb);
4629 ret = ldb_build_search_req(&req, ldb, res,
4636 ldb_search_default_callback,
4638 if (ret != LDB_SUCCESS) {
4643 ret = dsdb_request_add_controls(req, dsdb_flags);
4644 if (ret != LDB_SUCCESS) {
4649 ret = ldb_request(ldb, req);
4650 if (ret == LDB_SUCCESS) {
4651 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4655 if (ret != LDB_SUCCESS) {
4665 search for attrs on one DN, by the GUID of the DN, allowing for
4668 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
4669 TALLOC_CTX *mem_ctx,
4670 struct ldb_result **_result,
4671 const struct GUID *guid,
4672 const char * const *attrs,
4673 uint32_t dsdb_flags)
4675 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4679 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
4681 talloc_free(tmp_ctx);
4682 return ldb_oom(ldb);
4685 ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
4686 talloc_free(tmp_ctx);
4691 general search with dsdb_flags for controls
4693 int dsdb_search(struct ldb_context *ldb,
4694 TALLOC_CTX *mem_ctx,
4695 struct ldb_result **_result,
4696 struct ldb_dn *basedn,
4697 enum ldb_scope scope,
4698 const char * const *attrs,
4699 uint32_t dsdb_flags,
4700 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4703 struct ldb_request *req;
4704 struct ldb_result *res;
4706 char *expression = NULL;
4707 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4709 /* cross-partitions searches with a basedn break multi-domain support */
4710 SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
4712 res = talloc_zero(tmp_ctx, struct ldb_result);
4714 talloc_free(tmp_ctx);
4715 return ldb_oom(ldb);
4719 va_start(ap, exp_fmt);
4720 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4724 talloc_free(tmp_ctx);
4725 return ldb_oom(ldb);
4729 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
4736 ldb_search_default_callback,
4738 if (ret != LDB_SUCCESS) {
4739 talloc_free(tmp_ctx);
4743 ret = dsdb_request_add_controls(req, dsdb_flags);
4744 if (ret != LDB_SUCCESS) {
4745 talloc_free(tmp_ctx);
4746 ldb_reset_err_string(ldb);
4750 ret = ldb_request(ldb, req);
4751 if (ret == LDB_SUCCESS) {
4752 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4755 if (ret != LDB_SUCCESS) {
4756 talloc_free(tmp_ctx);
4760 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
4761 if (res->count == 0) {
4762 talloc_free(tmp_ctx);
4763 ldb_reset_err_string(ldb);
4764 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4766 if (res->count != 1) {
4767 talloc_free(tmp_ctx);
4768 ldb_reset_err_string(ldb);
4769 return LDB_ERR_CONSTRAINT_VIOLATION;
4773 *_result = talloc_steal(mem_ctx, res);
4774 talloc_free(tmp_ctx);
4781 general search with dsdb_flags for controls
4782 returns exactly 1 record or an error
4784 int dsdb_search_one(struct ldb_context *ldb,
4785 TALLOC_CTX *mem_ctx,
4786 struct ldb_message **msg,
4787 struct ldb_dn *basedn,
4788 enum ldb_scope scope,
4789 const char * const *attrs,
4790 uint32_t dsdb_flags,
4791 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4794 struct ldb_result *res;
4796 char *expression = NULL;
4797 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4799 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
4801 res = talloc_zero(tmp_ctx, struct ldb_result);
4803 talloc_free(tmp_ctx);
4804 return ldb_oom(ldb);
4808 va_start(ap, exp_fmt);
4809 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4813 talloc_free(tmp_ctx);
4814 return ldb_oom(ldb);
4816 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4817 dsdb_flags, "%s", expression);
4819 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4823 if (ret != LDB_SUCCESS) {
4824 talloc_free(tmp_ctx);
4828 *msg = talloc_steal(mem_ctx, res->msgs[0]);
4829 talloc_free(tmp_ctx);
4834 /* returns back the forest DNS name */
4835 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4837 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
4838 ldb_get_root_basedn(ldb));
4841 if (forest_name == NULL) {
4845 p = strchr(forest_name, '/');
4853 /* returns back the default domain DNS name */
4854 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4856 const char *domain_name = ldb_dn_canonical_string(mem_ctx,
4857 ldb_get_default_basedn(ldb));
4860 if (domain_name == NULL) {
4864 p = strchr(domain_name, '/');
4873 validate that an DSA GUID belongs to the specified user sid.
4874 The user SID must be a domain controller account (either RODC or
4877 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
4878 const struct GUID *dsa_guid,
4879 const struct dom_sid *sid)
4882 - find DN of record with the DSA GUID in the
4883 configuration partition (objectGUID)
4884 - remove "NTDS Settings" component from DN
4885 - do a base search on that DN for serverReference with
4887 - extract objectSid from resulting serverReference
4889 - check this sid matches the sid argument
4891 struct ldb_dn *config_dn;
4892 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4893 struct ldb_message *msg;
4894 const char *attrs1[] = { NULL };
4895 const char *attrs2[] = { "serverReference", NULL };
4897 struct ldb_dn *dn, *account_dn;
4898 struct dom_sid sid2;
4901 config_dn = ldb_get_config_basedn(ldb);
4903 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4904 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4905 if (ret != LDB_SUCCESS) {
4906 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4907 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4908 talloc_free(tmp_ctx);
4909 return ldb_operr(ldb);
4913 if (!ldb_dn_remove_child_components(dn, 1)) {
4914 talloc_free(tmp_ctx);
4915 return ldb_operr(ldb);
4918 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4919 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4920 "(objectClass=server)");
4921 if (ret != LDB_SUCCESS) {
4922 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4923 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4924 talloc_free(tmp_ctx);
4925 return ldb_operr(ldb);
4928 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4929 if (account_dn == NULL) {
4930 DEBUG(1,(__location__ ": Failed to find account dn "
4931 "(serverReference) for %s, parent of DSA with "
4932 "objectGUID %s, sid %s\n",
4933 ldb_dn_get_linearized(msg->dn),
4934 GUID_string(tmp_ctx, dsa_guid),
4935 dom_sid_string(tmp_ctx, sid)));
4936 talloc_free(tmp_ctx);
4937 return ldb_operr(ldb);
4940 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4941 if (!NT_STATUS_IS_OK(status)) {
4942 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4943 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4944 talloc_free(tmp_ctx);
4945 return ldb_operr(ldb);
4948 if (!dom_sid_equal(sid, &sid2)) {
4949 /* someone is trying to spoof another account */
4950 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4951 GUID_string(tmp_ctx, dsa_guid),
4952 dom_sid_string(tmp_ctx, sid),
4953 dom_sid_string(tmp_ctx, &sid2)));
4954 talloc_free(tmp_ctx);
4955 return ldb_operr(ldb);
4958 talloc_free(tmp_ctx);
4962 static const char * const secret_attributes[] = {
4963 DSDB_SECRET_ATTRIBUTES,
4968 check if the attribute belongs to the RODC filtered attribute set
4969 Note that attributes that are in the filtered attribute set are the
4970 ones that _are_ always sent to a RODC
4972 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4974 /* they never get secret attributes */
4975 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4979 /* they do get non-secret critical attributes */
4980 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4984 /* they do get non-secret attributes marked as being in the FAS */
4985 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4989 /* other attributes are denied */
4993 /* return fsmo role dn and role owner dn for a particular role*/
4994 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4995 struct ldb_context *ldb,
4997 struct ldb_dn **fsmo_role_dn,
4998 struct ldb_dn **role_owner_dn)
5002 case DREPL_NAMING_MASTER:
5003 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
5004 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5005 if (ret != LDB_SUCCESS) {
5006 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
5007 ldb_errstring(ldb)));
5008 talloc_free(tmp_ctx);
5009 return WERR_DS_DRA_INTERNAL_ERROR;
5012 case DREPL_INFRASTRUCTURE_MASTER:
5013 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
5014 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5015 if (ret != LDB_SUCCESS) {
5016 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
5017 ldb_errstring(ldb)));
5018 talloc_free(tmp_ctx);
5019 return WERR_DS_DRA_INTERNAL_ERROR;
5022 case DREPL_RID_MASTER:
5023 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
5024 if (ret != LDB_SUCCESS) {
5025 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
5026 talloc_free(tmp_ctx);
5027 return WERR_DS_DRA_INTERNAL_ERROR;
5030 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5031 if (ret != LDB_SUCCESS) {
5032 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
5033 ldb_errstring(ldb)));
5034 talloc_free(tmp_ctx);
5035 return WERR_DS_DRA_INTERNAL_ERROR;
5038 case DREPL_SCHEMA_MASTER:
5039 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
5040 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5041 if (ret != LDB_SUCCESS) {
5042 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
5043 ldb_errstring(ldb)));
5044 talloc_free(tmp_ctx);
5045 return WERR_DS_DRA_INTERNAL_ERROR;
5048 case DREPL_PDC_MASTER:
5049 *fsmo_role_dn = ldb_get_default_basedn(ldb);
5050 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5051 if (ret != LDB_SUCCESS) {
5052 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
5053 ldb_errstring(ldb)));
5054 talloc_free(tmp_ctx);
5055 return WERR_DS_DRA_INTERNAL_ERROR;
5059 return WERR_DS_DRA_INTERNAL_ERROR;
5064 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
5065 TALLOC_CTX *mem_ctx,
5066 struct ldb_dn *server_dn)
5069 struct ldb_result *res = NULL;
5070 const char * const attrs[] = { "dNSHostName", NULL};
5072 ldb_ret = ldb_search(ldb, mem_ctx, &res,
5076 if (ldb_ret != LDB_SUCCESS) {
5077 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
5078 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
5082 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
5086 returns true if an attribute is in the filter,
5087 false otherwise, provided that attribute value is provided with the expression
5089 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
5093 switch (tree->operation) {
5096 for (i=0;i<tree->u.list.num_elements;i++) {
5097 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
5103 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
5104 case LDB_OP_EQUALITY:
5105 case LDB_OP_GREATER:
5108 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
5112 case LDB_OP_SUBSTRING:
5113 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
5117 case LDB_OP_PRESENT:
5118 /* (attrname=*) is not filtered out */
5120 case LDB_OP_EXTENDED:
5121 if (tree->u.extended.attr &&
5122 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
5130 bool is_attr_in_list(const char * const * attrs, const char *attr)
5134 for (i = 0; attrs[i]; i++) {
5135 if (ldb_attr_cmp(attrs[i], attr) == 0)
5142 int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
5143 const char *location, const char *func,
5146 if (reason == NULL) {
5147 reason = win_errstr(werr);
5149 ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
5150 W_ERROR_V(werr), reason, location, func);
5155 map an ldb error code to an approximate NTSTATUS code
5157 NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
5161 return NT_STATUS_OK;
5163 case LDB_ERR_PROTOCOL_ERROR:
5164 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
5166 case LDB_ERR_TIME_LIMIT_EXCEEDED:
5167 return NT_STATUS_IO_TIMEOUT;
5169 case LDB_ERR_SIZE_LIMIT_EXCEEDED:
5170 return NT_STATUS_BUFFER_TOO_SMALL;
5172 case LDB_ERR_COMPARE_FALSE:
5173 case LDB_ERR_COMPARE_TRUE:
5174 return NT_STATUS_REVISION_MISMATCH;
5176 case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
5177 return NT_STATUS_NOT_SUPPORTED;
5179 case LDB_ERR_STRONG_AUTH_REQUIRED:
5180 case LDB_ERR_CONFIDENTIALITY_REQUIRED:
5181 case LDB_ERR_SASL_BIND_IN_PROGRESS:
5182 case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
5183 case LDB_ERR_INVALID_CREDENTIALS:
5184 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
5185 case LDB_ERR_UNWILLING_TO_PERFORM:
5186 return NT_STATUS_ACCESS_DENIED;
5188 case LDB_ERR_NO_SUCH_OBJECT:
5189 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5191 case LDB_ERR_REFERRAL:
5192 case LDB_ERR_NO_SUCH_ATTRIBUTE:
5193 return NT_STATUS_NOT_FOUND;
5195 case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
5196 return NT_STATUS_NOT_SUPPORTED;
5198 case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
5199 return NT_STATUS_BUFFER_TOO_SMALL;
5201 case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
5202 case LDB_ERR_INAPPROPRIATE_MATCHING:
5203 case LDB_ERR_CONSTRAINT_VIOLATION:
5204 case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
5205 case LDB_ERR_INVALID_DN_SYNTAX:
5206 case LDB_ERR_NAMING_VIOLATION:
5207 case LDB_ERR_OBJECT_CLASS_VIOLATION:
5208 case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
5209 case LDB_ERR_NOT_ALLOWED_ON_RDN:
5210 return NT_STATUS_INVALID_PARAMETER;
5212 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
5213 case LDB_ERR_ENTRY_ALREADY_EXISTS:
5214 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
5217 return NT_STATUS_NETWORK_BUSY;
5219 case LDB_ERR_ALIAS_PROBLEM:
5220 case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
5221 case LDB_ERR_UNAVAILABLE:
5222 case LDB_ERR_LOOP_DETECT:
5223 case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
5224 case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
5226 case LDB_ERR_OPERATIONS_ERROR:
5229 return NT_STATUS_UNSUCCESSFUL;
5234 create a new naming context that will hold a partial replica
5236 int dsdb_create_partial_replica_NC(struct ldb_context *ldb, struct ldb_dn *dn)
5238 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5239 struct ldb_message *msg;
5242 msg = ldb_msg_new(tmp_ctx);
5244 talloc_free(tmp_ctx);
5245 return ldb_oom(ldb);
5249 ret = ldb_msg_add_string(msg, "objectClass", "top");
5250 if (ret != LDB_SUCCESS) {
5251 talloc_free(tmp_ctx);
5252 return ldb_oom(ldb);
5255 /* [MS-DRSR] implies that we should only add the 'top'
5256 * objectclass, but that would cause lots of problems with our
5257 * objectclass code as top is not structural, so we add
5258 * 'domainDNS' as well to keep things sane. We're expecting
5259 * this new NC to be of objectclass domainDNS after
5260 * replication anyway
5262 ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
5263 if (ret != LDB_SUCCESS) {
5264 talloc_free(tmp_ctx);
5265 return ldb_oom(ldb);
5268 ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
5269 INSTANCE_TYPE_IS_NC_HEAD|
5270 INSTANCE_TYPE_NC_ABOVE|
5271 INSTANCE_TYPE_UNINSTANT);
5272 if (ret != LDB_SUCCESS) {
5273 talloc_free(tmp_ctx);
5274 return ldb_oom(ldb);
5277 ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
5278 if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5279 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
5280 ldb_dn_get_linearized(dn),
5281 ldb_errstring(ldb), ldb_strerror(ret)));
5282 talloc_free(tmp_ctx);
5286 DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
5288 talloc_free(tmp_ctx);
5293 * Return the effective badPwdCount
5295 * This requires that the user_msg have (if present):
5299 * This also requires that the domain_msg have (if present):
5300 * - lockOutObservationWindow
5302 static int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
5303 int64_t lockOutObservationWindow,
5306 int64_t badPasswordTime;
5307 badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
5309 if (badPasswordTime - lockOutObservationWindow >= now) {
5310 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
5317 * Returns a user's PSO, or NULL if none was found
5319 static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
5320 TALLOC_CTX *mem_ctx,
5321 const struct ldb_message *user_msg,
5322 const char * const *attrs)
5324 struct ldb_result *res = NULL;
5325 struct ldb_dn *pso_dn = NULL;
5328 /* if the user has a PSO that applies, then use the PSO's setting */
5329 pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
5330 "msDS-ResultantPSO");
5332 if (pso_dn != NULL) {
5334 ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
5335 if (ret != LDB_SUCCESS) {
5338 * log the error. The caller should fallback to using
5339 * the default domain password settings
5341 DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s",
5342 ldb_dn_get_linearized(pso_dn),
5343 ldb_dn_get_linearized(user_msg->dn));
5345 talloc_free(pso_dn);
5351 * Return the effective badPwdCount
5353 * This requires that the user_msg have (if present):
5356 * - msDS-ResultantPSO
5358 int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
5359 TALLOC_CTX *mem_ctx,
5360 struct ldb_dn *domain_dn,
5361 const struct ldb_message *user_msg)
5363 struct timeval tv_now = timeval_current();
5364 NTTIME now = timeval_to_nttime(&tv_now);
5365 int64_t lockOutObservationWindow;
5366 struct ldb_result *res = NULL;
5367 const char *attrs[] = { "msDS-LockoutObservationWindow",
5370 res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
5373 lockOutObservationWindow =
5374 ldb_msg_find_attr_as_int64(res->msgs[0],
5375 "msDS-LockoutObservationWindow",
5376 DEFAULT_OBSERVATION_WINDOW);
5380 /* no PSO was found, lookup the default domain setting */
5381 lockOutObservationWindow =
5382 samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
5383 "lockOutObservationWindow", NULL);
5386 return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5390 * Returns the lockoutThreshold that applies. If a PSO is specified, then that
5391 * setting is used over the domain defaults
5393 static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
5394 struct ldb_message *pso_msg)
5396 if (pso_msg != NULL) {
5397 return ldb_msg_find_attr_as_int(pso_msg,
5398 "msDS-LockoutThreshold", 0);
5400 return ldb_msg_find_attr_as_int(domain_msg,
5401 "lockoutThreshold", 0);
5406 * Returns the lockOutObservationWindow that applies. If a PSO is specified,
5407 * then that setting is used over the domain defaults
5409 static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
5410 struct ldb_message *pso_msg)
5412 if (pso_msg != NULL) {
5413 return ldb_msg_find_attr_as_int64(pso_msg,
5414 "msDS-LockoutObservationWindow",
5415 DEFAULT_OBSERVATION_WINDOW);
5417 return ldb_msg_find_attr_as_int64(domain_msg,
5418 "lockOutObservationWindow",
5419 DEFAULT_OBSERVATION_WINDOW);
5424 * Prepare an update to the badPwdCount and associated attributes.
5426 * This requires that the user_msg have (if present):
5431 * This also requires that the domain_msg have (if present):
5433 * - lockoutThreshold
5434 * - lockOutObservationWindow
5436 * This also requires that the pso_msg have (if present):
5437 * - msDS-LockoutThreshold
5438 * - msDS-LockoutObservationWindow
5440 NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
5441 struct ldb_context *sam_ctx,
5442 struct ldb_message *user_msg,
5443 struct ldb_message *domain_msg,
5444 struct ldb_message *pso_msg,
5445 struct ldb_message **_mod_msg)
5447 int ret, badPwdCount;
5449 int64_t lockoutThreshold, lockOutObservationWindow;
5450 struct dom_sid *sid;
5451 struct timeval tv_now = timeval_current();
5452 NTTIME now = timeval_to_nttime(&tv_now);
5454 uint32_t pwdProperties, rid = 0;
5455 struct ldb_message *mod_msg;
5457 sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
5459 pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
5460 "pwdProperties", -1);
5461 if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
5462 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
5463 if (!NT_STATUS_IS_OK(status)) {
5465 * This can't happen anyway, but always try
5466 * and update the badPwdCount on failure
5474 * Work out if we are doing password lockout on the domain.
5475 * Also, the built in administrator account is exempt:
5476 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
5478 lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
5479 if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
5480 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
5481 ldb_dn_get_linearized(user_msg->dn)));
5482 return NT_STATUS_OK;
5485 mod_msg = ldb_msg_new(mem_ctx);
5486 if (mod_msg == NULL) {
5487 return NT_STATUS_NO_MEMORY;
5489 mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
5490 if (mod_msg->dn == NULL) {
5491 TALLOC_FREE(mod_msg);
5492 return NT_STATUS_NO_MEMORY;
5495 lockOutObservationWindow = get_lockout_observation_window(domain_msg,
5498 badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5502 ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
5503 if (ret != LDB_SUCCESS) {
5504 TALLOC_FREE(mod_msg);
5505 return NT_STATUS_NO_MEMORY;
5507 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
5508 if (ret != LDB_SUCCESS) {
5509 TALLOC_FREE(mod_msg);
5510 return NT_STATUS_NO_MEMORY;
5513 if (badPwdCount >= lockoutThreshold) {
5514 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
5515 if (ret != LDB_SUCCESS) {
5516 TALLOC_FREE(mod_msg);
5517 return NT_STATUS_NO_MEMORY;
5519 DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
5520 ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5522 DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
5523 ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5526 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5527 for (i=0; i< mod_msg->num_elements; i++) {
5528 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5531 *_mod_msg = mod_msg;
5532 return NT_STATUS_OK;
5536 * Sets defaults for a User object
5537 * List of default attributes set:
5538 * accountExpires, badPasswordTime, badPwdCount,
5539 * codePage, countryCode, lastLogoff, lastLogon
5540 * logonCount, pwdLastSet
5542 int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
5543 struct ldb_message *usr_obj,
5544 struct ldb_request *req)
5548 const struct attribute_values {
5551 const char *add_value;
5552 const char *mod_value;
5553 const char *control;
5558 .name = "accountExpires",
5559 .add_value = "9223372036854775807",
5563 .name = "badPasswordTime",
5567 .name = "badPwdCount",
5575 .name = "countryCode",
5579 .name = "lastLogoff",
5583 .name = "lastLogon",
5587 .name = "logonCount",
5591 .name = "logonHours",
5592 .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
5595 .name = "pwdLastSet",
5597 .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
5600 .name = "adminCount",
5604 .name = "operatorCount",
5609 for (i = 0; i < ARRAY_SIZE(map); i++) {
5611 const char *value = NULL;
5614 if (req != NULL && req->operation == LDB_ADD) {
5615 value = map[i].add_value;
5616 flags = map[i].add_flags;
5618 value = map[i].mod_value;
5619 flags = map[i].mod_flags;
5622 if (value == NULL) {
5623 value = map[i].value;
5626 if (value != NULL) {
5627 flags |= LDB_FLAG_MOD_ADD;
5634 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
5638 if (ret != LDB_SUCCESS) {
5642 if (req != NULL && added && map[i].control != NULL) {
5643 ret = ldb_request_add_control(req,
5646 if (ret != LDB_SUCCESS) {
5656 * Sets 'sAMAccountType on user object based on userAccountControl
5657 * @param ldb Current ldb_context
5658 * @param usr_obj ldb_message representing User object
5659 * @param user_account_control Value for userAccountControl flags
5660 * @param account_type_p Optional pointer to account_type to return
5661 * @return LDB_SUCCESS or LDB_ERR* code on failure
5663 int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
5664 uint32_t user_account_control, uint32_t *account_type_p)
5667 uint32_t account_type;
5668 struct ldb_message_element *el;
5670 account_type = ds_uf2atype(user_account_control);
5671 if (account_type == 0) {
5672 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
5673 return LDB_ERR_UNWILLING_TO_PERFORM;
5675 ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5678 if (ret != LDB_SUCCESS) {
5681 el = ldb_msg_find_element(usr_obj, "sAMAccountType");
5682 el->flags = LDB_FLAG_MOD_REPLACE;
5684 if (account_type_p) {
5685 *account_type_p = account_type;
5692 * Determine and set primaryGroupID based on userAccountControl value
5693 * @param ldb Current ldb_context
5694 * @param usr_obj ldb_message representing User object
5695 * @param user_account_control Value for userAccountControl flags
5696 * @param group_rid_p Optional pointer to group RID to return
5697 * @return LDB_SUCCESS or LDB_ERR* code on failure
5699 int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
5700 uint32_t user_account_control, uint32_t *group_rid_p)
5704 struct ldb_message_element *el;
5706 rid = ds_uf2prim_group_rid(user_account_control);
5708 ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5709 "primaryGroupID", rid);
5710 if (ret != LDB_SUCCESS) {
5713 el = ldb_msg_find_element(usr_obj, "primaryGroupID");
5714 el->flags = LDB_FLAG_MOD_REPLACE;
5724 * Returns True if the source and target DNs both have the same naming context,
5725 * i.e. they're both in the same partition.
5727 bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
5728 TALLOC_CTX *mem_ctx,
5729 struct ldb_dn *source_dn,
5730 struct ldb_dn *target_dn)
5732 TALLOC_CTX *tmp_ctx;
5733 struct ldb_dn *source_nc = NULL;
5734 struct ldb_dn *target_nc = NULL;
5736 bool same_nc = true;
5738 tmp_ctx = talloc_new(mem_ctx);
5740 ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
5741 /* fix clang warning */
5742 if (source_nc == NULL) {
5743 ret = LDB_ERR_OTHER;
5745 if (ret != LDB_SUCCESS) {
5746 DBG_ERR("Failed to find base DN for source %s\n",
5747 ldb_dn_get_linearized(source_dn));
5748 talloc_free(tmp_ctx);
5752 ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
5753 /* fix clang warning */
5754 if (target_nc == NULL) {
5755 ret = LDB_ERR_OTHER;
5757 if (ret != LDB_SUCCESS) {
5758 DBG_ERR("Failed to find base DN for target %s\n",
5759 ldb_dn_get_linearized(target_dn));
5760 talloc_free(tmp_ctx);
5764 same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
5766 talloc_free(tmp_ctx);
5771 * Context for dsdb_count_domain_callback
5773 struct dsdb_count_domain_context {
5775 * Number of matching records
5779 * sid of the domain that the records must belong to.
5780 * if NULL records can belong to any domain.
5782 struct dom_sid *dom_sid;
5786 * @brief ldb aysnc callback for dsdb_domain_count.
5788 * count the number of records in the database matching an LDAP query,
5789 * optionally filtering for domain membership.
5791 * @param [in,out] req the ldb request being processed
5792 * req->context contains:
5793 * count The number of matching records
5794 * dom_sid The domain sid, if present records must belong
5795 * to the domain to be counted.
5796 *@param [in,out] ares The query result.
5798 * @return an LDB error code
5801 static int dsdb_count_domain_callback(
5802 struct ldb_request *req,
5803 struct ldb_reply *ares)
5807 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
5809 if (ares->error != LDB_SUCCESS) {
5810 int error = ares->error;
5812 return ldb_request_done(req, error);
5815 switch (ares->type) {
5816 case LDB_REPLY_ENTRY:
5818 struct dsdb_count_domain_context *context = NULL;
5822 const struct ldb_val *v;
5824 context = req->context;
5825 if (context->dom_sid == NULL) {
5830 v = ldb_msg_find_ldb_val(ares->message, "objectSid");
5835 ret = sid_parse(v->data, v->length, &sid);
5840 in_domain = dom_sid_in_domain(context->dom_sid, &sid);
5848 case LDB_REPLY_REFERRAL:
5851 case LDB_REPLY_DONE:
5853 return ldb_request_done(req, LDB_SUCCESS);
5862 * @brief Count the number of records matching a query.
5864 * Count the number of entries in the database matching the supplied query,
5865 * optionally filtering only those entries belonging to the supplied domain.
5867 * @param ldb [in] Current ldb context
5868 * @param count [out] Pointer to the count
5869 * @param base [in] The base dn for the quey
5870 * @param dom_sid [in] The domain sid, if non NULL records that are not a member
5871 * of the domain are ignored.
5872 * @param scope [in] Search scope.
5873 * @param exp_fmt [in] format string for the query.
5875 * @return LDB_STATUS code.
5877 int PRINTF_ATTRIBUTE(6, 7) dsdb_domain_count(
5878 struct ldb_context *ldb,
5880 struct ldb_dn *base,
5881 struct dom_sid *dom_sid,
5882 enum ldb_scope scope,
5883 const char *exp_fmt, ...)
5885 TALLOC_CTX *tmp_ctx = NULL;
5886 struct ldb_request *req = NULL;
5887 struct dsdb_count_domain_context *context = NULL;
5888 char *expression = NULL;
5889 const char *object_sid[] = {"objectSid", NULL};
5890 const char *none[] = {NULL};
5895 tmp_ctx = talloc_new(ldb);
5897 context = talloc_zero(tmp_ctx, struct dsdb_count_domain_context);
5898 if (context == NULL) {
5899 return LDB_ERR_OPERATIONS_ERROR;
5901 context->dom_sid = dom_sid;
5904 va_start(ap, exp_fmt);
5905 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
5908 if (expression == NULL) {
5909 TALLOC_FREE(context);
5910 TALLOC_FREE(tmp_ctx);
5911 return LDB_ERR_OPERATIONS_ERROR;
5915 ret = ldb_build_search_req(
5922 (dom_sid == NULL) ? none : object_sid,
5925 dsdb_count_domain_callback,
5927 ldb_req_set_location(req, "dsdb_domain_count");
5929 if (ret != LDB_SUCCESS) goto done;
5931 ret = ldb_request(ldb, req);
5933 if (ret == LDB_SUCCESS) {
5934 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
5935 if (ret == LDB_SUCCESS) {
5936 *count = context->count;
5942 TALLOC_FREE(expression);
5944 TALLOC_FREE(context);
5945 TALLOC_FREE(tmp_ctx);