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 "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "librpc/gen_ndr/irpc.h"
48 search the sam for the specified attributes in a specific domain, filter on
49 objectSid being in domain_sid.
51 int samdb_search_domain(struct ldb_context *sam_ldb,
53 struct ldb_dn *basedn,
54 struct ldb_message ***res,
55 const char * const *attrs,
56 const struct dom_sid *domain_sid,
57 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
63 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
64 res, attrs, format, ap);
70 struct dom_sid *entry_sid;
72 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
74 if ((entry_sid == NULL) ||
75 (!dom_sid_in_domain(domain_sid, entry_sid))) {
76 /* Delete that entry from the result set */
77 (*res)[i] = (*res)[count-1];
79 talloc_free(entry_sid);
82 talloc_free(entry_sid);
90 search the sam for a single string attribute in exactly 1 record
92 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
94 struct ldb_dn *basedn,
95 const char *attr_name,
96 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
99 const char *attrs[2] = { NULL, NULL };
100 struct ldb_message **res = NULL;
102 attrs[0] = attr_name;
104 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
106 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
107 attr_name, format, count));
114 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
118 search the sam for a single string attribute in exactly 1 record
120 const char *samdb_search_string(struct ldb_context *sam_ldb,
122 struct ldb_dn *basedn,
123 const char *attr_name,
124 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
129 va_start(ap, format);
130 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
136 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
138 struct ldb_dn *basedn,
139 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
143 struct ldb_message **res = NULL;
146 va_start(ap, format);
147 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
150 if (count != 1) return NULL;
152 ret = talloc_steal(mem_ctx, res[0]->dn);
159 search the sam for a dom_sid attribute in exactly 1 record
161 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
163 struct ldb_dn *basedn,
164 const char *attr_name,
165 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
169 struct ldb_message **res;
170 const char *attrs[2] = { NULL, NULL };
173 attrs[0] = attr_name;
175 va_start(ap, format);
176 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
179 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
180 attr_name, format, count));
186 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
192 return the count of the number of records in the sam matching the query
194 int samdb_search_count(struct ldb_context *sam_ldb,
196 struct ldb_dn *basedn,
197 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
200 const char *attrs[] = { NULL };
203 va_start(ap, format);
204 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
212 search the sam for a single integer attribute in exactly 1 record
214 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
216 unsigned int default_value,
217 struct ldb_dn *basedn,
218 const char *attr_name,
219 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
223 struct ldb_message **res;
224 const char *attrs[2] = { NULL, NULL };
226 attrs[0] = attr_name;
228 va_start(ap, format);
229 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
233 return default_value;
236 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
240 search the sam for a single signed 64 bit integer attribute in exactly 1 record
242 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
244 int64_t default_value,
245 struct ldb_dn *basedn,
246 const char *attr_name,
247 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
251 struct ldb_message **res;
252 const char *attrs[2] = { NULL, NULL };
254 attrs[0] = attr_name;
256 va_start(ap, format);
257 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
261 return default_value;
264 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
268 search the sam for multipe records each giving a single string attribute
269 return the number of matches, or -1 on error
271 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
273 struct ldb_dn *basedn,
275 const char *attr_name,
276 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
280 const char *attrs[2] = { NULL, NULL };
281 struct ldb_message **res = NULL;
283 attrs[0] = attr_name;
285 va_start(ap, format);
286 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
293 /* make sure its single valued */
294 for (i=0;i<count;i++) {
295 if (res[i]->num_elements != 1) {
296 DEBUG(1,("samdb: search for %s %s not single valued\n",
303 *strs = talloc_array(mem_ctx, const char *, count+1);
309 for (i=0;i<count;i++) {
310 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
312 (*strs)[count] = NULL;
317 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
318 const char *attr, struct ldb_dn *default_value)
320 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
322 return default_value;
328 pull a rid from a objectSid in a result set.
330 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
331 const char *attr, uint32_t default_value)
336 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
338 return default_value;
340 rid = sid->sub_auths[sid->num_auths-1];
346 pull a dom_sid structure from a objectSid in a result set.
348 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
351 const struct ldb_val *v;
353 enum ndr_err_code ndr_err;
354 v = ldb_msg_find_ldb_val(msg, attr);
358 sid = talloc(mem_ctx, struct dom_sid);
362 ndr_err = ndr_pull_struct_blob(v, sid, sid,
363 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
364 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 pull a guid structure from a objectGUID in a result set.
374 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
376 const struct ldb_val *v;
380 v = ldb_msg_find_ldb_val(msg, attr);
381 if (!v) return GUID_zero();
383 status = GUID_from_ndr_blob(v, &guid);
384 if (!NT_STATUS_IS_OK(status)) {
392 pull a sid prefix from a objectSid in a result set.
393 this is used to find the domain sid for a user
395 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
398 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
399 if (!sid || sid->num_auths < 1) return NULL;
405 pull a NTTIME in a result set.
407 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
408 NTTIME default_value)
410 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
414 * Windows stores 0 for lastLogoff.
415 * But when a MS DC return the lastLogoff (as Logoff Time)
416 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
417 * cause windows 2008 and newer version to fail for SMB requests
419 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
421 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
424 ret = 0x7FFFFFFFFFFFFFFFULL;
430 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
431 * indicate an account doesn't expire.
433 * When Windows initially creates an account, it sets
434 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
435 * when changing from an account having a specific expiration date to
436 * that account never expiring, it sets accountExpires = 0.
438 * Consolidate that logic here to allow clearer logic for account expiry in
439 * the rest of the code.
441 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
443 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
447 ret = 0x7FFFFFFFFFFFFFFFULL;
453 construct the allow_password_change field from the PwdLastSet attribute and the
454 domain password settings
456 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
458 struct ldb_dn *domain_dn,
459 struct ldb_message *msg,
462 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
465 if (attr_time == 0) {
469 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
471 /* yes, this is a -= not a += as minPwdAge is stored as the negative
472 of the number of 100-nano-seconds */
473 attr_time -= minPwdAge;
479 construct the force_password_change field from the PwdLastSet
480 attribute, the userAccountControl and the domain password settings
482 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
484 struct ldb_dn *domain_dn,
485 struct ldb_message *msg)
487 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
488 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
489 "userAccountControl",
493 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
494 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
495 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
496 return 0x7FFFFFFFFFFFFFFFULL;
499 if (attr_time == 0) {
502 if (attr_time == -1) {
503 return 0x7FFFFFFFFFFFFFFFULL;
506 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
508 if (maxPwdAge == 0) {
509 return 0x7FFFFFFFFFFFFFFFULL;
511 attr_time -= maxPwdAge;
518 pull a samr_Password structutre from a result set.
520 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
522 struct samr_Password *hash = NULL;
523 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
524 if (val && (val->length >= sizeof(hash->hash))) {
525 hash = talloc(mem_ctx, struct samr_Password);
526 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
532 pull an array of samr_Password structures from a result set.
534 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
535 const char *attr, struct samr_Password **hashes)
537 unsigned int count, i;
538 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
544 count = val->length / 16;
549 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
554 for (i=0;i<count;i++) {
555 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
561 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
562 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
564 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];
598 pull a samr_LogonHours structutre from a result set.
600 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
602 struct samr_LogonHours hours;
603 size_t units_per_week = 168;
604 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
609 units_per_week = val->length * 8;
612 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
616 hours.units_per_week = units_per_week;
617 memset(hours.bits, 0xFF, units_per_week/8);
619 memcpy(hours.bits, val->data, val->length);
626 pull a set of account_flags from a result set.
628 This requires that the attributes:
633 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
634 struct ldb_message *msg, struct ldb_dn *domain_dn)
636 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
637 uint32_t acct_flags = ds_uf2acb(userAccountControl);
638 NTTIME must_change_time;
641 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
644 /* Test account expire time */
645 unix_to_nt_time(&now, time(NULL));
646 /* check for expired password */
647 if (must_change_time < now) {
648 acct_flags |= ACB_PW_EXPIRED;
653 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
654 struct ldb_message *msg,
657 struct lsa_BinaryString s;
658 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
666 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
670 s.length = s.size = val->length;
671 memcpy(s.array, val->data, val->length);
676 /* Find an attribute, with a particular value */
678 /* The current callers of this function expect a very specific
679 * behaviour: In particular, objectClass subclass equivilance is not
680 * wanted. This means that we should not lookup the schema for the
681 * comparison function */
682 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
683 const struct ldb_message *msg,
684 const char *name, const char *value)
687 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
693 for (i=0;i<el->num_values;i++) {
694 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
703 * This is intended for use by the "password hash" module since there
704 * password changes can be specified through one message element with the
705 * new password (to set) and another one with the old password (to unset).
707 * The first which sets a password (new value) can have flags
708 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
709 * for entries). The latter (old value) has always specified
710 * LDB_FLAG_MOD_DELETE.
712 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
713 * doesn't contain only one value (this is the Windows Server behaviour)
714 * otherwise LDB_SUCCESS.
716 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
718 const struct ldb_val **new_val,
719 const struct ldb_val **old_val)
730 for (i = 0; i < msg->num_elements; i++) {
731 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
732 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
733 *old_val = &msg->elements[i].values[0];
735 *new_val = &msg->elements[i].values[0];
743 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
745 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
746 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
751 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
753 struct ldb_message_element *el;
755 el = ldb_msg_find_element(msg, name);
760 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
766 add a string element to a message
768 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
769 const char *attr_name, const char *str)
771 const char *s = talloc_strdup(mem_ctx, str);
773 return ldb_oom(sam_ldb);
775 return ldb_msg_add_string(msg, attr_name, s);
779 add a dom_sid element to a message
781 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
782 const char *attr_name, struct dom_sid *sid)
785 enum ndr_err_code ndr_err;
787 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
789 (ndr_push_flags_fn_t)ndr_push_dom_sid);
790 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
791 return ldb_operr(sam_ldb);
793 return ldb_msg_add_value(msg, attr_name, &v, NULL);
798 add a delete element operation to a message
800 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
801 const char *attr_name)
803 /* we use an empty replace rather than a delete, as it allows for
804 dsdb_replace() to be used everywhere */
805 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
809 add an add attribute value to a message or enhance an existing attribute
810 which has the same name and the add flag set.
812 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
813 struct ldb_message *msg, const char *attr_name,
816 struct ldb_message_element *el;
817 struct ldb_val val, *vals;
823 v = talloc_strdup(mem_ctx, value);
825 return ldb_oom(sam_ldb);
828 val.data = (uint8_t *) v;
829 val.length = strlen(v);
831 if (val.length == 0) {
832 /* allow empty strings as non-existent attributes */
836 for (i = 0; i < msg->num_elements; i++) {
837 el = &msg->elements[i];
838 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
839 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
845 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
847 if (ret != LDB_SUCCESS) {
852 vals = talloc_realloc(msg, el->values, struct ldb_val,
855 return ldb_oom(sam_ldb);
858 el->values[el->num_values] = val;
865 add a delete attribute value to a message or enhance an existing attribute
866 which has the same name and the delete flag set.
868 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
869 struct ldb_message *msg, const char *attr_name,
872 struct ldb_message_element *el;
873 struct ldb_val val, *vals;
879 v = talloc_strdup(mem_ctx, value);
881 return ldb_oom(sam_ldb);
884 val.data = (uint8_t *) v;
885 val.length = strlen(v);
887 if (val.length == 0) {
888 /* allow empty strings as non-existent attributes */
892 for (i = 0; i < msg->num_elements; i++) {
893 el = &msg->elements[i];
894 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
895 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
901 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
903 if (ret != LDB_SUCCESS) {
908 vals = talloc_realloc(msg, el->values, struct ldb_val,
911 return ldb_oom(sam_ldb);
914 el->values[el->num_values] = val;
921 add a int element to a message
923 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
924 const char *attr_name, int v)
926 const char *s = talloc_asprintf(mem_ctx, "%d", v);
928 return ldb_oom(sam_ldb);
930 return ldb_msg_add_string(msg, attr_name, s);
934 * Add an unsigned int element to a message
936 * The issue here is that we have not yet first cast to int32_t explicitly,
937 * before we cast to an signed int to printf() into the %d or cast to a
938 * int64_t before we then cast to a long long to printf into a %lld.
940 * There are *no* unsigned integers in Active Directory LDAP, even the RID
941 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
942 * (See the schema, and the syntax definitions in schema_syntax.c).
945 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
946 const char *attr_name, unsigned int v)
948 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
952 add a (signed) int64_t element to a message
954 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955 const char *attr_name, int64_t v)
957 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
959 return ldb_oom(sam_ldb);
961 return ldb_msg_add_string(msg, attr_name, s);
965 * Add an unsigned int64_t (uint64_t) element to a message
967 * The issue here is that we have not yet first cast to int32_t explicitly,
968 * before we cast to an signed int to printf() into the %d or cast to a
969 * int64_t before we then cast to a long long to printf into a %lld.
971 * There are *no* unsigned integers in Active Directory LDAP, even the RID
972 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
973 * (See the schema, and the syntax definitions in schema_syntax.c).
976 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
977 const char *attr_name, uint64_t v)
979 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
983 add a samr_Password element to a message
985 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
986 const char *attr_name, const struct samr_Password *hash)
989 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
991 return ldb_oom(sam_ldb);
994 return ldb_msg_add_value(msg, attr_name, &val, NULL);
998 add a samr_Password array to a message
1000 int samdb_msg_add_hashes(struct ldb_context *ldb,
1001 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1002 const char *attr_name, struct samr_Password *hashes,
1007 val.data = talloc_array_size(mem_ctx, 16, count);
1008 val.length = count*16;
1010 return ldb_oom(ldb);
1012 for (i=0;i<count;i++) {
1013 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1015 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1019 add a acct_flags element to a message
1021 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1022 const char *attr_name, uint32_t v)
1024 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1028 add a logon_hours element to a message
1030 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1031 const char *attr_name, struct samr_LogonHours *hours)
1034 val.length = hours->units_per_week / 8;
1035 val.data = hours->bits;
1036 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1040 add a parameters element to a message
1042 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1043 const char *attr_name, struct lsa_BinaryString *parameters)
1046 val.length = parameters->length;
1047 val.data = (uint8_t *)parameters->array;
1048 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1052 sets a general value element to a message
1054 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1055 const char *attr_name, const struct ldb_val *val)
1057 struct ldb_message_element *el;
1059 el = ldb_msg_find_element(msg, attr_name);
1063 return ldb_msg_add_value(msg, attr_name, val, NULL);
1067 set a string element in a message
1069 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1070 const char *attr_name, const char *str)
1072 struct ldb_message_element *el;
1074 el = ldb_msg_find_element(msg, attr_name);
1078 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1082 * sets a signed integer in a message
1084 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1085 struct ldb_message *msg, const char *attr_name, int v)
1087 struct ldb_message_element *el;
1089 el = ldb_msg_find_element(msg, attr_name);
1093 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1097 * Sets an unsigned int element in a message
1099 * The issue here is that we have not yet first cast to int32_t explicitly,
1100 * before we cast to an signed int to printf() into the %d or cast to a
1101 * int64_t before we then cast to a long long to printf into a %lld.
1103 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1104 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1105 * (See the schema, and the syntax definitions in schema_syntax.c).
1108 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1109 struct ldb_message *msg, const char *attr_name,
1112 struct ldb_message_element *el;
1114 el = ldb_msg_find_element(msg, attr_name);
1118 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1122 * Handle ldb_request in transaction
1124 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1125 struct ldb_request *req)
1129 ret = ldb_transaction_start(sam_ldb);
1130 if (ret != LDB_SUCCESS) {
1134 ret = ldb_request(sam_ldb, req);
1135 if (ret == LDB_SUCCESS) {
1136 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1139 if (ret == LDB_SUCCESS) {
1140 return ldb_transaction_commit(sam_ldb);
1142 ldb_transaction_cancel(sam_ldb);
1148 return a default security descriptor
1150 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1152 struct security_descriptor *sd;
1154 sd = security_descriptor_initialise(mem_ctx);
1159 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1161 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1162 struct ldb_dn *aggregate_dn;
1167 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1168 if (!aggregate_dn) {
1171 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1174 return aggregate_dn;
1177 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1179 struct ldb_dn *new_dn;
1181 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1182 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1183 talloc_free(new_dn);
1189 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1191 struct ldb_dn *new_dn;
1193 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1194 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1195 talloc_free(new_dn);
1201 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1203 struct ldb_dn *new_dn;
1205 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1206 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1207 talloc_free(new_dn);
1214 work out the domain sid for the current open ldb
1216 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1218 TALLOC_CTX *tmp_ctx;
1219 const struct dom_sid *domain_sid;
1220 const char *attrs[] = {
1224 struct ldb_result *res;
1227 /* see if we have a cached copy */
1228 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1233 tmp_ctx = talloc_new(ldb);
1234 if (tmp_ctx == NULL) {
1238 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1240 if (ret != LDB_SUCCESS) {
1244 if (res->count != 1) {
1248 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1249 if (domain_sid == NULL) {
1253 /* cache the domain_sid in the ldb */
1254 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1258 talloc_steal(ldb, domain_sid);
1259 talloc_free(tmp_ctx);
1264 talloc_free(tmp_ctx);
1269 get domain sid from cache
1271 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1273 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1276 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1278 TALLOC_CTX *tmp_ctx;
1279 struct dom_sid *dom_sid_new;
1280 struct dom_sid *dom_sid_old;
1282 /* see if we have a cached copy */
1283 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1284 "cache.domain_sid"), struct dom_sid);
1286 tmp_ctx = talloc_new(ldb);
1287 if (tmp_ctx == NULL) {
1291 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1296 /* cache the domain_sid in the ldb */
1297 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1301 talloc_steal(ldb, dom_sid_new);
1302 talloc_free(tmp_ctx);
1303 talloc_free(dom_sid_old);
1308 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1309 talloc_free(tmp_ctx);
1313 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1315 TALLOC_CTX *tmp_ctx;
1316 struct ldb_dn *ntds_settings_dn_new;
1317 struct ldb_dn *ntds_settings_dn_old;
1319 /* see if we have a cached copy */
1320 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1321 "cache.ntds_settings_dn"), struct ldb_dn);
1323 tmp_ctx = talloc_new(ldb);
1324 if (tmp_ctx == NULL) {
1328 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1329 if (!ntds_settings_dn_new) {
1333 /* cache the domain_sid in the ldb */
1334 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1338 talloc_steal(ldb, ntds_settings_dn_new);
1339 talloc_free(tmp_ctx);
1340 talloc_free(ntds_settings_dn_old);
1345 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1346 talloc_free(tmp_ctx);
1350 /* Obtain the short name of the flexible single master operator
1351 * (FSMO), such as the PDC Emulator */
1352 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1355 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1356 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1357 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1358 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1360 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1361 /* Ensure this matches the format. This gives us a
1362 * bit more confidence that a 'cn' value will be a
1367 return (char *)val->data;
1373 work out the ntds settings dn for the current open ldb
1375 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1377 TALLOC_CTX *tmp_ctx;
1378 const char *root_attrs[] = { "dsServiceName", NULL };
1380 struct ldb_result *root_res;
1381 struct ldb_dn *settings_dn;
1383 /* see if we have a cached copy */
1384 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1389 tmp_ctx = talloc_new(ldb);
1390 if (tmp_ctx == NULL) {
1394 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1396 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1397 ldb_errstring(ldb)));
1401 if (root_res->count != 1) {
1405 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1407 /* cache the domain_sid in the ldb */
1408 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1412 talloc_steal(ldb, settings_dn);
1413 talloc_free(tmp_ctx);
1418 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1419 talloc_free(tmp_ctx);
1424 work out the ntds settings invocationId for the current open ldb
1426 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1428 TALLOC_CTX *tmp_ctx;
1429 const char *attrs[] = { "invocationId", NULL };
1431 struct ldb_result *res;
1432 struct GUID *invocation_id;
1434 /* see if we have a cached copy */
1435 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1436 if (invocation_id) {
1437 return invocation_id;
1440 tmp_ctx = talloc_new(ldb);
1441 if (tmp_ctx == NULL) {
1445 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1450 if (res->count != 1) {
1454 invocation_id = talloc(tmp_ctx, struct GUID);
1455 if (!invocation_id) {
1459 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1461 /* cache the domain_sid in the ldb */
1462 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1466 talloc_steal(ldb, invocation_id);
1467 talloc_free(tmp_ctx);
1469 return invocation_id;
1472 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1473 talloc_free(tmp_ctx);
1477 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1479 TALLOC_CTX *tmp_ctx;
1480 struct GUID *invocation_id_new;
1481 struct GUID *invocation_id_old;
1483 /* see if we have a cached copy */
1484 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1485 "cache.invocation_id");
1487 tmp_ctx = talloc_new(ldb);
1488 if (tmp_ctx == NULL) {
1492 invocation_id_new = talloc(tmp_ctx, struct GUID);
1493 if (!invocation_id_new) {
1497 *invocation_id_new = *invocation_id_in;
1499 /* cache the domain_sid in the ldb */
1500 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1504 talloc_steal(ldb, invocation_id_new);
1505 talloc_free(tmp_ctx);
1506 talloc_free(invocation_id_old);
1511 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1512 talloc_free(tmp_ctx);
1517 work out the ntds settings objectGUID for the current open ldb
1519 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1521 TALLOC_CTX *tmp_ctx;
1522 const char *attrs[] = { "objectGUID", NULL };
1524 struct ldb_result *res;
1525 struct GUID *ntds_guid;
1527 /* see if we have a cached copy */
1528 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1533 tmp_ctx = talloc_new(ldb);
1534 if (tmp_ctx == NULL) {
1538 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1543 if (res->count != 1) {
1547 ntds_guid = talloc(tmp_ctx, struct GUID);
1552 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1554 /* cache the domain_sid in the ldb */
1555 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1559 talloc_steal(ldb, ntds_guid);
1560 talloc_free(tmp_ctx);
1565 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1566 talloc_free(tmp_ctx);
1570 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1572 TALLOC_CTX *tmp_ctx;
1573 struct GUID *ntds_guid_new;
1574 struct GUID *ntds_guid_old;
1576 /* see if we have a cached copy */
1577 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1579 tmp_ctx = talloc_new(ldb);
1580 if (tmp_ctx == NULL) {
1584 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1585 if (!ntds_guid_new) {
1589 *ntds_guid_new = *ntds_guid_in;
1591 /* cache the domain_sid in the ldb */
1592 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1596 talloc_steal(ldb, ntds_guid_new);
1597 talloc_free(tmp_ctx);
1598 talloc_free(ntds_guid_old);
1603 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1604 talloc_free(tmp_ctx);
1609 work out the server dn for the current open ldb
1611 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1613 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1617 work out the server dn for the current open ldb
1619 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1621 struct ldb_dn *server_dn;
1622 struct ldb_dn *servers_dn;
1623 struct ldb_dn *server_site_dn;
1625 /* TODO: there must be a saner way to do this!! */
1626 server_dn = samdb_server_dn(ldb, mem_ctx);
1627 if (!server_dn) return NULL;
1629 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1630 talloc_free(server_dn);
1631 if (!servers_dn) return NULL;
1633 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1634 talloc_free(servers_dn);
1636 return server_site_dn;
1640 find the site name from a computers DN record
1642 int samdb_find_site_for_computer(struct ldb_context *ldb,
1643 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1644 const char **site_name)
1648 const struct ldb_val *rdn_val;
1652 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1653 if (ret != LDB_SUCCESS) {
1657 if (!ldb_dn_remove_child_components(dn, 2)) {
1659 return LDB_ERR_INVALID_DN_SYNTAX;
1661 rdn_val = ldb_dn_get_rdn_val(dn);
1662 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1665 return LDB_ERR_OPERATIONS_ERROR;
1671 find the NTDS GUID from a computers DN record
1673 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1674 struct GUID *ntds_guid)
1679 *ntds_guid = GUID_zero();
1681 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1682 if (ret != LDB_SUCCESS) {
1686 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1688 return LDB_ERR_OPERATIONS_ERROR;
1691 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1697 find a 'reference' DN that points at another object
1698 (eg. serverReference, rIDManagerReference etc)
1700 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1701 const char *attribute, struct ldb_dn **dn)
1703 const char *attrs[2];
1704 struct ldb_result *res;
1707 attrs[0] = attribute;
1710 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1711 if (ret != LDB_SUCCESS) {
1715 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1717 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1718 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1719 ldb_dn_get_linearized(base));
1721 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1722 ldb_dn_get_linearized(base));
1725 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1733 find our machine account via the serverReference attribute in the
1736 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1738 struct ldb_dn *server_dn;
1741 server_dn = samdb_server_dn(ldb, mem_ctx);
1742 if (server_dn == NULL) {
1743 return LDB_ERR_NO_SUCH_OBJECT;
1746 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1747 talloc_free(server_dn);
1753 find the RID Manager$ DN via the rIDManagerReference attribute in the
1756 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1758 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1759 "rIDManagerReference", dn);
1763 find the RID Set DN via the rIDSetReferences attribute in our
1766 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1768 struct ldb_dn *server_ref_dn;
1771 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1772 if (ret != LDB_SUCCESS) {
1775 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1776 talloc_free(server_ref_dn);
1780 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1782 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1789 return (const char *) val->data;
1793 * Finds the client site by using the client's IP address.
1794 * The "subnet_name" returns the name of the subnet if parameter != NULL
1796 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1797 const char *ip_address, char **subnet_name)
1799 const char *attrs[] = { "cn", "siteObject", NULL };
1800 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1801 struct ldb_result *res;
1802 const struct ldb_val *val;
1803 const char *site_name = NULL, *l_subnet_name = NULL;
1804 const char *allow_list[2] = { NULL, NULL };
1805 unsigned int i, count;
1809 * if we don't have a client ip e.g. ncalrpc
1810 * the server site is the client site
1812 if (ip_address == NULL) {
1813 return samdb_server_site_name(ldb, mem_ctx);
1816 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1817 if (sites_container_dn == NULL) {
1821 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1822 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1823 talloc_free(sites_container_dn);
1824 talloc_free(subnets_dn);
1828 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1830 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1832 } else if (ret != LDB_SUCCESS) {
1833 talloc_free(sites_container_dn);
1834 talloc_free(subnets_dn);
1840 for (i = 0; i < count; i++) {
1841 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1844 allow_list[0] = l_subnet_name;
1846 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1847 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1850 if (sites_dn == NULL) {
1851 /* No reference, maybe another subnet matches */
1855 /* "val" cannot be NULL here since "sites_dn" != NULL */
1856 val = ldb_dn_get_rdn_val(sites_dn);
1857 site_name = talloc_strdup(mem_ctx,
1858 (const char *) val->data);
1860 talloc_free(sites_dn);
1866 if (site_name == NULL) {
1867 /* This is the Windows Server fallback rule: when no subnet
1868 * exists and we have only one site available then use it (it
1869 * is for sure the same as our server site). If more sites do
1870 * exist then we don't know which one to use and set the site
1872 cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
1873 "(objectClass=site)");
1875 site_name = samdb_server_site_name(ldb, mem_ctx);
1877 site_name = talloc_strdup(mem_ctx, "");
1879 l_subnet_name = NULL;
1882 if (subnet_name != NULL) {
1883 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1886 talloc_free(sites_container_dn);
1887 talloc_free(subnets_dn);
1894 work out if we are the PDC for the domain of the current open ldb
1896 bool samdb_is_pdc(struct ldb_context *ldb)
1898 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1900 struct ldb_result *dom_res;
1901 TALLOC_CTX *tmp_ctx;
1905 tmp_ctx = talloc_new(ldb);
1906 if (tmp_ctx == NULL) {
1907 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1911 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1912 if (ret != LDB_SUCCESS) {
1913 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1914 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1915 ldb_errstring(ldb)));
1918 if (dom_res->count != 1) {
1922 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1924 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1930 talloc_free(tmp_ctx);
1935 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1936 talloc_free(tmp_ctx);
1941 work out if we are a Global Catalog server for the domain of the current open ldb
1943 bool samdb_is_gc(struct ldb_context *ldb)
1945 const char *attrs[] = { "options", NULL };
1947 struct ldb_result *res;
1948 TALLOC_CTX *tmp_ctx;
1950 tmp_ctx = talloc_new(ldb);
1951 if (tmp_ctx == NULL) {
1952 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1956 /* Query cn=ntds settings,.... */
1957 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1958 if (ret != LDB_SUCCESS) {
1959 talloc_free(tmp_ctx);
1962 if (res->count != 1) {
1963 talloc_free(tmp_ctx);
1967 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1968 talloc_free(tmp_ctx);
1970 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1971 if (options & 0x000000001) {
1977 /* Find a domain object in the parents of a particular DN. */
1978 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1979 struct ldb_dn **parent_dn, const char **errstring)
1981 TALLOC_CTX *local_ctx;
1982 struct ldb_dn *sdn = dn;
1983 struct ldb_result *res = NULL;
1984 int ret = LDB_SUCCESS;
1985 const char *attrs[] = { NULL };
1987 local_ctx = talloc_new(mem_ctx);
1988 if (local_ctx == NULL) return ldb_oom(ldb);
1990 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1991 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1992 "(|(objectClass=domain)(objectClass=builtinDomain))");
1993 if (ret == LDB_SUCCESS) {
1994 if (res->count == 1) {
2002 if (ret != LDB_SUCCESS) {
2003 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2004 ldb_dn_get_linearized(dn),
2005 ldb_dn_get_linearized(sdn),
2006 ldb_errstring(ldb));
2007 talloc_free(local_ctx);
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);
2025 * Performs checks on a user password (plaintext UNIX format - attribute
2026 * "password"). The remaining parameters have to be extracted from the domain
2029 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2031 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2032 const uint32_t pwdProperties,
2033 const uint32_t minPwdLength)
2035 /* checks if the "minPwdLength" property is satisfied */
2036 if (minPwdLength > password->length)
2037 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2039 /* checks the password complexity */
2040 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2041 && (password->data != NULL)
2042 && (!check_password_quality((const char *) password->data)))
2043 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2045 return SAMR_VALIDATION_STATUS_SUCCESS;
2049 * Callback for "samdb_set_password" password change
2051 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2056 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2059 if (ares->error != LDB_SUCCESS) {
2061 req->context = talloc_steal(req,
2062 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2064 return ldb_request_done(req, ret);
2067 if (ares->type != LDB_REPLY_DONE) {
2069 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2072 req->context = talloc_steal(req,
2073 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2075 return ldb_request_done(req, LDB_SUCCESS);
2079 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2080 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2081 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2082 * user change or not. The "rejectReason" gives some more informations if the
2085 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2086 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2088 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2089 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2090 const DATA_BLOB *new_password,
2091 const struct samr_Password *lmNewHash,
2092 const struct samr_Password *ntNewHash,
2093 const struct samr_Password *lmOldHash,
2094 const struct samr_Password *ntOldHash,
2095 enum samPwdChangeReason *reject_reason,
2096 struct samr_DomInfo1 **_dominfo)
2098 struct ldb_message *msg;
2099 struct ldb_message_element *el;
2100 struct ldb_request *req;
2101 struct dsdb_control_password_change_status *pwd_stat = NULL;
2103 NTSTATUS status = NT_STATUS_OK;
2105 #define CHECK_RET(x) \
2106 if (x != LDB_SUCCESS) { \
2108 return NT_STATUS_NO_MEMORY; \
2111 msg = ldb_msg_new(mem_ctx);
2113 return NT_STATUS_NO_MEMORY;
2116 if ((new_password != NULL)
2117 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2118 /* we have the password as plaintext UTF16 */
2119 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2120 new_password, NULL));
2121 el = ldb_msg_find_element(msg, "clearTextPassword");
2122 el->flags = LDB_FLAG_MOD_REPLACE;
2123 } else if ((new_password == NULL)
2124 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2125 /* we have a password as LM and/or NT hash */
2126 if (lmNewHash != NULL) {
2127 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2128 "dBCSPwd", lmNewHash));
2129 el = ldb_msg_find_element(msg, "dBCSPwd");
2130 el->flags = LDB_FLAG_MOD_REPLACE;
2132 if (ntNewHash != NULL) {
2133 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2134 "unicodePwd", ntNewHash));
2135 el = ldb_msg_find_element(msg, "unicodePwd");
2136 el->flags = LDB_FLAG_MOD_REPLACE;
2139 /* the password wasn't specified correctly */
2141 return NT_STATUS_INVALID_PARAMETER;
2144 /* build modify request */
2145 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2146 samdb_set_password_callback, NULL);
2147 if (ret != LDB_SUCCESS) {
2149 return NT_STATUS_NO_MEMORY;
2152 /* A password change operation */
2153 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2154 struct dsdb_control_password_change *change;
2156 change = talloc(req, struct dsdb_control_password_change);
2157 if (change == NULL) {
2160 return NT_STATUS_NO_MEMORY;
2163 change->old_nt_pwd_hash = ntOldHash;
2164 change->old_lm_pwd_hash = lmOldHash;
2166 ret = ldb_request_add_control(req,
2167 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2169 if (ret != LDB_SUCCESS) {
2172 return NT_STATUS_NO_MEMORY;
2175 ret = ldb_request_add_control(req,
2176 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2178 if (ret != LDB_SUCCESS) {
2181 return NT_STATUS_NO_MEMORY;
2183 ret = ldb_request_add_control(req,
2184 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2186 if (ret != LDB_SUCCESS) {
2189 return NT_STATUS_NO_MEMORY;
2192 ret = dsdb_autotransaction_request(ldb, req);
2194 if (req->context != NULL) {
2195 pwd_stat = talloc_steal(mem_ctx,
2196 ((struct ldb_control *)req->context)->data);
2202 /* Sets the domain info (if requested) */
2203 if (_dominfo != NULL) {
2204 struct samr_DomInfo1 *dominfo;
2206 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2207 if (dominfo == NULL) {
2208 return NT_STATUS_NO_MEMORY;
2211 if (pwd_stat != NULL) {
2212 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2213 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2214 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2215 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2216 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2219 *_dominfo = dominfo;
2222 if (reject_reason != NULL) {
2223 if (pwd_stat != NULL) {
2224 *reject_reason = pwd_stat->reject_reason;
2226 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2230 if (pwd_stat != NULL) {
2231 talloc_free(pwd_stat);
2234 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2235 const char *errmsg = ldb_errstring(ldb);
2236 char *endptr = NULL;
2237 WERROR werr = WERR_GENERAL_FAILURE;
2238 status = NT_STATUS_UNSUCCESSFUL;
2239 if (errmsg != NULL) {
2240 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2242 if (endptr != errmsg) {
2243 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2244 status = NT_STATUS_WRONG_PASSWORD;
2246 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2247 status = NT_STATUS_PASSWORD_RESTRICTION;
2250 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2251 /* don't let the caller know if an account doesn't exist */
2252 status = NT_STATUS_WRONG_PASSWORD;
2253 } else if (ret != LDB_SUCCESS) {
2254 status = NT_STATUS_UNSUCCESSFUL;
2261 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2262 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2263 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2264 * user change or not. The "rejectReason" gives some more informations if the
2267 * This wrapper function for "samdb_set_password" takes a SID as input rather
2270 * This call encapsulates a new LDB transaction for changing the password;
2271 * therefore the user hasn't to start a new one.
2273 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2274 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2275 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2276 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2278 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2279 const struct dom_sid *user_sid,
2280 const DATA_BLOB *new_password,
2281 const struct samr_Password *lmNewHash,
2282 const struct samr_Password *ntNewHash,
2283 const struct samr_Password *lmOldHash,
2284 const struct samr_Password *ntOldHash,
2285 enum samPwdChangeReason *reject_reason,
2286 struct samr_DomInfo1 **_dominfo)
2289 struct ldb_dn *user_dn;
2292 ret = ldb_transaction_start(ldb);
2293 if (ret != LDB_SUCCESS) {
2294 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2295 return NT_STATUS_TRANSACTION_ABORTED;
2298 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2299 "(&(objectSid=%s)(objectClass=user))",
2300 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2302 ldb_transaction_cancel(ldb);
2303 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2304 dom_sid_string(mem_ctx, user_sid)));
2305 return NT_STATUS_NO_SUCH_USER;
2308 nt_status = samdb_set_password(ldb, mem_ctx,
2311 lmNewHash, ntNewHash,
2312 lmOldHash, ntOldHash,
2313 reject_reason, _dominfo);
2314 if (!NT_STATUS_IS_OK(nt_status)) {
2315 ldb_transaction_cancel(ldb);
2316 talloc_free(user_dn);
2320 ret = ldb_transaction_commit(ldb);
2321 if (ret != LDB_SUCCESS) {
2322 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2323 ldb_dn_get_linearized(user_dn),
2324 ldb_errstring(ldb)));
2325 talloc_free(user_dn);
2326 return NT_STATUS_TRANSACTION_ABORTED;
2329 talloc_free(user_dn);
2330 return NT_STATUS_OK;
2334 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2335 struct dom_sid *sid, struct ldb_dn **ret_dn)
2337 struct ldb_message *msg;
2338 struct ldb_dn *basedn;
2342 sidstr = dom_sid_string(mem_ctx, sid);
2343 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2345 /* We might have to create a ForeignSecurityPrincipal, even if this user
2346 * is in our own domain */
2348 msg = ldb_msg_new(sidstr);
2350 talloc_free(sidstr);
2351 return NT_STATUS_NO_MEMORY;
2354 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2355 ldb_get_default_basedn(sam_ctx),
2356 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2358 if (ret != LDB_SUCCESS) {
2359 DEBUG(0, ("Failed to find DN for "
2360 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2361 talloc_free(sidstr);
2362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2365 /* add core elements to the ldb_message for the alias */
2367 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2368 talloc_free(sidstr);
2369 return NT_STATUS_NO_MEMORY;
2372 ret = samdb_msg_add_string(sam_ctx, msg, msg,
2373 "objectClass", "foreignSecurityPrincipal");
2374 if (ret != LDB_SUCCESS) {
2375 talloc_free(sidstr);
2376 return NT_STATUS_NO_MEMORY;
2379 /* create the alias */
2380 ret = ldb_add(sam_ctx, msg);
2381 if (ret != LDB_SUCCESS) {
2382 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2384 ldb_dn_get_linearized(msg->dn),
2385 ldb_errstring(sam_ctx)));
2386 talloc_free(sidstr);
2387 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2390 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2391 talloc_free(sidstr);
2393 return NT_STATUS_OK;
2398 Find the DN of a domain, assuming it to be a dotted.dns name
2401 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2404 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2405 const char *binary_encoded;
2406 const char **split_realm;
2413 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2415 talloc_free(tmp_ctx);
2418 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2419 for (i=0; split_realm[i]; i++) {
2420 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2421 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2422 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2423 binary_encoded, ldb_dn_get_linearized(dn)));
2424 talloc_free(tmp_ctx);
2428 if (!ldb_dn_validate(dn)) {
2429 DEBUG(2, ("Failed to validated DN %s\n",
2430 ldb_dn_get_linearized(dn)));
2431 talloc_free(tmp_ctx);
2434 talloc_free(tmp_ctx);
2439 Find the DN of a domain, be it the netbios or DNS name
2441 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2442 const char *domain_name)
2444 const char * const domain_ref_attrs[] = {
2447 const char * const domain_ref2_attrs[] = {
2450 struct ldb_result *res_domain_ref;
2451 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2452 /* find the domain's DN */
2453 int ret_domain = ldb_search(ldb, mem_ctx,
2455 samdb_partitions_dn(ldb, mem_ctx),
2458 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2460 if (ret_domain != LDB_SUCCESS) {
2464 if (res_domain_ref->count == 0) {
2465 ret_domain = ldb_search(ldb, mem_ctx,
2467 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2470 "(objectclass=domain)");
2471 if (ret_domain != LDB_SUCCESS) {
2475 if (res_domain_ref->count == 1) {
2476 return res_domain_ref->msgs[0]->dn;
2481 if (res_domain_ref->count > 1) {
2482 DEBUG(0,("Found %d records matching domain [%s]\n",
2483 ret_domain, domain_name));
2487 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2493 use a GUID to find a DN
2495 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2496 TALLOC_CTX *mem_ctx,
2497 const struct GUID *guid, struct ldb_dn **dn)
2500 struct ldb_result *res;
2501 const char *attrs[] = { NULL };
2502 char *guid_str = GUID_string(mem_ctx, guid);
2505 return ldb_operr(ldb);
2508 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2509 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2510 DSDB_SEARCH_SHOW_EXTENDED_DN |
2511 DSDB_SEARCH_ONE_ONLY,
2512 "objectGUID=%s", guid_str);
2513 talloc_free(guid_str);
2514 if (ret != LDB_SUCCESS) {
2518 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2525 use a DN to find a GUID with a given attribute name
2527 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2528 struct ldb_dn *dn, const char *attribute,
2532 struct ldb_result *res;
2533 const char *attrs[2];
2534 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2536 attrs[0] = attribute;
2539 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2540 DSDB_SEARCH_SHOW_DELETED |
2541 DSDB_SEARCH_SHOW_RECYCLED);
2542 if (ret != LDB_SUCCESS) {
2543 talloc_free(tmp_ctx);
2546 if (res->count < 1) {
2547 talloc_free(tmp_ctx);
2548 return LDB_ERR_NO_SUCH_OBJECT;
2550 *guid = samdb_result_guid(res->msgs[0], attribute);
2551 talloc_free(tmp_ctx);
2556 use a DN to find a GUID
2558 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2559 struct ldb_dn *dn, struct GUID *guid)
2561 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2567 adds the given GUID to the given ldb_message. This value is added
2568 for the given attr_name (may be either "objectGUID" or "parentGUID").
2570 int dsdb_msg_add_guid(struct ldb_message *msg,
2572 const char *attr_name)
2577 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2579 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 ret = LDB_ERR_OPERATIONS_ERROR;
2585 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2586 if (ret != LDB_SUCCESS) {
2587 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2595 talloc_free(tmp_ctx);
2602 use a DN to find a SID
2604 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2605 struct ldb_dn *dn, struct dom_sid *sid)
2608 struct ldb_result *res;
2609 const char *attrs[] = { "objectSid", NULL };
2610 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2615 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2616 DSDB_SEARCH_SHOW_DELETED |
2617 DSDB_SEARCH_SHOW_RECYCLED);
2618 if (ret != LDB_SUCCESS) {
2619 talloc_free(tmp_ctx);
2622 if (res->count < 1) {
2623 talloc_free(tmp_ctx);
2624 return LDB_ERR_NO_SUCH_OBJECT;
2626 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2628 talloc_free(tmp_ctx);
2629 return LDB_ERR_NO_SUCH_OBJECT;
2632 talloc_free(tmp_ctx);
2637 use a SID to find a DN
2639 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2640 TALLOC_CTX *mem_ctx,
2641 struct dom_sid *sid, struct ldb_dn **dn)
2644 struct ldb_result *res;
2645 const char *attrs[] = { NULL };
2646 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2649 return ldb_operr(ldb);
2652 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2653 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2654 DSDB_SEARCH_SHOW_EXTENDED_DN |
2655 DSDB_SEARCH_ONE_ONLY,
2656 "objectSid=%s", sid_str);
2657 talloc_free(sid_str);
2658 if (ret != LDB_SUCCESS) {
2662 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2669 load a repsFromTo blob list for a given partition GUID
2670 attr must be "repsFrom" or "repsTo"
2672 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2673 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2675 const char *attrs[] = { attr, NULL };
2676 struct ldb_result *res = NULL;
2677 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2679 struct ldb_message_element *el;
2684 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2686 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2687 talloc_free(tmp_ctx);
2688 return WERR_DS_DRA_INTERNAL_ERROR;
2691 el = ldb_msg_find_element(res->msgs[0], attr);
2693 /* it's OK to be empty */
2694 talloc_free(tmp_ctx);
2698 *count = el->num_values;
2699 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2701 talloc_free(tmp_ctx);
2702 return WERR_DS_DRA_INTERNAL_ERROR;
2705 for (i=0; i<(*count); i++) {
2706 enum ndr_err_code ndr_err;
2707 ndr_err = ndr_pull_struct_blob(&el->values[i],
2710 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2711 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2712 talloc_free(tmp_ctx);
2713 return WERR_DS_DRA_INTERNAL_ERROR;
2717 talloc_free(tmp_ctx);
2723 save the repsFromTo blob list for a given partition GUID
2724 attr must be "repsFrom" or "repsTo"
2726 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2727 const char *attr, struct repsFromToBlob *r, uint32_t count)
2729 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2730 struct ldb_message *msg;
2731 struct ldb_message_element *el;
2734 msg = ldb_msg_new(tmp_ctx);
2736 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2740 el->values = talloc_array(msg, struct ldb_val, count);
2745 for (i=0; i<count; i++) {
2747 enum ndr_err_code ndr_err;
2749 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2751 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2752 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2760 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2761 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2765 talloc_free(tmp_ctx);
2770 talloc_free(tmp_ctx);
2771 return WERR_DS_DRA_INTERNAL_ERROR;
2776 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2777 object for a partition
2779 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2780 uint64_t *uSN, uint64_t *urgent_uSN)
2782 struct ldb_request *req;
2784 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2785 struct dsdb_control_current_partition *p_ctrl;
2786 struct ldb_result *res;
2788 res = talloc_zero(tmp_ctx, struct ldb_result);
2790 talloc_free(tmp_ctx);
2791 return ldb_oom(ldb);
2794 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2795 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2799 res, ldb_search_default_callback,
2801 if (ret != LDB_SUCCESS) {
2802 talloc_free(tmp_ctx);
2806 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2807 if (p_ctrl == NULL) {
2808 talloc_free(tmp_ctx);
2809 return ldb_oom(ldb);
2811 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2814 ret = ldb_request_add_control(req,
2815 DSDB_CONTROL_CURRENT_PARTITION_OID,
2817 if (ret != LDB_SUCCESS) {
2818 talloc_free(tmp_ctx);
2822 /* Run the new request */
2823 ret = ldb_request(ldb, req);
2825 if (ret == LDB_SUCCESS) {
2826 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2829 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
2830 /* it hasn't been created yet, which means
2831 an implicit value of zero */
2833 talloc_free(tmp_ctx);
2837 if (ret != LDB_SUCCESS) {
2838 talloc_free(tmp_ctx);
2842 if (res->count < 1) {
2848 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2850 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2854 talloc_free(tmp_ctx);
2859 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2860 const struct drsuapi_DsReplicaCursor2 *c2)
2862 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2865 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2866 const struct drsuapi_DsReplicaCursor *c2)
2868 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2873 see if a computer identified by its invocationId is a RODC
2875 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2877 /* 1) find the DN for this servers NTDSDSA object
2878 2) search for the msDS-isRODC attribute
2879 3) if not present then not a RODC
2880 4) if present and TRUE then is a RODC
2882 struct ldb_dn *config_dn;
2883 const char *attrs[] = { "msDS-isRODC", NULL };
2885 struct ldb_result *res;
2886 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2888 config_dn = ldb_get_config_basedn(sam_ctx);
2890 talloc_free(tmp_ctx);
2891 return ldb_operr(sam_ctx);
2894 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2895 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2897 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2899 talloc_free(tmp_ctx);
2903 if (ret != LDB_SUCCESS) {
2904 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2905 GUID_string(tmp_ctx, objectGUID)));
2907 talloc_free(tmp_ctx);
2911 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2912 *is_rodc = (ret == 1);
2914 talloc_free(tmp_ctx);
2920 see if we are a RODC
2922 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2924 const struct GUID *objectGUID;
2928 /* see if we have a cached copy */
2929 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2935 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2937 return ldb_operr(sam_ctx);
2940 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2941 if (ret != LDB_SUCCESS) {
2945 cached = talloc(sam_ctx, bool);
2946 if (cached == NULL) {
2947 return ldb_oom(sam_ctx);
2951 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2952 if (ret != LDB_SUCCESS) {
2953 talloc_free(cached);
2954 return ldb_operr(sam_ctx);
2960 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2962 TALLOC_CTX *tmp_ctx;
2965 tmp_ctx = talloc_new(ldb);
2966 if (tmp_ctx == NULL) {
2970 cached = talloc(tmp_ctx, bool);
2976 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2980 talloc_steal(ldb, cached);
2981 talloc_free(tmp_ctx);
2985 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2986 talloc_free(tmp_ctx);
2992 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2994 flags are DS_NTDS_OPTION_*
2996 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2998 TALLOC_CTX *tmp_ctx;
2999 const char *attrs[] = { "options", NULL };
3001 struct ldb_result *res;
3003 tmp_ctx = talloc_new(ldb);
3004 if (tmp_ctx == NULL) {
3008 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3009 if (ret != LDB_SUCCESS) {
3013 if (res->count != 1) {
3017 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3019 talloc_free(tmp_ctx);
3024 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3025 talloc_free(tmp_ctx);
3026 return LDB_ERR_NO_SUCH_OBJECT;
3029 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3031 const char *attrs[] = { "objectCategory", NULL };
3033 struct ldb_result *res;
3035 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3036 if (ret != LDB_SUCCESS) {
3040 if (res->count != 1) {
3044 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3047 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3052 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3053 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3055 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3057 char **tokens, *ret;
3060 tokens = str_list_make(mem_ctx, cn, " -_");
3064 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3065 tokens[0][0] = tolower(tokens[0][0]);
3066 for (i = 1; i < str_list_length((const char **)tokens); i++)
3067 tokens[i][0] = toupper(tokens[i][0]);
3069 ret = talloc_strdup(mem_ctx, tokens[0]);
3070 for (i = 1; i < str_list_length((const char **)tokens); i++)
3071 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3073 talloc_free(tokens);
3079 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3081 int dsdb_functional_level(struct ldb_context *ldb)
3083 int *domainFunctionality =
3084 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3085 if (!domainFunctionality) {
3086 /* this is expected during initial provision */
3087 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3088 return DS_DOMAIN_FUNCTION_2000;
3090 return *domainFunctionality;
3094 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3096 int dsdb_forest_functional_level(struct ldb_context *ldb)
3098 int *forestFunctionality =
3099 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3100 if (!forestFunctionality) {
3101 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3102 return DS_DOMAIN_FUNCTION_2000;
3104 return *forestFunctionality;
3108 set a GUID in an extended DN structure
3110 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3116 status = GUID_to_ndr_blob(guid, dn, &v);
3117 if (!NT_STATUS_IS_OK(status)) {
3118 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3121 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3127 return a GUID from a extended DN structure
3129 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3131 const struct ldb_val *v;
3133 v = ldb_dn_get_extended_component(dn, component_name);
3135 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3138 return GUID_from_ndr_blob(v, guid);
3142 return a uint64_t from a extended DN structure
3144 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3146 const struct ldb_val *v;
3149 v = ldb_dn_get_extended_component(dn, component_name);
3151 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3153 s = talloc_strndup(dn, (const char *)v->data, v->length);
3154 NT_STATUS_HAVE_NO_MEMORY(s);
3156 *val = strtoull(s, NULL, 0);
3159 return NT_STATUS_OK;
3163 return a NTTIME from a extended DN structure
3165 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3167 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3171 return a uint32_t from a extended DN structure
3173 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3175 const struct ldb_val *v;
3178 v = ldb_dn_get_extended_component(dn, component_name);
3180 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3183 s = talloc_strndup(dn, (const char *)v->data, v->length);
3184 NT_STATUS_HAVE_NO_MEMORY(s);
3186 *val = strtoul(s, NULL, 0);
3189 return NT_STATUS_OK;
3193 return a dom_sid from a extended DN structure
3195 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3197 const struct ldb_val *sid_blob;
3198 struct TALLOC_CTX *tmp_ctx;
3199 enum ndr_err_code ndr_err;
3201 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3203 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3206 tmp_ctx = talloc_new(NULL);
3208 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3209 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3211 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3212 talloc_free(tmp_ctx);
3216 talloc_free(tmp_ctx);
3217 return NT_STATUS_OK;
3222 return RMD_FLAGS directly from a ldb_dn
3223 returns 0 if not found
3225 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3227 const struct ldb_val *v;
3229 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3230 if (!v || v->length > sizeof(buf)-1) return 0;
3231 strncpy(buf, (const char *)v->data, v->length);
3233 return strtoul(buf, NULL, 10);
3237 return RMD_FLAGS directly from a ldb_val for a DN
3238 returns 0 if RMD_FLAGS is not found
3240 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3246 if (val->length < 13) {
3249 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3253 flags = strtoul(p+11, &end, 10);
3254 if (!end || *end != '>') {
3255 /* it must end in a > */
3262 return true if a ldb_val containing a DN in storage form is deleted
3264 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3266 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3270 return true if a ldb_val containing a DN in storage form is
3271 in the upgraded w2k3 linked attribute format
3273 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3275 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3279 return a DN for a wellknown GUID
3281 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3282 struct ldb_dn *nc_root, const char *wk_guid,
3283 struct ldb_dn **wkguid_dn)
3285 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3286 const char *attrs[] = { NULL };
3289 struct ldb_result *res;
3291 /* construct the magic WKGUID DN */
3292 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3293 wk_guid, ldb_dn_get_linearized(nc_root));
3295 talloc_free(tmp_ctx);
3296 return ldb_operr(samdb);
3299 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3300 DSDB_SEARCH_SHOW_DELETED |
3301 DSDB_SEARCH_SHOW_RECYCLED);
3302 if (ret != LDB_SUCCESS) {
3303 talloc_free(tmp_ctx);
3307 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3308 talloc_free(tmp_ctx);
3313 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3315 return ldb_dn_compare(*dn1, *dn2);
3319 find a NC root given a DN within the NC
3321 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3322 struct ldb_dn **nc_root)
3324 const char *root_attrs[] = { "namingContexts", NULL };
3325 TALLOC_CTX *tmp_ctx;
3327 struct ldb_message_element *el;
3328 struct ldb_result *root_res;
3330 struct ldb_dn **nc_dns;
3332 tmp_ctx = talloc_new(samdb);
3333 if (tmp_ctx == NULL) {
3334 return ldb_oom(samdb);
3337 ret = ldb_search(samdb, tmp_ctx, &root_res,
3338 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3339 if (ret != LDB_SUCCESS) {
3340 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3341 talloc_free(tmp_ctx);
3345 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3347 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3348 ldb_errstring(samdb)));
3349 talloc_free(tmp_ctx);
3350 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3353 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3355 talloc_free(tmp_ctx);
3356 return ldb_oom(samdb);
3359 for (i=0; i<el->num_values; i++) {
3360 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3361 if (nc_dns[i] == NULL) {
3362 talloc_free(tmp_ctx);
3363 return ldb_operr(samdb);
3367 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3369 for (i=0; i<el->num_values; i++) {
3370 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3371 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3372 talloc_free(tmp_ctx);
3377 talloc_free(tmp_ctx);
3378 return LDB_ERR_NO_SUCH_OBJECT;
3383 find the deleted objects DN for any object, by looking for the NC
3384 root, then looking up the wellknown GUID
3386 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3387 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3388 struct ldb_dn **do_dn)
3390 struct ldb_dn *nc_root;
3393 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3394 if (ret != LDB_SUCCESS) {
3398 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3399 talloc_free(nc_root);
3404 return the tombstoneLifetime, in days
3406 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3409 dn = ldb_get_config_basedn(ldb);
3411 return LDB_ERR_NO_SUCH_OBJECT;
3413 dn = ldb_dn_copy(ldb, dn);
3415 return ldb_operr(ldb);
3417 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3418 be a wellknown GUID for this */
3419 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3421 return ldb_operr(ldb);
3424 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3430 compare a ldb_val to a string case insensitively
3432 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3434 size_t len = strlen(s);
3436 if (len > v->length) return 1;
3437 ret = strncasecmp(s, (const char *)v->data, v->length);
3438 if (ret != 0) return ret;
3439 if (v->length > len && v->data[len] != 0) {
3447 load the UDV for a partition in v2 format
3448 The list is returned sorted, and with our local cursor added
3450 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3451 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3453 static const char *attrs[] = { "replUpToDateVector", NULL };
3454 struct ldb_result *r;
3455 const struct ldb_val *ouv_value;
3458 uint64_t highest_usn;
3459 const struct GUID *our_invocation_id;
3460 struct timeval now = timeval_current();
3462 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3463 if (ret != LDB_SUCCESS) {
3467 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3469 enum ndr_err_code ndr_err;
3470 struct replUpToDateVectorBlob ouv;
3472 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3473 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3474 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3476 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3478 if (ouv.version != 2) {
3479 /* we always store as version 2, and
3480 * replUpToDateVector is not replicated
3482 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3485 *count = ouv.ctr.ctr2.count;
3486 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3494 our_invocation_id = samdb_ntds_invocation_id(samdb);
3495 if (!our_invocation_id) {
3496 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3497 talloc_free(*cursors);
3498 return ldb_operr(samdb);
3501 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3502 if (ret != LDB_SUCCESS) {
3503 /* nothing to add - this can happen after a vampire */
3504 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3508 for (i=0; i<*count; i++) {
3509 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3510 (*cursors)[i].highest_usn = highest_usn;
3511 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3512 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3517 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3519 return ldb_oom(samdb);
3522 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3523 (*cursors)[*count].highest_usn = highest_usn;
3524 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3527 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3533 load the UDV for a partition in version 1 format
3534 The list is returned sorted, and with our local cursor added
3536 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3537 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3539 struct drsuapi_DsReplicaCursor2 *v2;
3543 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3544 if (ret != LDB_SUCCESS) {
3554 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3555 if (*cursors == NULL) {
3557 return ldb_oom(samdb);
3560 for (i=0; i<*count; i++) {
3561 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3562 (*cursors)[i].highest_usn = v2[i].highest_usn;
3569 add a set of controls to a ldb_request structure based on a set of
3570 flags. See util.h for a list of available flags
3572 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3575 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3576 struct ldb_search_options_control *options;
3577 /* Using the phantom root control allows us to search all partitions */
3578 options = talloc(req, struct ldb_search_options_control);
3579 if (options == NULL) {
3580 return LDB_ERR_OPERATIONS_ERROR;
3582 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3584 ret = ldb_request_add_control(req,
3585 LDB_CONTROL_SEARCH_OPTIONS_OID,
3587 if (ret != LDB_SUCCESS) {
3592 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3593 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3594 if (ret != LDB_SUCCESS) {
3599 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3600 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3601 if (ret != LDB_SUCCESS) {
3606 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3607 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3608 if (ret != LDB_SUCCESS) {
3613 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3614 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3615 if (!extended_ctrl) {
3616 return LDB_ERR_OPERATIONS_ERROR;
3618 extended_ctrl->type = 1;
3620 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3621 if (ret != LDB_SUCCESS) {
3626 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3627 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3628 if (ret != LDB_SUCCESS) {
3633 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3634 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3635 if (ret != LDB_SUCCESS) {
3640 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3641 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3642 if (ret != LDB_SUCCESS) {
3647 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3648 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3649 if (ret != LDB_SUCCESS) {
3654 if (dsdb_flags & DSDB_TREE_DELETE) {
3655 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3656 if (ret != LDB_SUCCESS) {
3661 if (dsdb_flags & DSDB_PROVISION) {
3662 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
3663 if (ret != LDB_SUCCESS) {
3672 an add with a set of controls
3674 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3675 uint32_t dsdb_flags)
3677 struct ldb_request *req;
3680 ret = ldb_build_add_req(&req, ldb, ldb,
3684 ldb_op_default_callback,
3687 if (ret != LDB_SUCCESS) return ret;
3689 ret = dsdb_request_add_controls(req, dsdb_flags);
3690 if (ret != LDB_SUCCESS) {
3695 ret = dsdb_autotransaction_request(ldb, req);
3702 a modify with a set of controls
3704 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3705 uint32_t dsdb_flags)
3707 struct ldb_request *req;
3710 ret = ldb_build_mod_req(&req, ldb, ldb,
3714 ldb_op_default_callback,
3717 if (ret != LDB_SUCCESS) return ret;
3719 ret = dsdb_request_add_controls(req, dsdb_flags);
3720 if (ret != LDB_SUCCESS) {
3725 ret = dsdb_autotransaction_request(ldb, req);
3732 like dsdb_modify() but set all the element flags to
3733 LDB_FLAG_MOD_REPLACE
3735 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3739 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3740 for (i=0;i<msg->num_elements;i++) {
3741 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3744 return dsdb_modify(ldb, msg, dsdb_flags);
3749 search for attrs on one DN, allowing for dsdb_flags controls
3751 int dsdb_search_dn(struct ldb_context *ldb,
3752 TALLOC_CTX *mem_ctx,
3753 struct ldb_result **_res,
3754 struct ldb_dn *basedn,
3755 const char * const *attrs,
3756 uint32_t dsdb_flags)
3759 struct ldb_request *req;
3760 struct ldb_result *res;
3762 res = talloc_zero(mem_ctx, struct ldb_result);
3764 return ldb_oom(ldb);
3767 ret = ldb_build_search_req(&req, ldb, res,
3774 ldb_search_default_callback,
3776 if (ret != LDB_SUCCESS) {
3781 ret = dsdb_request_add_controls(req, dsdb_flags);
3782 if (ret != LDB_SUCCESS) {
3787 ret = ldb_request(ldb, req);
3788 if (ret == LDB_SUCCESS) {
3789 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3793 if (ret != LDB_SUCCESS) {
3803 search for attrs on one DN, by the GUID of the DN, allowing for
3806 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3807 TALLOC_CTX *mem_ctx,
3808 struct ldb_result **_res,
3809 const struct GUID *guid,
3810 const char * const *attrs,
3811 uint32_t dsdb_flags)
3813 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3817 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3818 if (!ldb_dn_validate(dn)) {
3819 talloc_free(tmp_ctx);
3820 return LDB_ERR_INVALID_DN_SYNTAX;
3823 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3824 talloc_free(tmp_ctx);
3829 general search with dsdb_flags for controls
3831 int dsdb_search(struct ldb_context *ldb,
3832 TALLOC_CTX *mem_ctx,
3833 struct ldb_result **_res,
3834 struct ldb_dn *basedn,
3835 enum ldb_scope scope,
3836 const char * const *attrs,
3837 uint32_t dsdb_flags,
3838 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3841 struct ldb_request *req;
3842 struct ldb_result *res;
3844 char *expression = NULL;
3845 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3847 res = talloc_zero(tmp_ctx, struct ldb_result);
3849 talloc_free(tmp_ctx);
3850 return ldb_oom(ldb);
3854 va_start(ap, exp_fmt);
3855 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3859 talloc_free(tmp_ctx);
3860 return ldb_oom(ldb);
3864 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3871 ldb_search_default_callback,
3873 if (ret != LDB_SUCCESS) {
3874 talloc_free(tmp_ctx);
3878 ret = dsdb_request_add_controls(req, dsdb_flags);
3879 if (ret != LDB_SUCCESS) {
3880 talloc_free(tmp_ctx);
3881 ldb_reset_err_string(ldb);
3885 ret = ldb_request(ldb, req);
3886 if (ret == LDB_SUCCESS) {
3887 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3890 if (ret != LDB_SUCCESS) {
3891 talloc_free(tmp_ctx);
3895 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3896 if (res->count == 0) {
3897 talloc_free(tmp_ctx);
3898 ldb_reset_err_string(ldb);
3899 return LDB_ERR_NO_SUCH_OBJECT;
3901 if (res->count != 1) {
3902 talloc_free(tmp_ctx);
3903 ldb_reset_err_string(ldb);
3904 return LDB_ERR_CONSTRAINT_VIOLATION;
3908 *_res = talloc_steal(mem_ctx, res);
3909 talloc_free(tmp_ctx);
3916 general search with dsdb_flags for controls
3917 returns exactly 1 record or an error
3919 int dsdb_search_one(struct ldb_context *ldb,
3920 TALLOC_CTX *mem_ctx,
3921 struct ldb_message **msg,
3922 struct ldb_dn *basedn,
3923 enum ldb_scope scope,
3924 const char * const *attrs,
3925 uint32_t dsdb_flags,
3926 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3929 struct ldb_result *res;
3931 char *expression = NULL;
3932 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3934 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3936 res = talloc_zero(tmp_ctx, struct ldb_result);
3938 talloc_free(tmp_ctx);
3939 return ldb_oom(ldb);
3943 va_start(ap, exp_fmt);
3944 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3948 talloc_free(tmp_ctx);
3949 return ldb_oom(ldb);
3951 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3952 dsdb_flags, "%s", expression);
3954 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3958 if (ret != LDB_SUCCESS) {
3959 talloc_free(tmp_ctx);
3963 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3964 talloc_free(tmp_ctx);
3969 /* returns back the forest DNS name */
3970 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3972 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3973 ldb_get_root_basedn(ldb));
3976 if (forest_name == NULL) {
3980 p = strchr(forest_name, '/');
3989 validate that an DSA GUID belongs to the specified user sid.
3990 The user SID must be a domain controller account (either RODC or
3993 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3994 const struct GUID *dsa_guid,
3995 const struct dom_sid *sid)
3998 - find DN of record with the DSA GUID in the
3999 configuration partition (objectGUID)
4000 - remove "NTDS Settings" component from DN
4001 - do a base search on that DN for serverReference with
4003 - extract objectSid from resulting serverReference
4005 - check this sid matches the sid argument
4007 struct ldb_dn *config_dn;
4008 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4009 struct ldb_message *msg;
4010 const char *attrs1[] = { NULL };
4011 const char *attrs2[] = { "serverReference", NULL };
4013 struct ldb_dn *dn, *account_dn;
4014 struct dom_sid sid2;
4017 config_dn = ldb_get_config_basedn(ldb);
4019 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4020 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4021 if (ret != LDB_SUCCESS) {
4022 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4023 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4024 talloc_free(tmp_ctx);
4025 return ldb_operr(ldb);
4029 if (!ldb_dn_remove_child_components(dn, 1)) {
4030 talloc_free(tmp_ctx);
4031 return ldb_operr(ldb);
4034 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4035 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4036 "(objectClass=server)");
4037 if (ret != LDB_SUCCESS) {
4038 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4039 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4040 talloc_free(tmp_ctx);
4041 return ldb_operr(ldb);
4044 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4045 if (account_dn == NULL) {
4046 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4047 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4048 talloc_free(tmp_ctx);
4049 return ldb_operr(ldb);
4052 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4053 if (!NT_STATUS_IS_OK(status)) {
4054 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4055 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4056 talloc_free(tmp_ctx);
4057 return ldb_operr(ldb);
4060 if (!dom_sid_equal(sid, &sid2)) {
4061 /* someone is trying to spoof another account */
4062 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4063 GUID_string(tmp_ctx, dsa_guid),
4064 dom_sid_string(tmp_ctx, sid),
4065 dom_sid_string(tmp_ctx, &sid2)));
4066 talloc_free(tmp_ctx);
4067 return ldb_operr(ldb);
4070 talloc_free(tmp_ctx);
4074 static const char *secret_attributes[] = {
4077 "initialAuthIncoming",
4078 "initialAuthOutgoing",
4082 "supplementalCredentials",
4083 "trustAuthIncoming",
4084 "trustAuthOutgoing",
4090 check if the attribute belongs to the RODC filtered attribute set
4091 Note that attributes that are in the filtered attribute set are the
4092 ones that _are_ always sent to a RODC
4094 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4096 /* they never get secret attributes */
4097 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4101 /* they do get non-secret critical attributes */
4102 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4106 /* they do get non-secret attributes marked as being in the FAS */
4107 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4111 /* other attributes are denied */
4115 /* return fsmo role dn and role owner dn for a particular role*/
4116 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4117 struct ldb_context *ldb,
4119 struct ldb_dn **fsmo_role_dn,
4120 struct ldb_dn **role_owner_dn)
4124 case DREPL_NAMING_MASTER:
4125 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4126 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4127 if (ret != LDB_SUCCESS) {
4128 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4129 ldb_errstring(ldb)));
4130 talloc_free(tmp_ctx);
4131 return WERR_DS_DRA_INTERNAL_ERROR;
4134 case DREPL_INFRASTRUCTURE_MASTER:
4135 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4136 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4137 if (ret != LDB_SUCCESS) {
4138 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4139 ldb_errstring(ldb)));
4140 talloc_free(tmp_ctx);
4141 return WERR_DS_DRA_INTERNAL_ERROR;
4144 case DREPL_RID_MASTER:
4145 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4146 if (ret != LDB_SUCCESS) {
4147 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4148 talloc_free(tmp_ctx);
4149 return WERR_DS_DRA_INTERNAL_ERROR;
4152 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4153 if (ret != LDB_SUCCESS) {
4154 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4155 ldb_errstring(ldb)));
4156 talloc_free(tmp_ctx);
4157 return WERR_DS_DRA_INTERNAL_ERROR;
4160 case DREPL_SCHEMA_MASTER:
4161 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4162 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4163 if (ret != LDB_SUCCESS) {
4164 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4165 ldb_errstring(ldb)));
4166 talloc_free(tmp_ctx);
4167 return WERR_DS_DRA_INTERNAL_ERROR;
4170 case DREPL_PDC_MASTER:
4171 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4172 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4173 if (ret != LDB_SUCCESS) {
4174 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4175 ldb_errstring(ldb)));
4176 talloc_free(tmp_ctx);
4177 return WERR_DS_DRA_INTERNAL_ERROR;
4181 return WERR_DS_DRA_INTERNAL_ERROR;
4186 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4187 TALLOC_CTX *mem_ctx,
4188 struct ldb_dn *server_dn)
4191 struct ldb_result *res = NULL;
4192 const char * const attrs[] = { "dNSHostName", NULL};
4194 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4198 if (ldb_ret != LDB_SUCCESS) {
4199 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4200 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4204 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4208 returns true if an attribute is in the filter,
4209 false otherwise, provided that attribute value is provided with the expression
4211 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4215 switch (tree->operation) {
4218 for (i=0;i<tree->u.list.num_elements;i++) {
4219 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4225 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4226 case LDB_OP_EQUALITY:
4227 case LDB_OP_GREATER:
4230 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4234 case LDB_OP_SUBSTRING:
4235 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4239 case LDB_OP_PRESENT:
4240 /* (attrname=*) is not filtered out */
4242 case LDB_OP_EXTENDED:
4243 if (tree->u.extended.attr &&
4244 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4252 bool is_attr_in_list(const char * const * attrs, const char *attr)
4256 for (i = 0; attrs[i]; i++) {
4257 if (ldb_attr_cmp(attrs[i], attr) == 0)