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,
195 struct ldb_dn *basedn,
196 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
199 struct ldb_message **res;
200 const char *attrs[] = { NULL };
202 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
204 va_start(ap, format);
205 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
207 talloc_free(tmp_ctx);
214 search the sam for a single integer attribute in exactly 1 record
216 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
218 unsigned int default_value,
219 struct ldb_dn *basedn,
220 const char *attr_name,
221 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
225 struct ldb_message **res;
226 const char *attrs[2] = { NULL, NULL };
228 attrs[0] = attr_name;
230 va_start(ap, format);
231 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
235 return default_value;
238 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
242 search the sam for a single signed 64 bit integer attribute in exactly 1 record
244 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
246 int64_t default_value,
247 struct ldb_dn *basedn,
248 const char *attr_name,
249 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
253 struct ldb_message **res;
254 const char *attrs[2] = { NULL, NULL };
256 attrs[0] = attr_name;
258 va_start(ap, format);
259 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
263 return default_value;
266 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
270 search the sam for multipe records each giving a single string attribute
271 return the number of matches, or -1 on error
273 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
275 struct ldb_dn *basedn,
277 const char *attr_name,
278 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
282 const char *attrs[2] = { NULL, NULL };
283 struct ldb_message **res = NULL;
285 attrs[0] = attr_name;
287 va_start(ap, format);
288 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
295 /* make sure its single valued */
296 for (i=0;i<count;i++) {
297 if (res[i]->num_elements != 1) {
298 DEBUG(1,("samdb: search for %s %s not single valued\n",
305 *strs = talloc_array(mem_ctx, const char *, count+1);
311 for (i=0;i<count;i++) {
312 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
314 (*strs)[count] = NULL;
319 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
320 const char *attr, struct ldb_dn *default_value)
322 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
324 return default_value;
330 pull a rid from a objectSid in a result set.
332 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
333 const char *attr, uint32_t default_value)
338 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
340 return default_value;
342 rid = sid->sub_auths[sid->num_auths-1];
348 pull a dom_sid structure from a objectSid in a result set.
350 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
353 const struct ldb_val *v;
355 enum ndr_err_code ndr_err;
356 v = ldb_msg_find_ldb_val(msg, attr);
360 sid = talloc(mem_ctx, struct dom_sid);
364 ndr_err = ndr_pull_struct_blob(v, sid, sid,
365 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 pull a guid structure from a objectGUID in a result set.
376 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
378 const struct ldb_val *v;
382 v = ldb_msg_find_ldb_val(msg, attr);
383 if (!v) return GUID_zero();
385 status = GUID_from_ndr_blob(v, &guid);
386 if (!NT_STATUS_IS_OK(status)) {
394 pull a sid prefix from a objectSid in a result set.
395 this is used to find the domain sid for a user
397 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
400 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
401 if (!sid || sid->num_auths < 1) return NULL;
407 pull a NTTIME in a result set.
409 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
410 NTTIME default_value)
412 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
416 * Windows stores 0 for lastLogoff.
417 * But when a MS DC return the lastLogoff (as Logoff Time)
418 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
419 * cause windows 2008 and newer version to fail for SMB requests
421 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
423 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
426 ret = 0x7FFFFFFFFFFFFFFFULL;
432 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
433 * indicate an account doesn't expire.
435 * When Windows initially creates an account, it sets
436 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
437 * when changing from an account having a specific expiration date to
438 * that account never expiring, it sets accountExpires = 0.
440 * Consolidate that logic here to allow clearer logic for account expiry in
441 * the rest of the code.
443 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
445 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
449 ret = 0x7FFFFFFFFFFFFFFFULL;
455 construct the allow_password_change field from the PwdLastSet attribute and the
456 domain password settings
458 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
460 struct ldb_dn *domain_dn,
461 struct ldb_message *msg,
464 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
467 if (attr_time == 0) {
471 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
473 /* yes, this is a -= not a += as minPwdAge is stored as the negative
474 of the number of 100-nano-seconds */
475 attr_time -= minPwdAge;
481 construct the force_password_change field from the PwdLastSet
482 attribute, the userAccountControl and the domain password settings
484 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
486 struct ldb_dn *domain_dn,
487 struct ldb_message *msg)
489 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
490 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
491 "userAccountControl",
495 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
496 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
497 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
498 return 0x7FFFFFFFFFFFFFFFULL;
501 if (attr_time == 0) {
504 if (attr_time == -1) {
505 return 0x7FFFFFFFFFFFFFFFULL;
508 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
510 if (maxPwdAge == 0) {
511 return 0x7FFFFFFFFFFFFFFFULL;
513 attr_time -= maxPwdAge;
520 pull a samr_Password structutre from a result set.
522 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
524 struct samr_Password *hash = NULL;
525 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
526 if (val && (val->length >= sizeof(hash->hash))) {
527 hash = talloc(mem_ctx, struct samr_Password);
528 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
534 pull an array of samr_Password structures from a result set.
536 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
537 const char *attr, struct samr_Password **hashes)
539 unsigned int count, i;
540 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
546 count = val->length / 16;
551 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
556 for (i=0;i<count;i++) {
557 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
563 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
564 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
566 struct samr_Password *lmPwdHash, *ntPwdHash;
569 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
572 } else if (num_nt > 1) {
573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
575 *nt_pwd = &ntPwdHash[0];
579 /* Ensure that if we have turned off LM
580 * authentication, that we never use the LM hash, even
582 if (lpcfg_lanman_auth(lp_ctx)) {
584 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
587 } else if (num_lm > 1) {
588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590 *lm_pwd = &lmPwdHash[0];
600 pull a samr_LogonHours structutre from a result set.
602 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
604 struct samr_LogonHours hours;
605 size_t units_per_week = 168;
606 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
611 units_per_week = val->length * 8;
614 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
618 hours.units_per_week = units_per_week;
619 memset(hours.bits, 0xFF, units_per_week/8);
621 memcpy(hours.bits, val->data, val->length);
628 pull a set of account_flags from a result set.
630 This requires that the attributes:
635 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
636 struct ldb_message *msg, struct ldb_dn *domain_dn)
638 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
639 uint32_t acct_flags = ds_uf2acb(userAccountControl);
640 NTTIME must_change_time;
643 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
646 /* Test account expire time */
647 unix_to_nt_time(&now, time(NULL));
648 /* check for expired password */
649 if (must_change_time < now) {
650 acct_flags |= ACB_PW_EXPIRED;
655 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
656 struct ldb_message *msg,
659 struct lsa_BinaryString s;
660 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
668 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
672 s.length = s.size = val->length;
673 memcpy(s.array, val->data, val->length);
678 /* Find an attribute, with a particular value */
680 /* The current callers of this function expect a very specific
681 * behaviour: In particular, objectClass subclass equivilance is not
682 * wanted. This means that we should not lookup the schema for the
683 * comparison function */
684 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
685 const struct ldb_message *msg,
686 const char *name, const char *value)
689 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
695 for (i=0;i<el->num_values;i++) {
696 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
705 * This is intended for use by the "password hash" module since there
706 * password changes can be specified through one message element with the
707 * new password (to set) and another one with the old password (to unset).
709 * The first which sets a password (new value) can have flags
710 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
711 * for entries). The latter (old value) has always specified
712 * LDB_FLAG_MOD_DELETE.
714 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
715 * doesn't contain only one value (this is the Windows Server behaviour)
716 * otherwise LDB_SUCCESS.
718 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
720 const struct ldb_val **new_val,
721 const struct ldb_val **old_val)
732 for (i = 0; i < msg->num_elements; i++) {
733 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
734 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
735 *old_val = &msg->elements[i].values[0];
737 *new_val = &msg->elements[i].values[0];
745 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
747 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
748 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
753 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
755 struct ldb_message_element *el;
757 el = ldb_msg_find_element(msg, name);
762 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
768 add a string element to a message
770 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
771 const char *attr_name, const char *str)
773 const char *s = talloc_strdup(mem_ctx, str);
775 return ldb_oom(sam_ldb);
777 return ldb_msg_add_string(msg, attr_name, s);
781 add a dom_sid element to a message
783 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, struct dom_sid *sid)
787 enum ndr_err_code ndr_err;
789 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
791 (ndr_push_flags_fn_t)ndr_push_dom_sid);
792 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
793 return ldb_operr(sam_ldb);
795 return ldb_msg_add_value(msg, attr_name, &v, NULL);
800 add a delete element operation to a message
802 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
803 const char *attr_name)
805 /* we use an empty replace rather than a delete, as it allows for
806 dsdb_replace() to be used everywhere */
807 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
811 add an add attribute value to a message or enhance an existing attribute
812 which has the same name and the add flag set.
814 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
815 struct ldb_message *msg, const char *attr_name,
818 struct ldb_message_element *el;
819 struct ldb_val val, *vals;
825 v = talloc_strdup(mem_ctx, value);
827 return ldb_oom(sam_ldb);
830 val.data = (uint8_t *) v;
831 val.length = strlen(v);
833 if (val.length == 0) {
834 /* allow empty strings as non-existent attributes */
838 for (i = 0; i < msg->num_elements; i++) {
839 el = &msg->elements[i];
840 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
841 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
847 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
849 if (ret != LDB_SUCCESS) {
854 vals = talloc_realloc(msg, el->values, struct ldb_val,
857 return ldb_oom(sam_ldb);
860 el->values[el->num_values] = val;
867 add a delete attribute value to a message or enhance an existing attribute
868 which has the same name and the delete flag set.
870 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
871 struct ldb_message *msg, const char *attr_name,
874 struct ldb_message_element *el;
875 struct ldb_val val, *vals;
881 v = talloc_strdup(mem_ctx, value);
883 return ldb_oom(sam_ldb);
886 val.data = (uint8_t *) v;
887 val.length = strlen(v);
889 if (val.length == 0) {
890 /* allow empty strings as non-existent attributes */
894 for (i = 0; i < msg->num_elements; i++) {
895 el = &msg->elements[i];
896 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
897 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
903 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
905 if (ret != LDB_SUCCESS) {
910 vals = talloc_realloc(msg, el->values, struct ldb_val,
913 return ldb_oom(sam_ldb);
916 el->values[el->num_values] = val;
923 add a int element to a message
925 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
926 const char *attr_name, int v)
928 const char *s = talloc_asprintf(mem_ctx, "%d", v);
930 return ldb_oom(sam_ldb);
932 return ldb_msg_add_string(msg, attr_name, s);
936 * Add an unsigned int element to a message
938 * The issue here is that we have not yet first cast to int32_t explicitly,
939 * before we cast to an signed int to printf() into the %d or cast to a
940 * int64_t before we then cast to a long long to printf into a %lld.
942 * There are *no* unsigned integers in Active Directory LDAP, even the RID
943 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
944 * (See the schema, and the syntax definitions in schema_syntax.c).
947 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948 const char *attr_name, unsigned int v)
950 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
954 add a (signed) int64_t element to a message
956 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
957 const char *attr_name, int64_t v)
959 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
961 return ldb_oom(sam_ldb);
963 return ldb_msg_add_string(msg, attr_name, s);
967 * Add an unsigned int64_t (uint64_t) element to a message
969 * The issue here is that we have not yet first cast to int32_t explicitly,
970 * before we cast to an signed int to printf() into the %d or cast to a
971 * int64_t before we then cast to a long long to printf into a %lld.
973 * There are *no* unsigned integers in Active Directory LDAP, even the RID
974 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
975 * (See the schema, and the syntax definitions in schema_syntax.c).
978 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
979 const char *attr_name, uint64_t v)
981 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
985 add a samr_Password element to a message
987 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
988 const char *attr_name, const struct samr_Password *hash)
991 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
993 return ldb_oom(sam_ldb);
996 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1000 add a samr_Password array to a message
1002 int samdb_msg_add_hashes(struct ldb_context *ldb,
1003 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1004 const char *attr_name, struct samr_Password *hashes,
1009 val.data = talloc_array_size(mem_ctx, 16, count);
1010 val.length = count*16;
1012 return ldb_oom(ldb);
1014 for (i=0;i<count;i++) {
1015 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1017 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1021 add a acct_flags element to a message
1023 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1024 const char *attr_name, uint32_t v)
1026 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1030 add a logon_hours element to a message
1032 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1033 const char *attr_name, struct samr_LogonHours *hours)
1036 val.length = hours->units_per_week / 8;
1037 val.data = hours->bits;
1038 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1042 add a parameters element to a message
1044 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1045 const char *attr_name, struct lsa_BinaryString *parameters)
1048 val.length = parameters->length;
1049 val.data = (uint8_t *)parameters->array;
1050 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1054 sets a general value element to a message
1056 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1057 const char *attr_name, const struct ldb_val *val)
1059 struct ldb_message_element *el;
1061 el = ldb_msg_find_element(msg, attr_name);
1065 return ldb_msg_add_value(msg, attr_name, val, NULL);
1069 set a string element in a message
1071 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1072 const char *attr_name, const char *str)
1074 struct ldb_message_element *el;
1076 el = ldb_msg_find_element(msg, attr_name);
1080 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1084 * sets a signed integer in a message
1086 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1087 struct ldb_message *msg, const char *attr_name, int v)
1089 struct ldb_message_element *el;
1091 el = ldb_msg_find_element(msg, attr_name);
1095 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1099 * Sets an unsigned int element in a message
1101 * The issue here is that we have not yet first cast to int32_t explicitly,
1102 * before we cast to an signed int to printf() into the %d or cast to a
1103 * int64_t before we then cast to a long long to printf into a %lld.
1105 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1106 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1107 * (See the schema, and the syntax definitions in schema_syntax.c).
1110 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1111 struct ldb_message *msg, const char *attr_name,
1114 struct ldb_message_element *el;
1116 el = ldb_msg_find_element(msg, attr_name);
1120 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1124 * Handle ldb_request in transaction
1126 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1127 struct ldb_request *req)
1131 ret = ldb_transaction_start(sam_ldb);
1132 if (ret != LDB_SUCCESS) {
1136 ret = ldb_request(sam_ldb, req);
1137 if (ret == LDB_SUCCESS) {
1138 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1141 if (ret == LDB_SUCCESS) {
1142 return ldb_transaction_commit(sam_ldb);
1144 ldb_transaction_cancel(sam_ldb);
1150 return a default security descriptor
1152 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1154 struct security_descriptor *sd;
1156 sd = security_descriptor_initialise(mem_ctx);
1161 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1163 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1164 struct ldb_dn *aggregate_dn;
1169 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1170 if (!aggregate_dn) {
1173 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1176 return aggregate_dn;
1179 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1181 struct ldb_dn *new_dn;
1183 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1184 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1185 talloc_free(new_dn);
1191 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1193 struct ldb_dn *new_dn;
1195 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1196 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1197 talloc_free(new_dn);
1203 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1205 struct ldb_dn *new_dn;
1207 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1208 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1209 talloc_free(new_dn);
1216 work out the domain sid for the current open ldb
1218 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1220 TALLOC_CTX *tmp_ctx;
1221 const struct dom_sid *domain_sid;
1222 const char *attrs[] = {
1226 struct ldb_result *res;
1229 /* see if we have a cached copy */
1230 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1235 tmp_ctx = talloc_new(ldb);
1236 if (tmp_ctx == NULL) {
1240 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1242 if (ret != LDB_SUCCESS) {
1246 if (res->count != 1) {
1250 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1251 if (domain_sid == NULL) {
1255 /* cache the domain_sid in the ldb */
1256 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1260 talloc_steal(ldb, domain_sid);
1261 talloc_free(tmp_ctx);
1266 talloc_free(tmp_ctx);
1271 get domain sid from cache
1273 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1275 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1278 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1280 TALLOC_CTX *tmp_ctx;
1281 struct dom_sid *dom_sid_new;
1282 struct dom_sid *dom_sid_old;
1284 /* see if we have a cached copy */
1285 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1286 "cache.domain_sid"), struct dom_sid);
1288 tmp_ctx = talloc_new(ldb);
1289 if (tmp_ctx == NULL) {
1293 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1298 /* cache the domain_sid in the ldb */
1299 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1303 talloc_steal(ldb, dom_sid_new);
1304 talloc_free(tmp_ctx);
1305 talloc_free(dom_sid_old);
1310 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1311 talloc_free(tmp_ctx);
1315 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1317 TALLOC_CTX *tmp_ctx;
1318 struct ldb_dn *ntds_settings_dn_new;
1319 struct ldb_dn *ntds_settings_dn_old;
1321 /* see if we have a cached copy */
1322 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1323 "cache.ntds_settings_dn"), struct ldb_dn);
1325 tmp_ctx = talloc_new(ldb);
1326 if (tmp_ctx == NULL) {
1330 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1331 if (!ntds_settings_dn_new) {
1335 /* cache the domain_sid in the ldb */
1336 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1340 talloc_steal(ldb, ntds_settings_dn_new);
1341 talloc_free(tmp_ctx);
1342 talloc_free(ntds_settings_dn_old);
1347 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1348 talloc_free(tmp_ctx);
1352 /* Obtain the short name of the flexible single master operator
1353 * (FSMO), such as the PDC Emulator */
1354 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1357 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1358 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1359 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1360 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1362 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1363 /* Ensure this matches the format. This gives us a
1364 * bit more confidence that a 'cn' value will be a
1369 return (char *)val->data;
1375 work out the ntds settings dn for the current open ldb
1377 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1379 TALLOC_CTX *tmp_ctx;
1380 const char *root_attrs[] = { "dsServiceName", NULL };
1382 struct ldb_result *root_res;
1383 struct ldb_dn *settings_dn;
1385 /* see if we have a cached copy */
1386 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1391 tmp_ctx = talloc_new(ldb);
1392 if (tmp_ctx == NULL) {
1396 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1398 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1399 ldb_errstring(ldb)));
1403 if (root_res->count != 1) {
1407 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1409 /* cache the domain_sid in the ldb */
1410 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1414 talloc_steal(ldb, settings_dn);
1415 talloc_free(tmp_ctx);
1420 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1421 talloc_free(tmp_ctx);
1426 work out the ntds settings invocationId for the current open ldb
1428 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1430 TALLOC_CTX *tmp_ctx;
1431 const char *attrs[] = { "invocationId", NULL };
1433 struct ldb_result *res;
1434 struct GUID *invocation_id;
1436 /* see if we have a cached copy */
1437 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1438 if (invocation_id) {
1439 return invocation_id;
1442 tmp_ctx = talloc_new(ldb);
1443 if (tmp_ctx == NULL) {
1447 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1452 if (res->count != 1) {
1456 invocation_id = talloc(tmp_ctx, struct GUID);
1457 if (!invocation_id) {
1461 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1463 /* cache the domain_sid in the ldb */
1464 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1468 talloc_steal(ldb, invocation_id);
1469 talloc_free(tmp_ctx);
1471 return invocation_id;
1474 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1475 talloc_free(tmp_ctx);
1479 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1481 TALLOC_CTX *tmp_ctx;
1482 struct GUID *invocation_id_new;
1483 struct GUID *invocation_id_old;
1485 /* see if we have a cached copy */
1486 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1487 "cache.invocation_id");
1489 tmp_ctx = talloc_new(ldb);
1490 if (tmp_ctx == NULL) {
1494 invocation_id_new = talloc(tmp_ctx, struct GUID);
1495 if (!invocation_id_new) {
1499 *invocation_id_new = *invocation_id_in;
1501 /* cache the domain_sid in the ldb */
1502 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1506 talloc_steal(ldb, invocation_id_new);
1507 talloc_free(tmp_ctx);
1508 talloc_free(invocation_id_old);
1513 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1514 talloc_free(tmp_ctx);
1519 work out the ntds settings objectGUID for the current open ldb
1521 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1523 TALLOC_CTX *tmp_ctx;
1524 const char *attrs[] = { "objectGUID", NULL };
1526 struct ldb_result *res;
1527 struct GUID *ntds_guid;
1529 /* see if we have a cached copy */
1530 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1535 tmp_ctx = talloc_new(ldb);
1536 if (tmp_ctx == NULL) {
1540 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1545 if (res->count != 1) {
1549 ntds_guid = talloc(tmp_ctx, struct GUID);
1554 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1556 /* cache the domain_sid in the ldb */
1557 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1561 talloc_steal(ldb, ntds_guid);
1562 talloc_free(tmp_ctx);
1567 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1568 talloc_free(tmp_ctx);
1572 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1574 TALLOC_CTX *tmp_ctx;
1575 struct GUID *ntds_guid_new;
1576 struct GUID *ntds_guid_old;
1578 /* see if we have a cached copy */
1579 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1581 tmp_ctx = talloc_new(ldb);
1582 if (tmp_ctx == NULL) {
1586 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1587 if (!ntds_guid_new) {
1591 *ntds_guid_new = *ntds_guid_in;
1593 /* cache the domain_sid in the ldb */
1594 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1598 talloc_steal(ldb, ntds_guid_new);
1599 talloc_free(tmp_ctx);
1600 talloc_free(ntds_guid_old);
1605 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1606 talloc_free(tmp_ctx);
1611 work out the server dn for the current open ldb
1613 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1615 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1619 work out the server dn for the current open ldb
1621 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1623 struct ldb_dn *server_dn;
1624 struct ldb_dn *servers_dn;
1625 struct ldb_dn *server_site_dn;
1627 /* TODO: there must be a saner way to do this!! */
1628 server_dn = samdb_server_dn(ldb, mem_ctx);
1629 if (!server_dn) return NULL;
1631 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1632 talloc_free(server_dn);
1633 if (!servers_dn) return NULL;
1635 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1636 talloc_free(servers_dn);
1638 return server_site_dn;
1642 find the site name from a computers DN record
1644 int samdb_find_site_for_computer(struct ldb_context *ldb,
1645 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1646 const char **site_name)
1650 const struct ldb_val *rdn_val;
1654 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1655 if (ret != LDB_SUCCESS) {
1659 if (!ldb_dn_remove_child_components(dn, 2)) {
1661 return LDB_ERR_INVALID_DN_SYNTAX;
1663 rdn_val = ldb_dn_get_rdn_val(dn);
1664 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1667 return LDB_ERR_OPERATIONS_ERROR;
1673 find the NTDS GUID from a computers DN record
1675 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1676 struct GUID *ntds_guid)
1681 *ntds_guid = GUID_zero();
1683 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1684 if (ret != LDB_SUCCESS) {
1688 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1690 return LDB_ERR_OPERATIONS_ERROR;
1693 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1699 find a 'reference' DN that points at another object
1700 (eg. serverReference, rIDManagerReference etc)
1702 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1703 const char *attribute, struct ldb_dn **dn)
1705 const char *attrs[2];
1706 struct ldb_result *res;
1709 attrs[0] = attribute;
1712 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1713 if (ret != LDB_SUCCESS) {
1717 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1719 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1720 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1721 ldb_dn_get_linearized(base));
1723 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1724 ldb_dn_get_linearized(base));
1727 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1735 find our machine account via the serverReference attribute in the
1738 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1740 struct ldb_dn *server_dn;
1743 server_dn = samdb_server_dn(ldb, mem_ctx);
1744 if (server_dn == NULL) {
1745 return LDB_ERR_NO_SUCH_OBJECT;
1748 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1749 talloc_free(server_dn);
1755 find the RID Manager$ DN via the rIDManagerReference attribute in the
1758 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1760 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1761 "rIDManagerReference", dn);
1765 find the RID Set DN via the rIDSetReferences attribute in our
1768 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1770 struct ldb_dn *server_ref_dn;
1773 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1774 if (ret != LDB_SUCCESS) {
1777 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1778 talloc_free(server_ref_dn);
1782 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1784 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1791 return (const char *) val->data;
1795 * Finds the client site by using the client's IP address.
1796 * The "subnet_name" returns the name of the subnet if parameter != NULL
1798 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1799 const char *ip_address, char **subnet_name)
1801 const char *attrs[] = { "cn", "siteObject", NULL };
1802 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1803 struct ldb_result *res;
1804 const struct ldb_val *val;
1805 const char *site_name = NULL, *l_subnet_name = NULL;
1806 const char *allow_list[2] = { NULL, NULL };
1807 unsigned int i, count;
1811 * if we don't have a client ip e.g. ncalrpc
1812 * the server site is the client site
1814 if (ip_address == NULL) {
1815 return samdb_server_site_name(ldb, mem_ctx);
1818 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1819 if (sites_container_dn == NULL) {
1823 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1824 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1825 talloc_free(sites_container_dn);
1826 talloc_free(subnets_dn);
1830 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1832 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1834 } else if (ret != LDB_SUCCESS) {
1835 talloc_free(sites_container_dn);
1836 talloc_free(subnets_dn);
1842 for (i = 0; i < count; i++) {
1843 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1846 allow_list[0] = l_subnet_name;
1848 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1849 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1852 if (sites_dn == NULL) {
1853 /* No reference, maybe another subnet matches */
1857 /* "val" cannot be NULL here since "sites_dn" != NULL */
1858 val = ldb_dn_get_rdn_val(sites_dn);
1859 site_name = talloc_strdup(mem_ctx,
1860 (const char *) val->data);
1862 talloc_free(sites_dn);
1868 if (site_name == NULL) {
1869 /* This is the Windows Server fallback rule: when no subnet
1870 * exists and we have only one site available then use it (it
1871 * is for sure the same as our server site). If more sites do
1872 * exist then we don't know which one to use and set the site
1874 cnt = samdb_search_count(ldb, sites_container_dn,
1875 "(objectClass=site)");
1877 site_name = samdb_server_site_name(ldb, mem_ctx);
1879 site_name = talloc_strdup(mem_ctx, "");
1881 l_subnet_name = NULL;
1884 if (subnet_name != NULL) {
1885 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1888 talloc_free(sites_container_dn);
1889 talloc_free(subnets_dn);
1896 work out if we are the PDC for the domain of the current open ldb
1898 bool samdb_is_pdc(struct ldb_context *ldb)
1900 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1902 struct ldb_result *dom_res;
1903 TALLOC_CTX *tmp_ctx;
1907 tmp_ctx = talloc_new(ldb);
1908 if (tmp_ctx == NULL) {
1909 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1913 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1914 if (ret != LDB_SUCCESS) {
1915 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1916 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1917 ldb_errstring(ldb)));
1920 if (dom_res->count != 1) {
1924 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1926 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1932 talloc_free(tmp_ctx);
1937 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1938 talloc_free(tmp_ctx);
1943 work out if we are a Global Catalog server for the domain of the current open ldb
1945 bool samdb_is_gc(struct ldb_context *ldb)
1947 const char *attrs[] = { "options", NULL };
1949 struct ldb_result *res;
1950 TALLOC_CTX *tmp_ctx;
1952 tmp_ctx = talloc_new(ldb);
1953 if (tmp_ctx == NULL) {
1954 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1958 /* Query cn=ntds settings,.... */
1959 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1960 if (ret != LDB_SUCCESS) {
1961 talloc_free(tmp_ctx);
1964 if (res->count != 1) {
1965 talloc_free(tmp_ctx);
1969 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1970 talloc_free(tmp_ctx);
1972 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1973 if (options & 0x000000001) {
1979 /* Find a domain object in the parents of a particular DN. */
1980 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1981 struct ldb_dn **parent_dn, const char **errstring)
1983 TALLOC_CTX *local_ctx;
1984 struct ldb_dn *sdn = dn;
1985 struct ldb_result *res = NULL;
1986 int ret = LDB_SUCCESS;
1987 const char *attrs[] = { NULL };
1989 local_ctx = talloc_new(mem_ctx);
1990 if (local_ctx == NULL) return ldb_oom(ldb);
1992 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1993 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1994 "(|(objectClass=domain)(objectClass=builtinDomain))");
1995 if (ret == LDB_SUCCESS) {
1996 if (res->count == 1) {
2004 if (ret != LDB_SUCCESS) {
2005 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2006 ldb_dn_get_linearized(dn),
2007 ldb_dn_get_linearized(sdn),
2008 ldb_errstring(ldb));
2009 talloc_free(local_ctx);
2012 if (res->count != 1) {
2013 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2014 ldb_dn_get_linearized(dn));
2015 DEBUG(0,(__location__ ": %s\n", *errstring));
2016 talloc_free(local_ctx);
2017 return LDB_ERR_CONSTRAINT_VIOLATION;
2020 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2021 talloc_free(local_ctx);
2027 * Performs checks on a user password (plaintext UNIX format - attribute
2028 * "password"). The remaining parameters have to be extracted from the domain
2031 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2033 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2034 const uint32_t pwdProperties,
2035 const uint32_t minPwdLength)
2037 /* checks if the "minPwdLength" property is satisfied */
2038 if (minPwdLength > password->length)
2039 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2041 /* checks the password complexity */
2042 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2043 && (password->data != NULL)
2044 && (!check_password_quality((const char *) password->data)))
2045 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2047 return SAMR_VALIDATION_STATUS_SUCCESS;
2051 * Callback for "samdb_set_password" password change
2053 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2058 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2061 if (ares->error != LDB_SUCCESS) {
2063 req->context = talloc_steal(req,
2064 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2066 return ldb_request_done(req, ret);
2069 if (ares->type != LDB_REPLY_DONE) {
2071 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2074 req->context = talloc_steal(req,
2075 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2077 return ldb_request_done(req, LDB_SUCCESS);
2081 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2082 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2083 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2084 * user change or not. The "rejectReason" gives some more informations if the
2087 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2088 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2090 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2091 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2092 const DATA_BLOB *new_password,
2093 const struct samr_Password *lmNewHash,
2094 const struct samr_Password *ntNewHash,
2095 const struct samr_Password *lmOldHash,
2096 const struct samr_Password *ntOldHash,
2097 enum samPwdChangeReason *reject_reason,
2098 struct samr_DomInfo1 **_dominfo)
2100 struct ldb_message *msg;
2101 struct ldb_message_element *el;
2102 struct ldb_request *req;
2103 struct dsdb_control_password_change_status *pwd_stat = NULL;
2105 NTSTATUS status = NT_STATUS_OK;
2107 #define CHECK_RET(x) \
2108 if (x != LDB_SUCCESS) { \
2110 return NT_STATUS_NO_MEMORY; \
2113 msg = ldb_msg_new(mem_ctx);
2115 return NT_STATUS_NO_MEMORY;
2118 if ((new_password != NULL)
2119 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2120 /* we have the password as plaintext UTF16 */
2121 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2122 new_password, NULL));
2123 el = ldb_msg_find_element(msg, "clearTextPassword");
2124 el->flags = LDB_FLAG_MOD_REPLACE;
2125 } else if ((new_password == NULL)
2126 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2127 /* we have a password as LM and/or NT hash */
2128 if (lmNewHash != NULL) {
2129 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2130 "dBCSPwd", lmNewHash));
2131 el = ldb_msg_find_element(msg, "dBCSPwd");
2132 el->flags = LDB_FLAG_MOD_REPLACE;
2134 if (ntNewHash != NULL) {
2135 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2136 "unicodePwd", ntNewHash));
2137 el = ldb_msg_find_element(msg, "unicodePwd");
2138 el->flags = LDB_FLAG_MOD_REPLACE;
2141 /* the password wasn't specified correctly */
2143 return NT_STATUS_INVALID_PARAMETER;
2146 /* build modify request */
2147 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2148 samdb_set_password_callback, NULL);
2149 if (ret != LDB_SUCCESS) {
2151 return NT_STATUS_NO_MEMORY;
2154 /* A password change operation */
2155 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2156 struct dsdb_control_password_change *change;
2158 change = talloc(req, struct dsdb_control_password_change);
2159 if (change == NULL) {
2162 return NT_STATUS_NO_MEMORY;
2165 change->old_nt_pwd_hash = ntOldHash;
2166 change->old_lm_pwd_hash = lmOldHash;
2168 ret = ldb_request_add_control(req,
2169 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2171 if (ret != LDB_SUCCESS) {
2174 return NT_STATUS_NO_MEMORY;
2177 ret = ldb_request_add_control(req,
2178 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2180 if (ret != LDB_SUCCESS) {
2183 return NT_STATUS_NO_MEMORY;
2185 ret = ldb_request_add_control(req,
2186 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2188 if (ret != LDB_SUCCESS) {
2191 return NT_STATUS_NO_MEMORY;
2194 ret = dsdb_autotransaction_request(ldb, req);
2196 if (req->context != NULL) {
2197 pwd_stat = talloc_steal(mem_ctx,
2198 ((struct ldb_control *)req->context)->data);
2204 /* Sets the domain info (if requested) */
2205 if (_dominfo != NULL) {
2206 struct samr_DomInfo1 *dominfo;
2208 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2209 if (dominfo == NULL) {
2210 return NT_STATUS_NO_MEMORY;
2213 if (pwd_stat != NULL) {
2214 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2215 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2216 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2217 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2218 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2221 *_dominfo = dominfo;
2224 if (reject_reason != NULL) {
2225 if (pwd_stat != NULL) {
2226 *reject_reason = pwd_stat->reject_reason;
2228 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2232 if (pwd_stat != NULL) {
2233 talloc_free(pwd_stat);
2236 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2237 const char *errmsg = ldb_errstring(ldb);
2238 char *endptr = NULL;
2239 WERROR werr = WERR_GENERAL_FAILURE;
2240 status = NT_STATUS_UNSUCCESSFUL;
2241 if (errmsg != NULL) {
2242 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2244 if (endptr != errmsg) {
2245 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2246 status = NT_STATUS_WRONG_PASSWORD;
2248 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2249 status = NT_STATUS_PASSWORD_RESTRICTION;
2252 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2253 /* don't let the caller know if an account doesn't exist */
2254 status = NT_STATUS_WRONG_PASSWORD;
2255 } else if (ret != LDB_SUCCESS) {
2256 status = NT_STATUS_UNSUCCESSFUL;
2263 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2264 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2265 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2266 * user change or not. The "rejectReason" gives some more informations if the
2269 * This wrapper function for "samdb_set_password" takes a SID as input rather
2272 * This call encapsulates a new LDB transaction for changing the password;
2273 * therefore the user hasn't to start a new one.
2275 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2276 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2277 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2278 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2280 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2281 const struct dom_sid *user_sid,
2282 const DATA_BLOB *new_password,
2283 const struct samr_Password *lmNewHash,
2284 const struct samr_Password *ntNewHash,
2285 const struct samr_Password *lmOldHash,
2286 const struct samr_Password *ntOldHash,
2287 enum samPwdChangeReason *reject_reason,
2288 struct samr_DomInfo1 **_dominfo)
2291 struct ldb_dn *user_dn;
2294 ret = ldb_transaction_start(ldb);
2295 if (ret != LDB_SUCCESS) {
2296 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2297 return NT_STATUS_TRANSACTION_ABORTED;
2300 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2301 "(&(objectSid=%s)(objectClass=user))",
2302 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2304 ldb_transaction_cancel(ldb);
2305 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2306 dom_sid_string(mem_ctx, user_sid)));
2307 return NT_STATUS_NO_SUCH_USER;
2310 nt_status = samdb_set_password(ldb, mem_ctx,
2313 lmNewHash, ntNewHash,
2314 lmOldHash, ntOldHash,
2315 reject_reason, _dominfo);
2316 if (!NT_STATUS_IS_OK(nt_status)) {
2317 ldb_transaction_cancel(ldb);
2318 talloc_free(user_dn);
2322 ret = ldb_transaction_commit(ldb);
2323 if (ret != LDB_SUCCESS) {
2324 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2325 ldb_dn_get_linearized(user_dn),
2326 ldb_errstring(ldb)));
2327 talloc_free(user_dn);
2328 return NT_STATUS_TRANSACTION_ABORTED;
2331 talloc_free(user_dn);
2332 return NT_STATUS_OK;
2336 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2337 struct dom_sid *sid, struct ldb_dn **ret_dn)
2339 struct ldb_message *msg;
2340 struct ldb_dn *basedn;
2344 sidstr = dom_sid_string(mem_ctx, sid);
2345 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2347 /* We might have to create a ForeignSecurityPrincipal, even if this user
2348 * is in our own domain */
2350 msg = ldb_msg_new(sidstr);
2352 talloc_free(sidstr);
2353 return NT_STATUS_NO_MEMORY;
2356 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2357 ldb_get_default_basedn(sam_ctx),
2358 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2360 if (ret != LDB_SUCCESS) {
2361 DEBUG(0, ("Failed to find DN for "
2362 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2363 talloc_free(sidstr);
2364 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2367 /* add core elements to the ldb_message for the alias */
2369 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2370 talloc_free(sidstr);
2371 return NT_STATUS_NO_MEMORY;
2374 ret = samdb_msg_add_string(sam_ctx, msg, msg,
2375 "objectClass", "foreignSecurityPrincipal");
2376 if (ret != LDB_SUCCESS) {
2377 talloc_free(sidstr);
2378 return NT_STATUS_NO_MEMORY;
2381 /* create the alias */
2382 ret = ldb_add(sam_ctx, msg);
2383 if (ret != LDB_SUCCESS) {
2384 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2386 ldb_dn_get_linearized(msg->dn),
2387 ldb_errstring(sam_ctx)));
2388 talloc_free(sidstr);
2389 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2392 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2393 talloc_free(sidstr);
2395 return NT_STATUS_OK;
2400 Find the DN of a domain, assuming it to be a dotted.dns name
2403 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2406 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2407 const char *binary_encoded;
2408 const char **split_realm;
2415 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2417 talloc_free(tmp_ctx);
2420 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2421 for (i=0; split_realm[i]; i++) {
2422 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2423 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2424 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2425 binary_encoded, ldb_dn_get_linearized(dn)));
2426 talloc_free(tmp_ctx);
2430 if (!ldb_dn_validate(dn)) {
2431 DEBUG(2, ("Failed to validated DN %s\n",
2432 ldb_dn_get_linearized(dn)));
2433 talloc_free(tmp_ctx);
2436 talloc_free(tmp_ctx);
2441 Find the DN of a domain, be it the netbios or DNS name
2443 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2444 const char *domain_name)
2446 const char * const domain_ref_attrs[] = {
2449 const char * const domain_ref2_attrs[] = {
2452 struct ldb_result *res_domain_ref;
2453 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2454 /* find the domain's DN */
2455 int ret_domain = ldb_search(ldb, mem_ctx,
2457 samdb_partitions_dn(ldb, mem_ctx),
2460 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2462 if (ret_domain != LDB_SUCCESS) {
2466 if (res_domain_ref->count == 0) {
2467 ret_domain = ldb_search(ldb, mem_ctx,
2469 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2472 "(objectclass=domain)");
2473 if (ret_domain != LDB_SUCCESS) {
2477 if (res_domain_ref->count == 1) {
2478 return res_domain_ref->msgs[0]->dn;
2483 if (res_domain_ref->count > 1) {
2484 DEBUG(0,("Found %d records matching domain [%s]\n",
2485 ret_domain, domain_name));
2489 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2495 use a GUID to find a DN
2497 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2498 TALLOC_CTX *mem_ctx,
2499 const struct GUID *guid, struct ldb_dn **dn)
2502 struct ldb_result *res;
2503 const char *attrs[] = { NULL };
2504 char *guid_str = GUID_string(mem_ctx, guid);
2507 return ldb_operr(ldb);
2510 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2511 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2512 DSDB_SEARCH_SHOW_EXTENDED_DN |
2513 DSDB_SEARCH_ONE_ONLY,
2514 "objectGUID=%s", guid_str);
2515 talloc_free(guid_str);
2516 if (ret != LDB_SUCCESS) {
2520 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2527 use a DN to find a GUID with a given attribute name
2529 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2530 struct ldb_dn *dn, const char *attribute,
2534 struct ldb_result *res;
2535 const char *attrs[2];
2536 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2538 attrs[0] = attribute;
2541 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2542 DSDB_SEARCH_SHOW_DELETED |
2543 DSDB_SEARCH_SHOW_RECYCLED);
2544 if (ret != LDB_SUCCESS) {
2545 talloc_free(tmp_ctx);
2548 if (res->count < 1) {
2549 talloc_free(tmp_ctx);
2550 return LDB_ERR_NO_SUCH_OBJECT;
2552 *guid = samdb_result_guid(res->msgs[0], attribute);
2553 talloc_free(tmp_ctx);
2558 use a DN to find a GUID
2560 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2561 struct ldb_dn *dn, struct GUID *guid)
2563 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2569 adds the given GUID to the given ldb_message. This value is added
2570 for the given attr_name (may be either "objectGUID" or "parentGUID").
2572 int dsdb_msg_add_guid(struct ldb_message *msg,
2574 const char *attr_name)
2579 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2581 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2582 if (!NT_STATUS_IS_OK(status)) {
2583 ret = LDB_ERR_OPERATIONS_ERROR;
2587 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2588 if (ret != LDB_SUCCESS) {
2589 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2597 talloc_free(tmp_ctx);
2604 use a DN to find a SID
2606 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2607 struct ldb_dn *dn, struct dom_sid *sid)
2610 struct ldb_result *res;
2611 const char *attrs[] = { "objectSid", NULL };
2612 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2617 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2618 DSDB_SEARCH_SHOW_DELETED |
2619 DSDB_SEARCH_SHOW_RECYCLED);
2620 if (ret != LDB_SUCCESS) {
2621 talloc_free(tmp_ctx);
2624 if (res->count < 1) {
2625 talloc_free(tmp_ctx);
2626 return LDB_ERR_NO_SUCH_OBJECT;
2628 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2630 talloc_free(tmp_ctx);
2631 return LDB_ERR_NO_SUCH_OBJECT;
2634 talloc_free(tmp_ctx);
2639 use a SID to find a DN
2641 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2642 TALLOC_CTX *mem_ctx,
2643 struct dom_sid *sid, struct ldb_dn **dn)
2646 struct ldb_result *res;
2647 const char *attrs[] = { NULL };
2648 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2651 return ldb_operr(ldb);
2654 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2655 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2656 DSDB_SEARCH_SHOW_EXTENDED_DN |
2657 DSDB_SEARCH_ONE_ONLY,
2658 "objectSid=%s", sid_str);
2659 talloc_free(sid_str);
2660 if (ret != LDB_SUCCESS) {
2664 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2671 load a repsFromTo blob list for a given partition GUID
2672 attr must be "repsFrom" or "repsTo"
2674 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2675 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2677 const char *attrs[] = { attr, NULL };
2678 struct ldb_result *res = NULL;
2679 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2681 struct ldb_message_element *el;
2686 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2688 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2689 talloc_free(tmp_ctx);
2690 return WERR_DS_DRA_INTERNAL_ERROR;
2693 el = ldb_msg_find_element(res->msgs[0], attr);
2695 /* it's OK to be empty */
2696 talloc_free(tmp_ctx);
2700 *count = el->num_values;
2701 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2703 talloc_free(tmp_ctx);
2704 return WERR_DS_DRA_INTERNAL_ERROR;
2707 for (i=0; i<(*count); i++) {
2708 enum ndr_err_code ndr_err;
2709 ndr_err = ndr_pull_struct_blob(&el->values[i],
2712 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2713 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2714 talloc_free(tmp_ctx);
2715 return WERR_DS_DRA_INTERNAL_ERROR;
2719 talloc_free(tmp_ctx);
2725 save the repsFromTo blob list for a given partition GUID
2726 attr must be "repsFrom" or "repsTo"
2728 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2729 const char *attr, struct repsFromToBlob *r, uint32_t count)
2731 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2732 struct ldb_message *msg;
2733 struct ldb_message_element *el;
2736 msg = ldb_msg_new(tmp_ctx);
2738 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2742 el->values = talloc_array(msg, struct ldb_val, count);
2747 for (i=0; i<count; i++) {
2749 enum ndr_err_code ndr_err;
2751 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2753 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2754 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2762 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2763 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2767 talloc_free(tmp_ctx);
2772 talloc_free(tmp_ctx);
2773 return WERR_DS_DRA_INTERNAL_ERROR;
2778 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2779 object for a partition
2781 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2782 uint64_t *uSN, uint64_t *urgent_uSN)
2784 struct ldb_request *req;
2786 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2787 struct dsdb_control_current_partition *p_ctrl;
2788 struct ldb_result *res;
2790 res = talloc_zero(tmp_ctx, struct ldb_result);
2792 talloc_free(tmp_ctx);
2793 return ldb_oom(ldb);
2796 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2797 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2801 res, ldb_search_default_callback,
2803 if (ret != LDB_SUCCESS) {
2804 talloc_free(tmp_ctx);
2808 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2809 if (p_ctrl == NULL) {
2810 talloc_free(tmp_ctx);
2811 return ldb_oom(ldb);
2813 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2816 ret = ldb_request_add_control(req,
2817 DSDB_CONTROL_CURRENT_PARTITION_OID,
2819 if (ret != LDB_SUCCESS) {
2820 talloc_free(tmp_ctx);
2824 /* Run the new request */
2825 ret = ldb_request(ldb, req);
2827 if (ret == LDB_SUCCESS) {
2828 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2831 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
2832 /* it hasn't been created yet, which means
2833 an implicit value of zero */
2835 talloc_free(tmp_ctx);
2839 if (ret != LDB_SUCCESS) {
2840 talloc_free(tmp_ctx);
2844 if (res->count < 1) {
2850 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2852 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2856 talloc_free(tmp_ctx);
2861 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2862 const struct drsuapi_DsReplicaCursor2 *c2)
2864 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2867 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2868 const struct drsuapi_DsReplicaCursor *c2)
2870 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2875 see if a computer identified by its invocationId is a RODC
2877 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2879 /* 1) find the DN for this servers NTDSDSA object
2880 2) search for the msDS-isRODC attribute
2881 3) if not present then not a RODC
2882 4) if present and TRUE then is a RODC
2884 struct ldb_dn *config_dn;
2885 const char *attrs[] = { "msDS-isRODC", NULL };
2887 struct ldb_result *res;
2888 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2890 config_dn = ldb_get_config_basedn(sam_ctx);
2892 talloc_free(tmp_ctx);
2893 return ldb_operr(sam_ctx);
2896 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2897 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2899 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2901 talloc_free(tmp_ctx);
2905 if (ret != LDB_SUCCESS) {
2906 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2907 GUID_string(tmp_ctx, objectGUID)));
2909 talloc_free(tmp_ctx);
2913 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2914 *is_rodc = (ret == 1);
2916 talloc_free(tmp_ctx);
2922 see if we are a RODC
2924 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2926 const struct GUID *objectGUID;
2930 /* see if we have a cached copy */
2931 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2937 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2939 return ldb_operr(sam_ctx);
2942 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2943 if (ret != LDB_SUCCESS) {
2947 cached = talloc(sam_ctx, bool);
2948 if (cached == NULL) {
2949 return ldb_oom(sam_ctx);
2953 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2954 if (ret != LDB_SUCCESS) {
2955 talloc_free(cached);
2956 return ldb_operr(sam_ctx);
2962 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2964 TALLOC_CTX *tmp_ctx;
2967 tmp_ctx = talloc_new(ldb);
2968 if (tmp_ctx == NULL) {
2972 cached = talloc(tmp_ctx, bool);
2978 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2982 talloc_steal(ldb, cached);
2983 talloc_free(tmp_ctx);
2987 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2988 talloc_free(tmp_ctx);
2994 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2996 flags are DS_NTDS_OPTION_*
2998 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3000 TALLOC_CTX *tmp_ctx;
3001 const char *attrs[] = { "options", NULL };
3003 struct ldb_result *res;
3005 tmp_ctx = talloc_new(ldb);
3006 if (tmp_ctx == NULL) {
3010 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3011 if (ret != LDB_SUCCESS) {
3015 if (res->count != 1) {
3019 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3021 talloc_free(tmp_ctx);
3026 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3027 talloc_free(tmp_ctx);
3028 return LDB_ERR_NO_SUCH_OBJECT;
3031 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3033 const char *attrs[] = { "objectCategory", NULL };
3035 struct ldb_result *res;
3037 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3038 if (ret != LDB_SUCCESS) {
3042 if (res->count != 1) {
3046 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3049 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3054 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3055 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3057 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3059 char **tokens, *ret;
3062 tokens = str_list_make(mem_ctx, cn, " -_");
3066 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3067 tokens[0][0] = tolower(tokens[0][0]);
3068 for (i = 1; i < str_list_length((const char **)tokens); i++)
3069 tokens[i][0] = toupper(tokens[i][0]);
3071 ret = talloc_strdup(mem_ctx, tokens[0]);
3072 for (i = 1; i < str_list_length((const char **)tokens); i++)
3073 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3075 talloc_free(tokens);
3081 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3083 int dsdb_functional_level(struct ldb_context *ldb)
3085 int *domainFunctionality =
3086 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3087 if (!domainFunctionality) {
3088 /* this is expected during initial provision */
3089 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3090 return DS_DOMAIN_FUNCTION_2000;
3092 return *domainFunctionality;
3096 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3098 int dsdb_forest_functional_level(struct ldb_context *ldb)
3100 int *forestFunctionality =
3101 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3102 if (!forestFunctionality) {
3103 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3104 return DS_DOMAIN_FUNCTION_2000;
3106 return *forestFunctionality;
3110 set a GUID in an extended DN structure
3112 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3118 status = GUID_to_ndr_blob(guid, dn, &v);
3119 if (!NT_STATUS_IS_OK(status)) {
3120 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3123 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3129 return a GUID from a extended DN structure
3131 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3133 const struct ldb_val *v;
3135 v = ldb_dn_get_extended_component(dn, component_name);
3137 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3140 return GUID_from_ndr_blob(v, guid);
3144 return a uint64_t from a extended DN structure
3146 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3148 const struct ldb_val *v;
3151 v = ldb_dn_get_extended_component(dn, component_name);
3153 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3155 s = talloc_strndup(dn, (const char *)v->data, v->length);
3156 NT_STATUS_HAVE_NO_MEMORY(s);
3158 *val = strtoull(s, NULL, 0);
3161 return NT_STATUS_OK;
3165 return a NTTIME from a extended DN structure
3167 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3169 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3173 return a uint32_t from a extended DN structure
3175 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3177 const struct ldb_val *v;
3180 v = ldb_dn_get_extended_component(dn, component_name);
3182 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3185 s = talloc_strndup(dn, (const char *)v->data, v->length);
3186 NT_STATUS_HAVE_NO_MEMORY(s);
3188 *val = strtoul(s, NULL, 0);
3191 return NT_STATUS_OK;
3195 return a dom_sid from a extended DN structure
3197 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3199 const struct ldb_val *sid_blob;
3200 struct TALLOC_CTX *tmp_ctx;
3201 enum ndr_err_code ndr_err;
3203 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3205 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3208 tmp_ctx = talloc_new(NULL);
3210 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3211 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3213 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3214 talloc_free(tmp_ctx);
3218 talloc_free(tmp_ctx);
3219 return NT_STATUS_OK;
3224 return RMD_FLAGS directly from a ldb_dn
3225 returns 0 if not found
3227 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3229 const struct ldb_val *v;
3231 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3232 if (!v || v->length > sizeof(buf)-1) return 0;
3233 strncpy(buf, (const char *)v->data, v->length);
3235 return strtoul(buf, NULL, 10);
3239 return RMD_FLAGS directly from a ldb_val for a DN
3240 returns 0 if RMD_FLAGS is not found
3242 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3248 if (val->length < 13) {
3251 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3255 flags = strtoul(p+11, &end, 10);
3256 if (!end || *end != '>') {
3257 /* it must end in a > */
3264 return true if a ldb_val containing a DN in storage form is deleted
3266 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3268 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3272 return true if a ldb_val containing a DN in storage form is
3273 in the upgraded w2k3 linked attribute format
3275 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3277 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3281 return a DN for a wellknown GUID
3283 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3284 struct ldb_dn *nc_root, const char *wk_guid,
3285 struct ldb_dn **wkguid_dn)
3287 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3288 const char *attrs[] = { NULL };
3291 struct ldb_result *res;
3293 /* construct the magic WKGUID DN */
3294 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3295 wk_guid, ldb_dn_get_linearized(nc_root));
3297 talloc_free(tmp_ctx);
3298 return ldb_operr(samdb);
3301 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3302 DSDB_SEARCH_SHOW_DELETED |
3303 DSDB_SEARCH_SHOW_RECYCLED);
3304 if (ret != LDB_SUCCESS) {
3305 talloc_free(tmp_ctx);
3309 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3310 talloc_free(tmp_ctx);
3315 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3317 return ldb_dn_compare(*dn1, *dn2);
3321 find a NC root given a DN within the NC
3323 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3324 struct ldb_dn **nc_root)
3326 const char *root_attrs[] = { "namingContexts", NULL };
3327 TALLOC_CTX *tmp_ctx;
3329 struct ldb_message_element *el;
3330 struct ldb_result *root_res;
3332 struct ldb_dn **nc_dns;
3334 tmp_ctx = talloc_new(samdb);
3335 if (tmp_ctx == NULL) {
3336 return ldb_oom(samdb);
3339 ret = ldb_search(samdb, tmp_ctx, &root_res,
3340 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3341 if (ret != LDB_SUCCESS) {
3342 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3343 talloc_free(tmp_ctx);
3347 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3349 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3350 ldb_errstring(samdb)));
3351 talloc_free(tmp_ctx);
3352 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3355 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3357 talloc_free(tmp_ctx);
3358 return ldb_oom(samdb);
3361 for (i=0; i<el->num_values; i++) {
3362 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3363 if (nc_dns[i] == NULL) {
3364 talloc_free(tmp_ctx);
3365 return ldb_operr(samdb);
3369 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3371 for (i=0; i<el->num_values; i++) {
3372 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3373 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3374 talloc_free(tmp_ctx);
3379 talloc_free(tmp_ctx);
3380 return LDB_ERR_NO_SUCH_OBJECT;
3385 find the deleted objects DN for any object, by looking for the NC
3386 root, then looking up the wellknown GUID
3388 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3389 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3390 struct ldb_dn **do_dn)
3392 struct ldb_dn *nc_root;
3395 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3396 if (ret != LDB_SUCCESS) {
3400 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3401 talloc_free(nc_root);
3406 return the tombstoneLifetime, in days
3408 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3411 dn = ldb_get_config_basedn(ldb);
3413 return LDB_ERR_NO_SUCH_OBJECT;
3415 dn = ldb_dn_copy(ldb, dn);
3417 return ldb_operr(ldb);
3419 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3420 be a wellknown GUID for this */
3421 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3423 return ldb_operr(ldb);
3426 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3432 compare a ldb_val to a string case insensitively
3434 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3436 size_t len = strlen(s);
3438 if (len > v->length) return 1;
3439 ret = strncasecmp(s, (const char *)v->data, v->length);
3440 if (ret != 0) return ret;
3441 if (v->length > len && v->data[len] != 0) {
3449 load the UDV for a partition in v2 format
3450 The list is returned sorted, and with our local cursor added
3452 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3453 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3455 static const char *attrs[] = { "replUpToDateVector", NULL };
3456 struct ldb_result *r;
3457 const struct ldb_val *ouv_value;
3460 uint64_t highest_usn;
3461 const struct GUID *our_invocation_id;
3462 struct timeval now = timeval_current();
3464 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3465 if (ret != LDB_SUCCESS) {
3469 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3471 enum ndr_err_code ndr_err;
3472 struct replUpToDateVectorBlob ouv;
3474 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3475 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3476 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3478 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3480 if (ouv.version != 2) {
3481 /* we always store as version 2, and
3482 * replUpToDateVector is not replicated
3484 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3487 *count = ouv.ctr.ctr2.count;
3488 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3496 our_invocation_id = samdb_ntds_invocation_id(samdb);
3497 if (!our_invocation_id) {
3498 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3499 talloc_free(*cursors);
3500 return ldb_operr(samdb);
3503 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3504 if (ret != LDB_SUCCESS) {
3505 /* nothing to add - this can happen after a vampire */
3506 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3510 for (i=0; i<*count; i++) {
3511 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3512 (*cursors)[i].highest_usn = highest_usn;
3513 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3514 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3519 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3521 return ldb_oom(samdb);
3524 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3525 (*cursors)[*count].highest_usn = highest_usn;
3526 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3529 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3535 load the UDV for a partition in version 1 format
3536 The list is returned sorted, and with our local cursor added
3538 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3539 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3541 struct drsuapi_DsReplicaCursor2 *v2;
3545 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3546 if (ret != LDB_SUCCESS) {
3556 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3557 if (*cursors == NULL) {
3559 return ldb_oom(samdb);
3562 for (i=0; i<*count; i++) {
3563 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3564 (*cursors)[i].highest_usn = v2[i].highest_usn;
3571 add a set of controls to a ldb_request structure based on a set of
3572 flags. See util.h for a list of available flags
3574 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3577 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3578 struct ldb_search_options_control *options;
3579 /* Using the phantom root control allows us to search all partitions */
3580 options = talloc(req, struct ldb_search_options_control);
3581 if (options == NULL) {
3582 return LDB_ERR_OPERATIONS_ERROR;
3584 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3586 ret = ldb_request_add_control(req,
3587 LDB_CONTROL_SEARCH_OPTIONS_OID,
3589 if (ret != LDB_SUCCESS) {
3594 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3595 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3596 if (ret != LDB_SUCCESS) {
3601 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3602 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3603 if (ret != LDB_SUCCESS) {
3608 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3609 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3610 if (ret != LDB_SUCCESS) {
3615 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3616 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3617 if (!extended_ctrl) {
3618 return LDB_ERR_OPERATIONS_ERROR;
3620 extended_ctrl->type = 1;
3622 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3623 if (ret != LDB_SUCCESS) {
3628 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3629 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3630 if (ret != LDB_SUCCESS) {
3635 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3636 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3637 if (ret != LDB_SUCCESS) {
3642 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3643 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3644 if (ret != LDB_SUCCESS) {
3649 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3650 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3651 if (ret != LDB_SUCCESS) {
3656 if (dsdb_flags & DSDB_TREE_DELETE) {
3657 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3658 if (ret != LDB_SUCCESS) {
3667 an add with a set of controls
3669 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3670 uint32_t dsdb_flags)
3672 struct ldb_request *req;
3675 ret = ldb_build_add_req(&req, ldb, ldb,
3679 ldb_op_default_callback,
3682 if (ret != LDB_SUCCESS) return ret;
3684 ret = dsdb_request_add_controls(req, dsdb_flags);
3685 if (ret != LDB_SUCCESS) {
3690 ret = dsdb_autotransaction_request(ldb, req);
3697 a modify with a set of controls
3699 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3700 uint32_t dsdb_flags)
3702 struct ldb_request *req;
3705 ret = ldb_build_mod_req(&req, ldb, ldb,
3709 ldb_op_default_callback,
3712 if (ret != LDB_SUCCESS) return ret;
3714 ret = dsdb_request_add_controls(req, dsdb_flags);
3715 if (ret != LDB_SUCCESS) {
3720 ret = dsdb_autotransaction_request(ldb, req);
3727 like dsdb_modify() but set all the element flags to
3728 LDB_FLAG_MOD_REPLACE
3730 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3734 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3735 for (i=0;i<msg->num_elements;i++) {
3736 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3739 return dsdb_modify(ldb, msg, dsdb_flags);
3744 search for attrs on one DN, allowing for dsdb_flags controls
3746 int dsdb_search_dn(struct ldb_context *ldb,
3747 TALLOC_CTX *mem_ctx,
3748 struct ldb_result **_res,
3749 struct ldb_dn *basedn,
3750 const char * const *attrs,
3751 uint32_t dsdb_flags)
3754 struct ldb_request *req;
3755 struct ldb_result *res;
3757 res = talloc_zero(mem_ctx, struct ldb_result);
3759 return ldb_oom(ldb);
3762 ret = ldb_build_search_req(&req, ldb, res,
3769 ldb_search_default_callback,
3771 if (ret != LDB_SUCCESS) {
3776 ret = dsdb_request_add_controls(req, dsdb_flags);
3777 if (ret != LDB_SUCCESS) {
3782 ret = ldb_request(ldb, req);
3783 if (ret == LDB_SUCCESS) {
3784 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3788 if (ret != LDB_SUCCESS) {
3798 search for attrs on one DN, by the GUID of the DN, allowing for
3801 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3802 TALLOC_CTX *mem_ctx,
3803 struct ldb_result **_res,
3804 const struct GUID *guid,
3805 const char * const *attrs,
3806 uint32_t dsdb_flags)
3808 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3812 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3813 if (!ldb_dn_validate(dn)) {
3814 talloc_free(tmp_ctx);
3815 return LDB_ERR_INVALID_DN_SYNTAX;
3818 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3819 talloc_free(tmp_ctx);
3824 general search with dsdb_flags for controls
3826 int dsdb_search(struct ldb_context *ldb,
3827 TALLOC_CTX *mem_ctx,
3828 struct ldb_result **_res,
3829 struct ldb_dn *basedn,
3830 enum ldb_scope scope,
3831 const char * const *attrs,
3832 uint32_t dsdb_flags,
3833 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3836 struct ldb_request *req;
3837 struct ldb_result *res;
3839 char *expression = NULL;
3840 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3842 res = talloc_zero(tmp_ctx, struct ldb_result);
3844 talloc_free(tmp_ctx);
3845 return ldb_oom(ldb);
3849 va_start(ap, exp_fmt);
3850 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3854 talloc_free(tmp_ctx);
3855 return ldb_oom(ldb);
3859 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3866 ldb_search_default_callback,
3868 if (ret != LDB_SUCCESS) {
3869 talloc_free(tmp_ctx);
3873 ret = dsdb_request_add_controls(req, dsdb_flags);
3874 if (ret != LDB_SUCCESS) {
3875 talloc_free(tmp_ctx);
3876 ldb_reset_err_string(ldb);
3880 ret = ldb_request(ldb, req);
3881 if (ret == LDB_SUCCESS) {
3882 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3885 if (ret != LDB_SUCCESS) {
3886 talloc_free(tmp_ctx);
3890 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3891 if (res->count == 0) {
3892 talloc_free(tmp_ctx);
3893 ldb_reset_err_string(ldb);
3894 return LDB_ERR_NO_SUCH_OBJECT;
3896 if (res->count != 1) {
3897 talloc_free(tmp_ctx);
3898 ldb_reset_err_string(ldb);
3899 return LDB_ERR_CONSTRAINT_VIOLATION;
3903 *_res = talloc_steal(mem_ctx, res);
3904 talloc_free(tmp_ctx);
3911 general search with dsdb_flags for controls
3912 returns exactly 1 record or an error
3914 int dsdb_search_one(struct ldb_context *ldb,
3915 TALLOC_CTX *mem_ctx,
3916 struct ldb_message **msg,
3917 struct ldb_dn *basedn,
3918 enum ldb_scope scope,
3919 const char * const *attrs,
3920 uint32_t dsdb_flags,
3921 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3924 struct ldb_result *res;
3926 char *expression = NULL;
3927 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3929 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3931 res = talloc_zero(tmp_ctx, struct ldb_result);
3933 talloc_free(tmp_ctx);
3934 return ldb_oom(ldb);
3938 va_start(ap, exp_fmt);
3939 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3943 talloc_free(tmp_ctx);
3944 return ldb_oom(ldb);
3946 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3947 dsdb_flags, "%s", expression);
3949 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3953 if (ret != LDB_SUCCESS) {
3954 talloc_free(tmp_ctx);
3958 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3959 talloc_free(tmp_ctx);
3964 /* returns back the forest DNS name */
3965 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3967 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3968 ldb_get_root_basedn(ldb));
3971 if (forest_name == NULL) {
3975 p = strchr(forest_name, '/');
3984 validate that an DSA GUID belongs to the specified user sid.
3985 The user SID must be a domain controller account (either RODC or
3988 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3989 const struct GUID *dsa_guid,
3990 const struct dom_sid *sid)
3993 - find DN of record with the DSA GUID in the
3994 configuration partition (objectGUID)
3995 - remove "NTDS Settings" component from DN
3996 - do a base search on that DN for serverReference with
3998 - extract objectSid from resulting serverReference
4000 - check this sid matches the sid argument
4002 struct ldb_dn *config_dn;
4003 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4004 struct ldb_message *msg;
4005 const char *attrs1[] = { NULL };
4006 const char *attrs2[] = { "serverReference", NULL };
4008 struct ldb_dn *dn, *account_dn;
4009 struct dom_sid sid2;
4012 config_dn = ldb_get_config_basedn(ldb);
4014 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4015 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4016 if (ret != LDB_SUCCESS) {
4017 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4018 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4019 talloc_free(tmp_ctx);
4020 return ldb_operr(ldb);
4024 if (!ldb_dn_remove_child_components(dn, 1)) {
4025 talloc_free(tmp_ctx);
4026 return ldb_operr(ldb);
4029 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4030 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4031 "(objectClass=server)");
4032 if (ret != LDB_SUCCESS) {
4033 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4034 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4035 talloc_free(tmp_ctx);
4036 return ldb_operr(ldb);
4039 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4040 if (account_dn == NULL) {
4041 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4042 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4043 talloc_free(tmp_ctx);
4044 return ldb_operr(ldb);
4047 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4048 if (!NT_STATUS_IS_OK(status)) {
4049 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4050 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4051 talloc_free(tmp_ctx);
4052 return ldb_operr(ldb);
4055 if (!dom_sid_equal(sid, &sid2)) {
4056 /* someone is trying to spoof another account */
4057 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4058 GUID_string(tmp_ctx, dsa_guid),
4059 dom_sid_string(tmp_ctx, sid),
4060 dom_sid_string(tmp_ctx, &sid2)));
4061 talloc_free(tmp_ctx);
4062 return ldb_operr(ldb);
4065 talloc_free(tmp_ctx);
4069 static const char *secret_attributes[] = {
4072 "initialAuthIncoming",
4073 "initialAuthOutgoing",
4077 "supplementalCredentials",
4078 "trustAuthIncoming",
4079 "trustAuthOutgoing",
4085 check if the attribute belongs to the RODC filtered attribute set
4086 Note that attributes that are in the filtered attribute set are the
4087 ones that _are_ always sent to a RODC
4089 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4091 /* they never get secret attributes */
4092 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4096 /* they do get non-secret critical attributes */
4097 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4101 /* they do get non-secret attributes marked as being in the FAS */
4102 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4106 /* other attributes are denied */
4110 /* return fsmo role dn and role owner dn for a particular role*/
4111 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4112 struct ldb_context *ldb,
4114 struct ldb_dn **fsmo_role_dn,
4115 struct ldb_dn **role_owner_dn)
4119 case DREPL_NAMING_MASTER:
4120 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4121 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4122 if (ret != LDB_SUCCESS) {
4123 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4124 ldb_errstring(ldb)));
4125 talloc_free(tmp_ctx);
4126 return WERR_DS_DRA_INTERNAL_ERROR;
4129 case DREPL_INFRASTRUCTURE_MASTER:
4130 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4131 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4132 if (ret != LDB_SUCCESS) {
4133 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4134 ldb_errstring(ldb)));
4135 talloc_free(tmp_ctx);
4136 return WERR_DS_DRA_INTERNAL_ERROR;
4139 case DREPL_RID_MASTER:
4140 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4141 if (ret != LDB_SUCCESS) {
4142 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4143 talloc_free(tmp_ctx);
4144 return WERR_DS_DRA_INTERNAL_ERROR;
4147 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4148 if (ret != LDB_SUCCESS) {
4149 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4150 ldb_errstring(ldb)));
4151 talloc_free(tmp_ctx);
4152 return WERR_DS_DRA_INTERNAL_ERROR;
4155 case DREPL_SCHEMA_MASTER:
4156 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4157 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4158 if (ret != LDB_SUCCESS) {
4159 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4160 ldb_errstring(ldb)));
4161 talloc_free(tmp_ctx);
4162 return WERR_DS_DRA_INTERNAL_ERROR;
4165 case DREPL_PDC_MASTER:
4166 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4167 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4168 if (ret != LDB_SUCCESS) {
4169 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4170 ldb_errstring(ldb)));
4171 talloc_free(tmp_ctx);
4172 return WERR_DS_DRA_INTERNAL_ERROR;
4176 return WERR_DS_DRA_INTERNAL_ERROR;
4181 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4182 TALLOC_CTX *mem_ctx,
4183 struct ldb_dn *server_dn)
4186 struct ldb_result *res = NULL;
4187 const char * const attrs[] = { "dNSHostName", NULL};
4189 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4193 if (ldb_ret != LDB_SUCCESS) {
4194 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4195 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4199 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4203 returns true if an attribute is in the filter,
4204 false otherwise, provided that attribute value is provided with the expression
4206 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4210 switch (tree->operation) {
4213 for (i=0;i<tree->u.list.num_elements;i++) {
4214 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4220 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4221 case LDB_OP_EQUALITY:
4222 case LDB_OP_GREATER:
4225 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4229 case LDB_OP_SUBSTRING:
4230 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4234 case LDB_OP_PRESENT:
4235 /* (attrname=*) is not filtered out */
4237 case LDB_OP_EXTENDED:
4238 if (tree->u.extended.attr &&
4239 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4247 bool is_attr_in_list(const char * const * attrs, const char *attr)
4251 for (i = 0; attrs[i]; i++) {
4252 if (ldb_attr_cmp(attrs[i], attr) == 0)