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 const char *attrs[] = { NULL };
201 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
203 va_start(ap, format);
204 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, NULL, attrs, format, ap);
206 talloc_free(tmp_ctx);
213 search the sam for a single integer attribute in exactly 1 record
215 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
217 unsigned int default_value,
218 struct ldb_dn *basedn,
219 const char *attr_name,
220 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
224 struct ldb_message **res;
225 const char *attrs[2] = { NULL, NULL };
227 attrs[0] = attr_name;
229 va_start(ap, format);
230 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
234 return default_value;
237 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
241 search the sam for a single signed 64 bit integer attribute in exactly 1 record
243 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
245 int64_t default_value,
246 struct ldb_dn *basedn,
247 const char *attr_name,
248 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
252 struct ldb_message **res;
253 const char *attrs[2] = { NULL, NULL };
255 attrs[0] = attr_name;
257 va_start(ap, format);
258 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
262 return default_value;
265 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
269 search the sam for multipe records each giving a single string attribute
270 return the number of matches, or -1 on error
272 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
274 struct ldb_dn *basedn,
276 const char *attr_name,
277 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
281 const char *attrs[2] = { NULL, NULL };
282 struct ldb_message **res = NULL;
284 attrs[0] = attr_name;
286 va_start(ap, format);
287 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
294 /* make sure its single valued */
295 for (i=0;i<count;i++) {
296 if (res[i]->num_elements != 1) {
297 DEBUG(1,("samdb: search for %s %s not single valued\n",
304 *strs = talloc_array(mem_ctx, const char *, count+1);
310 for (i=0;i<count;i++) {
311 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
313 (*strs)[count] = NULL;
318 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
319 const char *attr, struct ldb_dn *default_value)
321 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
323 return default_value;
329 pull a rid from a objectSid in a result set.
331 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
332 const char *attr, uint32_t default_value)
337 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
339 return default_value;
341 rid = sid->sub_auths[sid->num_auths-1];
347 pull a dom_sid structure from a objectSid in a result set.
349 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
352 const struct ldb_val *v;
354 enum ndr_err_code ndr_err;
355 v = ldb_msg_find_ldb_val(msg, attr);
359 sid = talloc(mem_ctx, struct dom_sid);
363 ndr_err = ndr_pull_struct_blob(v, sid, sid,
364 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
365 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
373 pull a guid structure from a objectGUID in a result set.
375 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
377 const struct ldb_val *v;
381 v = ldb_msg_find_ldb_val(msg, attr);
382 if (!v) return GUID_zero();
384 status = GUID_from_ndr_blob(v, &guid);
385 if (!NT_STATUS_IS_OK(status)) {
393 pull a sid prefix from a objectSid in a result set.
394 this is used to find the domain sid for a user
396 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
399 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
400 if (!sid || sid->num_auths < 1) return NULL;
406 pull a NTTIME in a result set.
408 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
409 NTTIME default_value)
411 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
415 * Windows stores 0 for lastLogoff.
416 * But when a MS DC return the lastLogoff (as Logoff Time)
417 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
418 * cause windows 2008 and newer version to fail for SMB requests
420 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
422 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
425 ret = 0x7FFFFFFFFFFFFFFFULL;
431 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
432 * indicate an account doesn't expire.
434 * When Windows initially creates an account, it sets
435 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
436 * when changing from an account having a specific expiration date to
437 * that account never expiring, it sets accountExpires = 0.
439 * Consolidate that logic here to allow clearer logic for account expiry in
440 * the rest of the code.
442 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
444 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
448 ret = 0x7FFFFFFFFFFFFFFFULL;
454 construct the allow_password_change field from the PwdLastSet attribute and the
455 domain password settings
457 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
459 struct ldb_dn *domain_dn,
460 struct ldb_message *msg,
463 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
466 if (attr_time == 0) {
470 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
472 /* yes, this is a -= not a += as minPwdAge is stored as the negative
473 of the number of 100-nano-seconds */
474 attr_time -= minPwdAge;
480 construct the force_password_change field from the PwdLastSet
481 attribute, the userAccountControl and the domain password settings
483 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
485 struct ldb_dn *domain_dn,
486 struct ldb_message *msg)
488 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
489 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
490 "userAccountControl",
494 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
495 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
496 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
497 return 0x7FFFFFFFFFFFFFFFULL;
500 if (attr_time == 0) {
503 if (attr_time == -1) {
504 return 0x7FFFFFFFFFFFFFFFULL;
507 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
509 if (maxPwdAge == 0) {
510 return 0x7FFFFFFFFFFFFFFFULL;
512 attr_time -= maxPwdAge;
519 pull a samr_Password structutre from a result set.
521 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
523 struct samr_Password *hash = NULL;
524 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
525 if (val && (val->length >= sizeof(hash->hash))) {
526 hash = talloc(mem_ctx, struct samr_Password);
527 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
533 pull an array of samr_Password structures from a result set.
535 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
536 const char *attr, struct samr_Password **hashes)
538 unsigned int count, i;
539 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
545 count = val->length / 16;
550 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
555 for (i=0;i<count;i++) {
556 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
562 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
563 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
565 struct samr_Password *lmPwdHash, *ntPwdHash;
568 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
571 } else if (num_nt > 1) {
572 return NT_STATUS_INTERNAL_DB_CORRUPTION;
574 *nt_pwd = &ntPwdHash[0];
578 /* Ensure that if we have turned off LM
579 * authentication, that we never use the LM hash, even
581 if (lpcfg_lanman_auth(lp_ctx)) {
583 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
586 } else if (num_lm > 1) {
587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
589 *lm_pwd = &lmPwdHash[0];
599 pull a samr_LogonHours structutre from a result set.
601 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
603 struct samr_LogonHours hours;
604 size_t units_per_week = 168;
605 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
610 units_per_week = val->length * 8;
613 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
617 hours.units_per_week = units_per_week;
618 memset(hours.bits, 0xFF, units_per_week/8);
620 memcpy(hours.bits, val->data, val->length);
627 pull a set of account_flags from a result set.
629 This requires that the attributes:
634 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
635 struct ldb_message *msg, struct ldb_dn *domain_dn)
637 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
638 uint32_t acct_flags = ds_uf2acb(userAccountControl);
639 NTTIME must_change_time;
642 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
645 /* Test account expire time */
646 unix_to_nt_time(&now, time(NULL));
647 /* check for expired password */
648 if (must_change_time < now) {
649 acct_flags |= ACB_PW_EXPIRED;
654 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
655 struct ldb_message *msg,
658 struct lsa_BinaryString s;
659 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
667 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
671 s.length = s.size = val->length;
672 memcpy(s.array, val->data, val->length);
677 /* Find an attribute, with a particular value */
679 /* The current callers of this function expect a very specific
680 * behaviour: In particular, objectClass subclass equivilance is not
681 * wanted. This means that we should not lookup the schema for the
682 * comparison function */
683 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
684 const struct ldb_message *msg,
685 const char *name, const char *value)
688 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
694 for (i=0;i<el->num_values;i++) {
695 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
704 * This is intended for use by the "password hash" module since there
705 * password changes can be specified through one message element with the
706 * new password (to set) and another one with the old password (to unset).
708 * The first which sets a password (new value) can have flags
709 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
710 * for entries). The latter (old value) has always specified
711 * LDB_FLAG_MOD_DELETE.
713 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
714 * doesn't contain only one value (this is the Windows Server behaviour)
715 * otherwise LDB_SUCCESS.
717 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
719 const struct ldb_val **new_val,
720 const struct ldb_val **old_val)
731 for (i = 0; i < msg->num_elements; i++) {
732 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
733 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
734 *old_val = &msg->elements[i].values[0];
736 *new_val = &msg->elements[i].values[0];
744 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
746 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
747 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
752 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
754 struct ldb_message_element *el;
756 el = ldb_msg_find_element(msg, name);
761 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
767 add a string element to a message
769 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
770 const char *attr_name, const char *str)
772 const char *s = talloc_strdup(mem_ctx, str);
774 return ldb_oom(sam_ldb);
776 return ldb_msg_add_string(msg, attr_name, s);
780 add a dom_sid element to a message
782 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
783 const char *attr_name, struct dom_sid *sid)
786 enum ndr_err_code ndr_err;
788 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
790 (ndr_push_flags_fn_t)ndr_push_dom_sid);
791 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
792 return ldb_operr(sam_ldb);
794 return ldb_msg_add_value(msg, attr_name, &v, NULL);
799 add a delete element operation to a message
801 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
802 const char *attr_name)
804 /* we use an empty replace rather than a delete, as it allows for
805 dsdb_replace() to be used everywhere */
806 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
810 add an add attribute value to a message or enhance an existing attribute
811 which has the same name and the add flag set.
813 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
814 struct ldb_message *msg, const char *attr_name,
817 struct ldb_message_element *el;
818 struct ldb_val val, *vals;
824 v = talloc_strdup(mem_ctx, value);
826 return ldb_oom(sam_ldb);
829 val.data = (uint8_t *) v;
830 val.length = strlen(v);
832 if (val.length == 0) {
833 /* allow empty strings as non-existent attributes */
837 for (i = 0; i < msg->num_elements; i++) {
838 el = &msg->elements[i];
839 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
840 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
846 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
848 if (ret != LDB_SUCCESS) {
853 vals = talloc_realloc(msg, el->values, struct ldb_val,
856 return ldb_oom(sam_ldb);
859 el->values[el->num_values] = val;
866 add a delete attribute value to a message or enhance an existing attribute
867 which has the same name and the delete flag set.
869 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
870 struct ldb_message *msg, const char *attr_name,
873 struct ldb_message_element *el;
874 struct ldb_val val, *vals;
880 v = talloc_strdup(mem_ctx, value);
882 return ldb_oom(sam_ldb);
885 val.data = (uint8_t *) v;
886 val.length = strlen(v);
888 if (val.length == 0) {
889 /* allow empty strings as non-existent attributes */
893 for (i = 0; i < msg->num_elements; i++) {
894 el = &msg->elements[i];
895 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
896 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
902 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
904 if (ret != LDB_SUCCESS) {
909 vals = talloc_realloc(msg, el->values, struct ldb_val,
912 return ldb_oom(sam_ldb);
915 el->values[el->num_values] = val;
922 add a int element to a message
924 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
925 const char *attr_name, int v)
927 const char *s = talloc_asprintf(mem_ctx, "%d", v);
929 return ldb_oom(sam_ldb);
931 return ldb_msg_add_string(msg, attr_name, s);
935 * Add an unsigned int element to a message
937 * The issue here is that we have not yet first cast to int32_t explicitly,
938 * before we cast to an signed int to printf() into the %d or cast to a
939 * int64_t before we then cast to a long long to printf into a %lld.
941 * There are *no* unsigned integers in Active Directory LDAP, even the RID
942 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
943 * (See the schema, and the syntax definitions in schema_syntax.c).
946 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
947 const char *attr_name, unsigned int v)
949 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
953 add a (signed) int64_t element to a message
955 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
956 const char *attr_name, int64_t v)
958 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
960 return ldb_oom(sam_ldb);
962 return ldb_msg_add_string(msg, attr_name, s);
966 * Add an unsigned int64_t (uint64_t) element to a message
968 * The issue here is that we have not yet first cast to int32_t explicitly,
969 * before we cast to an signed int to printf() into the %d or cast to a
970 * int64_t before we then cast to a long long to printf into a %lld.
972 * There are *no* unsigned integers in Active Directory LDAP, even the RID
973 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
974 * (See the schema, and the syntax definitions in schema_syntax.c).
977 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
978 const char *attr_name, uint64_t v)
980 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
984 add a samr_Password element to a message
986 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
987 const char *attr_name, const struct samr_Password *hash)
990 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
992 return ldb_oom(sam_ldb);
995 return ldb_msg_add_value(msg, attr_name, &val, NULL);
999 add a samr_Password array to a message
1001 int samdb_msg_add_hashes(struct ldb_context *ldb,
1002 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1003 const char *attr_name, struct samr_Password *hashes,
1008 val.data = talloc_array_size(mem_ctx, 16, count);
1009 val.length = count*16;
1011 return ldb_oom(ldb);
1013 for (i=0;i<count;i++) {
1014 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1016 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1020 add a acct_flags element to a message
1022 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1023 const char *attr_name, uint32_t v)
1025 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1029 add a logon_hours element to a message
1031 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1032 const char *attr_name, struct samr_LogonHours *hours)
1035 val.length = hours->units_per_week / 8;
1036 val.data = hours->bits;
1037 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1041 add a parameters element to a message
1043 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1044 const char *attr_name, struct lsa_BinaryString *parameters)
1047 val.length = parameters->length;
1048 val.data = (uint8_t *)parameters->array;
1049 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1053 sets a general value element to a message
1055 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1056 const char *attr_name, const struct ldb_val *val)
1058 struct ldb_message_element *el;
1060 el = ldb_msg_find_element(msg, attr_name);
1064 return ldb_msg_add_value(msg, attr_name, val, NULL);
1068 set a string element in a message
1070 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1071 const char *attr_name, const char *str)
1073 struct ldb_message_element *el;
1075 el = ldb_msg_find_element(msg, attr_name);
1079 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1083 * sets a signed integer in a message
1085 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1086 struct ldb_message *msg, const char *attr_name, int v)
1088 struct ldb_message_element *el;
1090 el = ldb_msg_find_element(msg, attr_name);
1094 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1098 * Sets an unsigned int element in a message
1100 * The issue here is that we have not yet first cast to int32_t explicitly,
1101 * before we cast to an signed int to printf() into the %d or cast to a
1102 * int64_t before we then cast to a long long to printf into a %lld.
1104 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1105 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1106 * (See the schema, and the syntax definitions in schema_syntax.c).
1109 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1110 struct ldb_message *msg, const char *attr_name,
1113 struct ldb_message_element *el;
1115 el = ldb_msg_find_element(msg, attr_name);
1119 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1123 * Handle ldb_request in transaction
1125 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1126 struct ldb_request *req)
1130 ret = ldb_transaction_start(sam_ldb);
1131 if (ret != LDB_SUCCESS) {
1135 ret = ldb_request(sam_ldb, req);
1136 if (ret == LDB_SUCCESS) {
1137 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1140 if (ret == LDB_SUCCESS) {
1141 return ldb_transaction_commit(sam_ldb);
1143 ldb_transaction_cancel(sam_ldb);
1149 return a default security descriptor
1151 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1153 struct security_descriptor *sd;
1155 sd = security_descriptor_initialise(mem_ctx);
1160 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1162 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1163 struct ldb_dn *aggregate_dn;
1168 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1169 if (!aggregate_dn) {
1172 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1175 return aggregate_dn;
1178 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1180 struct ldb_dn *new_dn;
1182 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1183 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1184 talloc_free(new_dn);
1190 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1192 struct ldb_dn *new_dn;
1194 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1195 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1196 talloc_free(new_dn);
1202 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1204 struct ldb_dn *new_dn;
1206 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1207 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1208 talloc_free(new_dn);
1215 work out the domain sid for the current open ldb
1217 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1219 TALLOC_CTX *tmp_ctx;
1220 const struct dom_sid *domain_sid;
1221 const char *attrs[] = {
1225 struct ldb_result *res;
1228 /* see if we have a cached copy */
1229 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1234 tmp_ctx = talloc_new(ldb);
1235 if (tmp_ctx == NULL) {
1239 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1241 if (ret != LDB_SUCCESS) {
1245 if (res->count != 1) {
1249 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1250 if (domain_sid == NULL) {
1254 /* cache the domain_sid in the ldb */
1255 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1259 talloc_steal(ldb, domain_sid);
1260 talloc_free(tmp_ctx);
1265 talloc_free(tmp_ctx);
1270 get domain sid from cache
1272 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1274 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1277 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1279 TALLOC_CTX *tmp_ctx;
1280 struct dom_sid *dom_sid_new;
1281 struct dom_sid *dom_sid_old;
1283 /* see if we have a cached copy */
1284 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1285 "cache.domain_sid"), struct dom_sid);
1287 tmp_ctx = talloc_new(ldb);
1288 if (tmp_ctx == NULL) {
1292 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1297 /* cache the domain_sid in the ldb */
1298 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1302 talloc_steal(ldb, dom_sid_new);
1303 talloc_free(tmp_ctx);
1304 talloc_free(dom_sid_old);
1309 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1310 talloc_free(tmp_ctx);
1314 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1316 TALLOC_CTX *tmp_ctx;
1317 struct ldb_dn *ntds_settings_dn_new;
1318 struct ldb_dn *ntds_settings_dn_old;
1320 /* see if we have a cached copy */
1321 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1322 "cache.ntds_settings_dn"), struct ldb_dn);
1324 tmp_ctx = talloc_new(ldb);
1325 if (tmp_ctx == NULL) {
1329 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1330 if (!ntds_settings_dn_new) {
1334 /* cache the domain_sid in the ldb */
1335 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1339 talloc_steal(ldb, ntds_settings_dn_new);
1340 talloc_free(tmp_ctx);
1341 talloc_free(ntds_settings_dn_old);
1346 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1347 talloc_free(tmp_ctx);
1351 /* Obtain the short name of the flexible single master operator
1352 * (FSMO), such as the PDC Emulator */
1353 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1356 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1357 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1358 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1359 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1361 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1362 /* Ensure this matches the format. This gives us a
1363 * bit more confidence that a 'cn' value will be a
1368 return (char *)val->data;
1374 work out the ntds settings dn for the current open ldb
1376 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1378 TALLOC_CTX *tmp_ctx;
1379 const char *root_attrs[] = { "dsServiceName", NULL };
1381 struct ldb_result *root_res;
1382 struct ldb_dn *settings_dn;
1384 /* see if we have a cached copy */
1385 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1390 tmp_ctx = talloc_new(ldb);
1391 if (tmp_ctx == NULL) {
1395 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1397 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1398 ldb_errstring(ldb)));
1402 if (root_res->count != 1) {
1406 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1408 /* cache the domain_sid in the ldb */
1409 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1413 talloc_steal(ldb, settings_dn);
1414 talloc_free(tmp_ctx);
1419 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1420 talloc_free(tmp_ctx);
1425 work out the ntds settings invocationId for the current open ldb
1427 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1429 TALLOC_CTX *tmp_ctx;
1430 const char *attrs[] = { "invocationId", NULL };
1432 struct ldb_result *res;
1433 struct GUID *invocation_id;
1435 /* see if we have a cached copy */
1436 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1437 if (invocation_id) {
1438 return invocation_id;
1441 tmp_ctx = talloc_new(ldb);
1442 if (tmp_ctx == NULL) {
1446 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1451 if (res->count != 1) {
1455 invocation_id = talloc(tmp_ctx, struct GUID);
1456 if (!invocation_id) {
1460 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1462 /* cache the domain_sid in the ldb */
1463 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1467 talloc_steal(ldb, invocation_id);
1468 talloc_free(tmp_ctx);
1470 return invocation_id;
1473 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1474 talloc_free(tmp_ctx);
1478 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1480 TALLOC_CTX *tmp_ctx;
1481 struct GUID *invocation_id_new;
1482 struct GUID *invocation_id_old;
1484 /* see if we have a cached copy */
1485 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1486 "cache.invocation_id");
1488 tmp_ctx = talloc_new(ldb);
1489 if (tmp_ctx == NULL) {
1493 invocation_id_new = talloc(tmp_ctx, struct GUID);
1494 if (!invocation_id_new) {
1498 *invocation_id_new = *invocation_id_in;
1500 /* cache the domain_sid in the ldb */
1501 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1505 talloc_steal(ldb, invocation_id_new);
1506 talloc_free(tmp_ctx);
1507 talloc_free(invocation_id_old);
1512 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1513 talloc_free(tmp_ctx);
1518 work out the ntds settings objectGUID for the current open ldb
1520 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1522 TALLOC_CTX *tmp_ctx;
1523 const char *attrs[] = { "objectGUID", NULL };
1525 struct ldb_result *res;
1526 struct GUID *ntds_guid;
1528 /* see if we have a cached copy */
1529 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1534 tmp_ctx = talloc_new(ldb);
1535 if (tmp_ctx == NULL) {
1539 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1544 if (res->count != 1) {
1548 ntds_guid = talloc(tmp_ctx, struct GUID);
1553 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1555 /* cache the domain_sid in the ldb */
1556 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1560 talloc_steal(ldb, ntds_guid);
1561 talloc_free(tmp_ctx);
1566 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1567 talloc_free(tmp_ctx);
1571 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1573 TALLOC_CTX *tmp_ctx;
1574 struct GUID *ntds_guid_new;
1575 struct GUID *ntds_guid_old;
1577 /* see if we have a cached copy */
1578 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1580 tmp_ctx = talloc_new(ldb);
1581 if (tmp_ctx == NULL) {
1585 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1586 if (!ntds_guid_new) {
1590 *ntds_guid_new = *ntds_guid_in;
1592 /* cache the domain_sid in the ldb */
1593 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1597 talloc_steal(ldb, ntds_guid_new);
1598 talloc_free(tmp_ctx);
1599 talloc_free(ntds_guid_old);
1604 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1605 talloc_free(tmp_ctx);
1610 work out the server dn for the current open ldb
1612 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1614 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1618 work out the server dn for the current open ldb
1620 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1622 struct ldb_dn *server_dn;
1623 struct ldb_dn *servers_dn;
1624 struct ldb_dn *server_site_dn;
1626 /* TODO: there must be a saner way to do this!! */
1627 server_dn = samdb_server_dn(ldb, mem_ctx);
1628 if (!server_dn) return NULL;
1630 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1631 talloc_free(server_dn);
1632 if (!servers_dn) return NULL;
1634 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1635 talloc_free(servers_dn);
1637 return server_site_dn;
1641 find the site name from a computers DN record
1643 int samdb_find_site_for_computer(struct ldb_context *ldb,
1644 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1645 const char **site_name)
1649 const struct ldb_val *rdn_val;
1653 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1654 if (ret != LDB_SUCCESS) {
1658 if (!ldb_dn_remove_child_components(dn, 2)) {
1660 return LDB_ERR_INVALID_DN_SYNTAX;
1662 rdn_val = ldb_dn_get_rdn_val(dn);
1663 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1666 return LDB_ERR_OPERATIONS_ERROR;
1672 find the NTDS GUID from a computers DN record
1674 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1675 struct GUID *ntds_guid)
1680 *ntds_guid = GUID_zero();
1682 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1683 if (ret != LDB_SUCCESS) {
1687 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1689 return LDB_ERR_OPERATIONS_ERROR;
1692 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1698 find a 'reference' DN that points at another object
1699 (eg. serverReference, rIDManagerReference etc)
1701 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1702 const char *attribute, struct ldb_dn **dn)
1704 const char *attrs[2];
1705 struct ldb_result *res;
1708 attrs[0] = attribute;
1711 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1712 if (ret != LDB_SUCCESS) {
1716 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1718 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1719 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1720 ldb_dn_get_linearized(base));
1722 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1723 ldb_dn_get_linearized(base));
1726 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1734 find our machine account via the serverReference attribute in the
1737 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1739 struct ldb_dn *server_dn;
1742 server_dn = samdb_server_dn(ldb, mem_ctx);
1743 if (server_dn == NULL) {
1744 return LDB_ERR_NO_SUCH_OBJECT;
1747 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1748 talloc_free(server_dn);
1754 find the RID Manager$ DN via the rIDManagerReference attribute in the
1757 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1759 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1760 "rIDManagerReference", dn);
1764 find the RID Set DN via the rIDSetReferences attribute in our
1767 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1769 struct ldb_dn *server_ref_dn;
1772 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1773 if (ret != LDB_SUCCESS) {
1776 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1777 talloc_free(server_ref_dn);
1781 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1783 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1790 return (const char *) val->data;
1794 * Finds the client site by using the client's IP address.
1795 * The "subnet_name" returns the name of the subnet if parameter != NULL
1797 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1798 const char *ip_address, char **subnet_name)
1800 const char *attrs[] = { "cn", "siteObject", NULL };
1801 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1802 struct ldb_result *res;
1803 const struct ldb_val *val;
1804 const char *site_name = NULL, *l_subnet_name = NULL;
1805 const char *allow_list[2] = { NULL, NULL };
1806 unsigned int i, count;
1810 * if we don't have a client ip e.g. ncalrpc
1811 * the server site is the client site
1813 if (ip_address == NULL) {
1814 return samdb_server_site_name(ldb, mem_ctx);
1817 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1818 if (sites_container_dn == NULL) {
1822 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1823 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1824 talloc_free(sites_container_dn);
1825 talloc_free(subnets_dn);
1829 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1831 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1833 } else if (ret != LDB_SUCCESS) {
1834 talloc_free(sites_container_dn);
1835 talloc_free(subnets_dn);
1841 for (i = 0; i < count; i++) {
1842 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1845 allow_list[0] = l_subnet_name;
1847 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1848 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1851 if (sites_dn == NULL) {
1852 /* No reference, maybe another subnet matches */
1856 /* "val" cannot be NULL here since "sites_dn" != NULL */
1857 val = ldb_dn_get_rdn_val(sites_dn);
1858 site_name = talloc_strdup(mem_ctx,
1859 (const char *) val->data);
1861 talloc_free(sites_dn);
1867 if (site_name == NULL) {
1868 /* This is the Windows Server fallback rule: when no subnet
1869 * exists and we have only one site available then use it (it
1870 * is for sure the same as our server site). If more sites do
1871 * exist then we don't know which one to use and set the site
1873 cnt = samdb_search_count(ldb, sites_container_dn,
1874 "(objectClass=site)");
1876 site_name = samdb_server_site_name(ldb, mem_ctx);
1878 site_name = talloc_strdup(mem_ctx, "");
1880 l_subnet_name = NULL;
1883 if (subnet_name != NULL) {
1884 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1887 talloc_free(sites_container_dn);
1888 talloc_free(subnets_dn);
1895 work out if we are the PDC for the domain of the current open ldb
1897 bool samdb_is_pdc(struct ldb_context *ldb)
1899 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1901 struct ldb_result *dom_res;
1902 TALLOC_CTX *tmp_ctx;
1906 tmp_ctx = talloc_new(ldb);
1907 if (tmp_ctx == NULL) {
1908 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1912 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1913 if (ret != LDB_SUCCESS) {
1914 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1915 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1916 ldb_errstring(ldb)));
1919 if (dom_res->count != 1) {
1923 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1925 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1931 talloc_free(tmp_ctx);
1936 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1937 talloc_free(tmp_ctx);
1942 work out if we are a Global Catalog server for the domain of the current open ldb
1944 bool samdb_is_gc(struct ldb_context *ldb)
1946 const char *attrs[] = { "options", NULL };
1948 struct ldb_result *res;
1949 TALLOC_CTX *tmp_ctx;
1951 tmp_ctx = talloc_new(ldb);
1952 if (tmp_ctx == NULL) {
1953 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1957 /* Query cn=ntds settings,.... */
1958 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1959 if (ret != LDB_SUCCESS) {
1960 talloc_free(tmp_ctx);
1963 if (res->count != 1) {
1964 talloc_free(tmp_ctx);
1968 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1969 talloc_free(tmp_ctx);
1971 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1972 if (options & 0x000000001) {
1978 /* Find a domain object in the parents of a particular DN. */
1979 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1980 struct ldb_dn **parent_dn, const char **errstring)
1982 TALLOC_CTX *local_ctx;
1983 struct ldb_dn *sdn = dn;
1984 struct ldb_result *res = NULL;
1985 int ret = LDB_SUCCESS;
1986 const char *attrs[] = { NULL };
1988 local_ctx = talloc_new(mem_ctx);
1989 if (local_ctx == NULL) return ldb_oom(ldb);
1991 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1992 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1993 "(|(objectClass=domain)(objectClass=builtinDomain))");
1994 if (ret == LDB_SUCCESS) {
1995 if (res->count == 1) {
2003 if (ret != LDB_SUCCESS) {
2004 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2005 ldb_dn_get_linearized(dn),
2006 ldb_dn_get_linearized(sdn),
2007 ldb_errstring(ldb));
2008 talloc_free(local_ctx);
2011 if (res->count != 1) {
2012 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2013 ldb_dn_get_linearized(dn));
2014 DEBUG(0,(__location__ ": %s\n", *errstring));
2015 talloc_free(local_ctx);
2016 return LDB_ERR_CONSTRAINT_VIOLATION;
2019 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2020 talloc_free(local_ctx);
2026 * Performs checks on a user password (plaintext UNIX format - attribute
2027 * "password"). The remaining parameters have to be extracted from the domain
2030 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2032 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2033 const uint32_t pwdProperties,
2034 const uint32_t minPwdLength)
2036 /* checks if the "minPwdLength" property is satisfied */
2037 if (minPwdLength > password->length)
2038 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2040 /* checks the password complexity */
2041 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2042 && (password->data != NULL)
2043 && (!check_password_quality((const char *) password->data)))
2044 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2046 return SAMR_VALIDATION_STATUS_SUCCESS;
2050 * Callback for "samdb_set_password" password change
2052 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2057 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2060 if (ares->error != LDB_SUCCESS) {
2062 req->context = talloc_steal(req,
2063 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2065 return ldb_request_done(req, ret);
2068 if (ares->type != LDB_REPLY_DONE) {
2070 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2073 req->context = talloc_steal(req,
2074 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2076 return ldb_request_done(req, LDB_SUCCESS);
2080 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2081 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2082 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2083 * user change or not. The "rejectReason" gives some more informations if the
2086 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2087 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2089 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2090 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2091 const DATA_BLOB *new_password,
2092 const struct samr_Password *lmNewHash,
2093 const struct samr_Password *ntNewHash,
2094 const struct samr_Password *lmOldHash,
2095 const struct samr_Password *ntOldHash,
2096 enum samPwdChangeReason *reject_reason,
2097 struct samr_DomInfo1 **_dominfo)
2099 struct ldb_message *msg;
2100 struct ldb_message_element *el;
2101 struct ldb_request *req;
2102 struct dsdb_control_password_change_status *pwd_stat = NULL;
2104 NTSTATUS status = NT_STATUS_OK;
2106 #define CHECK_RET(x) \
2107 if (x != LDB_SUCCESS) { \
2109 return NT_STATUS_NO_MEMORY; \
2112 msg = ldb_msg_new(mem_ctx);
2114 return NT_STATUS_NO_MEMORY;
2117 if ((new_password != NULL)
2118 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2119 /* we have the password as plaintext UTF16 */
2120 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2121 new_password, NULL));
2122 el = ldb_msg_find_element(msg, "clearTextPassword");
2123 el->flags = LDB_FLAG_MOD_REPLACE;
2124 } else if ((new_password == NULL)
2125 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2126 /* we have a password as LM and/or NT hash */
2127 if (lmNewHash != NULL) {
2128 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2129 "dBCSPwd", lmNewHash));
2130 el = ldb_msg_find_element(msg, "dBCSPwd");
2131 el->flags = LDB_FLAG_MOD_REPLACE;
2133 if (ntNewHash != NULL) {
2134 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2135 "unicodePwd", ntNewHash));
2136 el = ldb_msg_find_element(msg, "unicodePwd");
2137 el->flags = LDB_FLAG_MOD_REPLACE;
2140 /* the password wasn't specified correctly */
2142 return NT_STATUS_INVALID_PARAMETER;
2145 /* build modify request */
2146 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2147 samdb_set_password_callback, NULL);
2148 if (ret != LDB_SUCCESS) {
2150 return NT_STATUS_NO_MEMORY;
2153 /* A password change operation */
2154 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2155 struct dsdb_control_password_change *change;
2157 change = talloc(req, struct dsdb_control_password_change);
2158 if (change == NULL) {
2161 return NT_STATUS_NO_MEMORY;
2164 change->old_nt_pwd_hash = ntOldHash;
2165 change->old_lm_pwd_hash = lmOldHash;
2167 ret = ldb_request_add_control(req,
2168 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2170 if (ret != LDB_SUCCESS) {
2173 return NT_STATUS_NO_MEMORY;
2176 ret = ldb_request_add_control(req,
2177 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2179 if (ret != LDB_SUCCESS) {
2182 return NT_STATUS_NO_MEMORY;
2184 ret = ldb_request_add_control(req,
2185 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2187 if (ret != LDB_SUCCESS) {
2190 return NT_STATUS_NO_MEMORY;
2193 ret = dsdb_autotransaction_request(ldb, req);
2195 if (req->context != NULL) {
2196 pwd_stat = talloc_steal(mem_ctx,
2197 ((struct ldb_control *)req->context)->data);
2203 /* Sets the domain info (if requested) */
2204 if (_dominfo != NULL) {
2205 struct samr_DomInfo1 *dominfo;
2207 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2208 if (dominfo == NULL) {
2209 return NT_STATUS_NO_MEMORY;
2212 if (pwd_stat != NULL) {
2213 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2214 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2215 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2216 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2217 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2220 *_dominfo = dominfo;
2223 if (reject_reason != NULL) {
2224 if (pwd_stat != NULL) {
2225 *reject_reason = pwd_stat->reject_reason;
2227 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2231 if (pwd_stat != NULL) {
2232 talloc_free(pwd_stat);
2235 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2236 const char *errmsg = ldb_errstring(ldb);
2237 char *endptr = NULL;
2238 WERROR werr = WERR_GENERAL_FAILURE;
2239 status = NT_STATUS_UNSUCCESSFUL;
2240 if (errmsg != NULL) {
2241 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2243 if (endptr != errmsg) {
2244 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2245 status = NT_STATUS_WRONG_PASSWORD;
2247 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2248 status = NT_STATUS_PASSWORD_RESTRICTION;
2251 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2252 /* don't let the caller know if an account doesn't exist */
2253 status = NT_STATUS_WRONG_PASSWORD;
2254 } else if (ret != LDB_SUCCESS) {
2255 status = NT_STATUS_UNSUCCESSFUL;
2262 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2263 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2264 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2265 * user change or not. The "rejectReason" gives some more informations if the
2268 * This wrapper function for "samdb_set_password" takes a SID as input rather
2271 * This call encapsulates a new LDB transaction for changing the password;
2272 * therefore the user hasn't to start a new one.
2274 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2275 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2276 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2277 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2279 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2280 const struct dom_sid *user_sid,
2281 const DATA_BLOB *new_password,
2282 const struct samr_Password *lmNewHash,
2283 const struct samr_Password *ntNewHash,
2284 const struct samr_Password *lmOldHash,
2285 const struct samr_Password *ntOldHash,
2286 enum samPwdChangeReason *reject_reason,
2287 struct samr_DomInfo1 **_dominfo)
2290 struct ldb_dn *user_dn;
2293 ret = ldb_transaction_start(ldb);
2294 if (ret != LDB_SUCCESS) {
2295 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2296 return NT_STATUS_TRANSACTION_ABORTED;
2299 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2300 "(&(objectSid=%s)(objectClass=user))",
2301 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2303 ldb_transaction_cancel(ldb);
2304 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2305 dom_sid_string(mem_ctx, user_sid)));
2306 return NT_STATUS_NO_SUCH_USER;
2309 nt_status = samdb_set_password(ldb, mem_ctx,
2312 lmNewHash, ntNewHash,
2313 lmOldHash, ntOldHash,
2314 reject_reason, _dominfo);
2315 if (!NT_STATUS_IS_OK(nt_status)) {
2316 ldb_transaction_cancel(ldb);
2317 talloc_free(user_dn);
2321 ret = ldb_transaction_commit(ldb);
2322 if (ret != LDB_SUCCESS) {
2323 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2324 ldb_dn_get_linearized(user_dn),
2325 ldb_errstring(ldb)));
2326 talloc_free(user_dn);
2327 return NT_STATUS_TRANSACTION_ABORTED;
2330 talloc_free(user_dn);
2331 return NT_STATUS_OK;
2335 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2336 struct dom_sid *sid, struct ldb_dn **ret_dn)
2338 struct ldb_message *msg;
2339 struct ldb_dn *basedn;
2343 sidstr = dom_sid_string(mem_ctx, sid);
2344 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2346 /* We might have to create a ForeignSecurityPrincipal, even if this user
2347 * is in our own domain */
2349 msg = ldb_msg_new(sidstr);
2351 talloc_free(sidstr);
2352 return NT_STATUS_NO_MEMORY;
2355 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2356 ldb_get_default_basedn(sam_ctx),
2357 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2359 if (ret != LDB_SUCCESS) {
2360 DEBUG(0, ("Failed to find DN for "
2361 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2362 talloc_free(sidstr);
2363 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2366 /* add core elements to the ldb_message for the alias */
2368 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2369 talloc_free(sidstr);
2370 return NT_STATUS_NO_MEMORY;
2373 ret = samdb_msg_add_string(sam_ctx, msg, msg,
2374 "objectClass", "foreignSecurityPrincipal");
2375 if (ret != LDB_SUCCESS) {
2376 talloc_free(sidstr);
2377 return NT_STATUS_NO_MEMORY;
2380 /* create the alias */
2381 ret = ldb_add(sam_ctx, msg);
2382 if (ret != LDB_SUCCESS) {
2383 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2385 ldb_dn_get_linearized(msg->dn),
2386 ldb_errstring(sam_ctx)));
2387 talloc_free(sidstr);
2388 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2391 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2392 talloc_free(sidstr);
2394 return NT_STATUS_OK;
2399 Find the DN of a domain, assuming it to be a dotted.dns name
2402 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2405 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2406 const char *binary_encoded;
2407 const char **split_realm;
2414 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2416 talloc_free(tmp_ctx);
2419 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2420 for (i=0; split_realm[i]; i++) {
2421 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2422 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2423 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2424 binary_encoded, ldb_dn_get_linearized(dn)));
2425 talloc_free(tmp_ctx);
2429 if (!ldb_dn_validate(dn)) {
2430 DEBUG(2, ("Failed to validated DN %s\n",
2431 ldb_dn_get_linearized(dn)));
2432 talloc_free(tmp_ctx);
2435 talloc_free(tmp_ctx);
2440 Find the DN of a domain, be it the netbios or DNS name
2442 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2443 const char *domain_name)
2445 const char * const domain_ref_attrs[] = {
2448 const char * const domain_ref2_attrs[] = {
2451 struct ldb_result *res_domain_ref;
2452 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2453 /* find the domain's DN */
2454 int ret_domain = ldb_search(ldb, mem_ctx,
2456 samdb_partitions_dn(ldb, mem_ctx),
2459 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2461 if (ret_domain != LDB_SUCCESS) {
2465 if (res_domain_ref->count == 0) {
2466 ret_domain = ldb_search(ldb, mem_ctx,
2468 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2471 "(objectclass=domain)");
2472 if (ret_domain != LDB_SUCCESS) {
2476 if (res_domain_ref->count == 1) {
2477 return res_domain_ref->msgs[0]->dn;
2482 if (res_domain_ref->count > 1) {
2483 DEBUG(0,("Found %d records matching domain [%s]\n",
2484 ret_domain, domain_name));
2488 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2494 use a GUID to find a DN
2496 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2497 TALLOC_CTX *mem_ctx,
2498 const struct GUID *guid, struct ldb_dn **dn)
2501 struct ldb_result *res;
2502 const char *attrs[] = { NULL };
2503 char *guid_str = GUID_string(mem_ctx, guid);
2506 return ldb_operr(ldb);
2509 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2510 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2511 DSDB_SEARCH_SHOW_EXTENDED_DN |
2512 DSDB_SEARCH_ONE_ONLY,
2513 "objectGUID=%s", guid_str);
2514 talloc_free(guid_str);
2515 if (ret != LDB_SUCCESS) {
2519 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2526 use a DN to find a GUID with a given attribute name
2528 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2529 struct ldb_dn *dn, const char *attribute,
2533 struct ldb_result *res;
2534 const char *attrs[2];
2535 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2537 attrs[0] = attribute;
2540 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2541 DSDB_SEARCH_SHOW_DELETED |
2542 DSDB_SEARCH_SHOW_RECYCLED);
2543 if (ret != LDB_SUCCESS) {
2544 talloc_free(tmp_ctx);
2547 if (res->count < 1) {
2548 talloc_free(tmp_ctx);
2549 return LDB_ERR_NO_SUCH_OBJECT;
2551 *guid = samdb_result_guid(res->msgs[0], attribute);
2552 talloc_free(tmp_ctx);
2557 use a DN to find a GUID
2559 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2560 struct ldb_dn *dn, struct GUID *guid)
2562 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2568 adds the given GUID to the given ldb_message. This value is added
2569 for the given attr_name (may be either "objectGUID" or "parentGUID").
2571 int dsdb_msg_add_guid(struct ldb_message *msg,
2573 const char *attr_name)
2578 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2580 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2581 if (!NT_STATUS_IS_OK(status)) {
2582 ret = LDB_ERR_OPERATIONS_ERROR;
2586 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2587 if (ret != LDB_SUCCESS) {
2588 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2596 talloc_free(tmp_ctx);
2603 use a DN to find a SID
2605 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2606 struct ldb_dn *dn, struct dom_sid *sid)
2609 struct ldb_result *res;
2610 const char *attrs[] = { "objectSid", NULL };
2611 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2616 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2617 DSDB_SEARCH_SHOW_DELETED |
2618 DSDB_SEARCH_SHOW_RECYCLED);
2619 if (ret != LDB_SUCCESS) {
2620 talloc_free(tmp_ctx);
2623 if (res->count < 1) {
2624 talloc_free(tmp_ctx);
2625 return LDB_ERR_NO_SUCH_OBJECT;
2627 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2629 talloc_free(tmp_ctx);
2630 return LDB_ERR_NO_SUCH_OBJECT;
2633 talloc_free(tmp_ctx);
2638 use a SID to find a DN
2640 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2641 TALLOC_CTX *mem_ctx,
2642 struct dom_sid *sid, struct ldb_dn **dn)
2645 struct ldb_result *res;
2646 const char *attrs[] = { NULL };
2647 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2650 return ldb_operr(ldb);
2653 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2654 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2655 DSDB_SEARCH_SHOW_EXTENDED_DN |
2656 DSDB_SEARCH_ONE_ONLY,
2657 "objectSid=%s", sid_str);
2658 talloc_free(sid_str);
2659 if (ret != LDB_SUCCESS) {
2663 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2670 load a repsFromTo blob list for a given partition GUID
2671 attr must be "repsFrom" or "repsTo"
2673 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2674 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2676 const char *attrs[] = { attr, NULL };
2677 struct ldb_result *res = NULL;
2678 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2680 struct ldb_message_element *el;
2685 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2687 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2688 talloc_free(tmp_ctx);
2689 return WERR_DS_DRA_INTERNAL_ERROR;
2692 el = ldb_msg_find_element(res->msgs[0], attr);
2694 /* it's OK to be empty */
2695 talloc_free(tmp_ctx);
2699 *count = el->num_values;
2700 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2702 talloc_free(tmp_ctx);
2703 return WERR_DS_DRA_INTERNAL_ERROR;
2706 for (i=0; i<(*count); i++) {
2707 enum ndr_err_code ndr_err;
2708 ndr_err = ndr_pull_struct_blob(&el->values[i],
2711 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2712 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2713 talloc_free(tmp_ctx);
2714 return WERR_DS_DRA_INTERNAL_ERROR;
2718 talloc_free(tmp_ctx);
2724 save the repsFromTo blob list for a given partition GUID
2725 attr must be "repsFrom" or "repsTo"
2727 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2728 const char *attr, struct repsFromToBlob *r, uint32_t count)
2730 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2731 struct ldb_message *msg;
2732 struct ldb_message_element *el;
2735 msg = ldb_msg_new(tmp_ctx);
2737 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2741 el->values = talloc_array(msg, struct ldb_val, count);
2746 for (i=0; i<count; i++) {
2748 enum ndr_err_code ndr_err;
2750 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2752 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2753 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2761 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2762 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2766 talloc_free(tmp_ctx);
2771 talloc_free(tmp_ctx);
2772 return WERR_DS_DRA_INTERNAL_ERROR;
2777 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2778 object for a partition
2780 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2781 uint64_t *uSN, uint64_t *urgent_uSN)
2783 struct ldb_request *req;
2785 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2786 struct dsdb_control_current_partition *p_ctrl;
2787 struct ldb_result *res;
2789 res = talloc_zero(tmp_ctx, struct ldb_result);
2791 talloc_free(tmp_ctx);
2792 return ldb_oom(ldb);
2795 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2796 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2800 res, ldb_search_default_callback,
2802 if (ret != LDB_SUCCESS) {
2803 talloc_free(tmp_ctx);
2807 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2808 if (p_ctrl == NULL) {
2809 talloc_free(tmp_ctx);
2810 return ldb_oom(ldb);
2812 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2815 ret = ldb_request_add_control(req,
2816 DSDB_CONTROL_CURRENT_PARTITION_OID,
2818 if (ret != LDB_SUCCESS) {
2819 talloc_free(tmp_ctx);
2823 /* Run the new request */
2824 ret = ldb_request(ldb, req);
2826 if (ret == LDB_SUCCESS) {
2827 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2830 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
2831 /* it hasn't been created yet, which means
2832 an implicit value of zero */
2834 talloc_free(tmp_ctx);
2838 if (ret != LDB_SUCCESS) {
2839 talloc_free(tmp_ctx);
2843 if (res->count < 1) {
2849 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2851 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2855 talloc_free(tmp_ctx);
2860 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2861 const struct drsuapi_DsReplicaCursor2 *c2)
2863 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2866 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2867 const struct drsuapi_DsReplicaCursor *c2)
2869 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2874 see if a computer identified by its invocationId is a RODC
2876 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2878 /* 1) find the DN for this servers NTDSDSA object
2879 2) search for the msDS-isRODC attribute
2880 3) if not present then not a RODC
2881 4) if present and TRUE then is a RODC
2883 struct ldb_dn *config_dn;
2884 const char *attrs[] = { "msDS-isRODC", NULL };
2886 struct ldb_result *res;
2887 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2889 config_dn = ldb_get_config_basedn(sam_ctx);
2891 talloc_free(tmp_ctx);
2892 return ldb_operr(sam_ctx);
2895 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2896 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2898 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2900 talloc_free(tmp_ctx);
2904 if (ret != LDB_SUCCESS) {
2905 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2906 GUID_string(tmp_ctx, objectGUID)));
2908 talloc_free(tmp_ctx);
2912 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2913 *is_rodc = (ret == 1);
2915 talloc_free(tmp_ctx);
2921 see if we are a RODC
2923 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2925 const struct GUID *objectGUID;
2929 /* see if we have a cached copy */
2930 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2936 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2938 return ldb_operr(sam_ctx);
2941 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2942 if (ret != LDB_SUCCESS) {
2946 cached = talloc(sam_ctx, bool);
2947 if (cached == NULL) {
2948 return ldb_oom(sam_ctx);
2952 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2953 if (ret != LDB_SUCCESS) {
2954 talloc_free(cached);
2955 return ldb_operr(sam_ctx);
2961 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2963 TALLOC_CTX *tmp_ctx;
2966 tmp_ctx = talloc_new(ldb);
2967 if (tmp_ctx == NULL) {
2971 cached = talloc(tmp_ctx, bool);
2977 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2981 talloc_steal(ldb, cached);
2982 talloc_free(tmp_ctx);
2986 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2987 talloc_free(tmp_ctx);
2993 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2995 flags are DS_NTDS_OPTION_*
2997 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2999 TALLOC_CTX *tmp_ctx;
3000 const char *attrs[] = { "options", NULL };
3002 struct ldb_result *res;
3004 tmp_ctx = talloc_new(ldb);
3005 if (tmp_ctx == NULL) {
3009 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3010 if (ret != LDB_SUCCESS) {
3014 if (res->count != 1) {
3018 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3020 talloc_free(tmp_ctx);
3025 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3026 talloc_free(tmp_ctx);
3027 return LDB_ERR_NO_SUCH_OBJECT;
3030 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3032 const char *attrs[] = { "objectCategory", NULL };
3034 struct ldb_result *res;
3036 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3037 if (ret != LDB_SUCCESS) {
3041 if (res->count != 1) {
3045 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3048 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3053 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3054 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3056 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3058 char **tokens, *ret;
3061 tokens = str_list_make(mem_ctx, cn, " -_");
3065 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3066 tokens[0][0] = tolower(tokens[0][0]);
3067 for (i = 1; i < str_list_length((const char **)tokens); i++)
3068 tokens[i][0] = toupper(tokens[i][0]);
3070 ret = talloc_strdup(mem_ctx, tokens[0]);
3071 for (i = 1; i < str_list_length((const char **)tokens); i++)
3072 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3074 talloc_free(tokens);
3080 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3082 int dsdb_functional_level(struct ldb_context *ldb)
3084 int *domainFunctionality =
3085 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3086 if (!domainFunctionality) {
3087 /* this is expected during initial provision */
3088 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3089 return DS_DOMAIN_FUNCTION_2000;
3091 return *domainFunctionality;
3095 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3097 int dsdb_forest_functional_level(struct ldb_context *ldb)
3099 int *forestFunctionality =
3100 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3101 if (!forestFunctionality) {
3102 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3103 return DS_DOMAIN_FUNCTION_2000;
3105 return *forestFunctionality;
3109 set a GUID in an extended DN structure
3111 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3117 status = GUID_to_ndr_blob(guid, dn, &v);
3118 if (!NT_STATUS_IS_OK(status)) {
3119 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3122 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3128 return a GUID from a extended DN structure
3130 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3132 const struct ldb_val *v;
3134 v = ldb_dn_get_extended_component(dn, component_name);
3136 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3139 return GUID_from_ndr_blob(v, guid);
3143 return a uint64_t from a extended DN structure
3145 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3147 const struct ldb_val *v;
3150 v = ldb_dn_get_extended_component(dn, component_name);
3152 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3154 s = talloc_strndup(dn, (const char *)v->data, v->length);
3155 NT_STATUS_HAVE_NO_MEMORY(s);
3157 *val = strtoull(s, NULL, 0);
3160 return NT_STATUS_OK;
3164 return a NTTIME from a extended DN structure
3166 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3168 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3172 return a uint32_t from a extended DN structure
3174 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3176 const struct ldb_val *v;
3179 v = ldb_dn_get_extended_component(dn, component_name);
3181 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3184 s = talloc_strndup(dn, (const char *)v->data, v->length);
3185 NT_STATUS_HAVE_NO_MEMORY(s);
3187 *val = strtoul(s, NULL, 0);
3190 return NT_STATUS_OK;
3194 return a dom_sid from a extended DN structure
3196 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3198 const struct ldb_val *sid_blob;
3199 struct TALLOC_CTX *tmp_ctx;
3200 enum ndr_err_code ndr_err;
3202 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3204 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3207 tmp_ctx = talloc_new(NULL);
3209 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3210 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3212 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3213 talloc_free(tmp_ctx);
3217 talloc_free(tmp_ctx);
3218 return NT_STATUS_OK;
3223 return RMD_FLAGS directly from a ldb_dn
3224 returns 0 if not found
3226 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3228 const struct ldb_val *v;
3230 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3231 if (!v || v->length > sizeof(buf)-1) return 0;
3232 strncpy(buf, (const char *)v->data, v->length);
3234 return strtoul(buf, NULL, 10);
3238 return RMD_FLAGS directly from a ldb_val for a DN
3239 returns 0 if RMD_FLAGS is not found
3241 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3247 if (val->length < 13) {
3250 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3254 flags = strtoul(p+11, &end, 10);
3255 if (!end || *end != '>') {
3256 /* it must end in a > */
3263 return true if a ldb_val containing a DN in storage form is deleted
3265 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3267 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3271 return true if a ldb_val containing a DN in storage form is
3272 in the upgraded w2k3 linked attribute format
3274 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3276 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3280 return a DN for a wellknown GUID
3282 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3283 struct ldb_dn *nc_root, const char *wk_guid,
3284 struct ldb_dn **wkguid_dn)
3286 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3287 const char *attrs[] = { NULL };
3290 struct ldb_result *res;
3292 /* construct the magic WKGUID DN */
3293 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3294 wk_guid, ldb_dn_get_linearized(nc_root));
3296 talloc_free(tmp_ctx);
3297 return ldb_operr(samdb);
3300 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3301 DSDB_SEARCH_SHOW_DELETED |
3302 DSDB_SEARCH_SHOW_RECYCLED);
3303 if (ret != LDB_SUCCESS) {
3304 talloc_free(tmp_ctx);
3308 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3309 talloc_free(tmp_ctx);
3314 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3316 return ldb_dn_compare(*dn1, *dn2);
3320 find a NC root given a DN within the NC
3322 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3323 struct ldb_dn **nc_root)
3325 const char *root_attrs[] = { "namingContexts", NULL };
3326 TALLOC_CTX *tmp_ctx;
3328 struct ldb_message_element *el;
3329 struct ldb_result *root_res;
3331 struct ldb_dn **nc_dns;
3333 tmp_ctx = talloc_new(samdb);
3334 if (tmp_ctx == NULL) {
3335 return ldb_oom(samdb);
3338 ret = ldb_search(samdb, tmp_ctx, &root_res,
3339 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3340 if (ret != LDB_SUCCESS) {
3341 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3342 talloc_free(tmp_ctx);
3346 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3348 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3349 ldb_errstring(samdb)));
3350 talloc_free(tmp_ctx);
3351 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3354 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3356 talloc_free(tmp_ctx);
3357 return ldb_oom(samdb);
3360 for (i=0; i<el->num_values; i++) {
3361 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3362 if (nc_dns[i] == NULL) {
3363 talloc_free(tmp_ctx);
3364 return ldb_operr(samdb);
3368 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3370 for (i=0; i<el->num_values; i++) {
3371 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3372 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3373 talloc_free(tmp_ctx);
3378 talloc_free(tmp_ctx);
3379 return LDB_ERR_NO_SUCH_OBJECT;
3384 find the deleted objects DN for any object, by looking for the NC
3385 root, then looking up the wellknown GUID
3387 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3388 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3389 struct ldb_dn **do_dn)
3391 struct ldb_dn *nc_root;
3394 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3395 if (ret != LDB_SUCCESS) {
3399 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3400 talloc_free(nc_root);
3405 return the tombstoneLifetime, in days
3407 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3410 dn = ldb_get_config_basedn(ldb);
3412 return LDB_ERR_NO_SUCH_OBJECT;
3414 dn = ldb_dn_copy(ldb, dn);
3416 return ldb_operr(ldb);
3418 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3419 be a wellknown GUID for this */
3420 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3422 return ldb_operr(ldb);
3425 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3431 compare a ldb_val to a string case insensitively
3433 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3435 size_t len = strlen(s);
3437 if (len > v->length) return 1;
3438 ret = strncasecmp(s, (const char *)v->data, v->length);
3439 if (ret != 0) return ret;
3440 if (v->length > len && v->data[len] != 0) {
3448 load the UDV for a partition in v2 format
3449 The list is returned sorted, and with our local cursor added
3451 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3452 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3454 static const char *attrs[] = { "replUpToDateVector", NULL };
3455 struct ldb_result *r;
3456 const struct ldb_val *ouv_value;
3459 uint64_t highest_usn;
3460 const struct GUID *our_invocation_id;
3461 struct timeval now = timeval_current();
3463 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3464 if (ret != LDB_SUCCESS) {
3468 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3470 enum ndr_err_code ndr_err;
3471 struct replUpToDateVectorBlob ouv;
3473 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3474 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3475 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3477 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3479 if (ouv.version != 2) {
3480 /* we always store as version 2, and
3481 * replUpToDateVector is not replicated
3483 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3486 *count = ouv.ctr.ctr2.count;
3487 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3495 our_invocation_id = samdb_ntds_invocation_id(samdb);
3496 if (!our_invocation_id) {
3497 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3498 talloc_free(*cursors);
3499 return ldb_operr(samdb);
3502 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3503 if (ret != LDB_SUCCESS) {
3504 /* nothing to add - this can happen after a vampire */
3505 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3509 for (i=0; i<*count; i++) {
3510 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3511 (*cursors)[i].highest_usn = highest_usn;
3512 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3513 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3518 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3520 return ldb_oom(samdb);
3523 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3524 (*cursors)[*count].highest_usn = highest_usn;
3525 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3528 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3534 load the UDV for a partition in version 1 format
3535 The list is returned sorted, and with our local cursor added
3537 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3538 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3540 struct drsuapi_DsReplicaCursor2 *v2;
3544 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3545 if (ret != LDB_SUCCESS) {
3555 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3556 if (*cursors == NULL) {
3558 return ldb_oom(samdb);
3561 for (i=0; i<*count; i++) {
3562 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3563 (*cursors)[i].highest_usn = v2[i].highest_usn;
3570 add a set of controls to a ldb_request structure based on a set of
3571 flags. See util.h for a list of available flags
3573 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3576 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3577 struct ldb_search_options_control *options;
3578 /* Using the phantom root control allows us to search all partitions */
3579 options = talloc(req, struct ldb_search_options_control);
3580 if (options == NULL) {
3581 return LDB_ERR_OPERATIONS_ERROR;
3583 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3585 ret = ldb_request_add_control(req,
3586 LDB_CONTROL_SEARCH_OPTIONS_OID,
3588 if (ret != LDB_SUCCESS) {
3593 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3594 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3595 if (ret != LDB_SUCCESS) {
3600 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3601 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3602 if (ret != LDB_SUCCESS) {
3607 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3608 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3609 if (ret != LDB_SUCCESS) {
3614 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3615 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3616 if (!extended_ctrl) {
3617 return LDB_ERR_OPERATIONS_ERROR;
3619 extended_ctrl->type = 1;
3621 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3622 if (ret != LDB_SUCCESS) {
3627 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3628 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3629 if (ret != LDB_SUCCESS) {
3634 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3635 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3636 if (ret != LDB_SUCCESS) {
3641 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3642 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3643 if (ret != LDB_SUCCESS) {
3648 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3649 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3650 if (ret != LDB_SUCCESS) {
3655 if (dsdb_flags & DSDB_TREE_DELETE) {
3656 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3657 if (ret != LDB_SUCCESS) {
3662 if (dsdb_flags & DSDB_PROVISION) {
3663 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
3664 if (ret != LDB_SUCCESS) {
3673 an add with a set of controls
3675 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3676 uint32_t dsdb_flags)
3678 struct ldb_request *req;
3681 ret = ldb_build_add_req(&req, ldb, ldb,
3685 ldb_op_default_callback,
3688 if (ret != LDB_SUCCESS) return ret;
3690 ret = dsdb_request_add_controls(req, dsdb_flags);
3691 if (ret != LDB_SUCCESS) {
3696 ret = dsdb_autotransaction_request(ldb, req);
3703 a modify with a set of controls
3705 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3706 uint32_t dsdb_flags)
3708 struct ldb_request *req;
3711 ret = ldb_build_mod_req(&req, ldb, ldb,
3715 ldb_op_default_callback,
3718 if (ret != LDB_SUCCESS) return ret;
3720 ret = dsdb_request_add_controls(req, dsdb_flags);
3721 if (ret != LDB_SUCCESS) {
3726 ret = dsdb_autotransaction_request(ldb, req);
3733 like dsdb_modify() but set all the element flags to
3734 LDB_FLAG_MOD_REPLACE
3736 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3740 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3741 for (i=0;i<msg->num_elements;i++) {
3742 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3745 return dsdb_modify(ldb, msg, dsdb_flags);
3750 search for attrs on one DN, allowing for dsdb_flags controls
3752 int dsdb_search_dn(struct ldb_context *ldb,
3753 TALLOC_CTX *mem_ctx,
3754 struct ldb_result **_res,
3755 struct ldb_dn *basedn,
3756 const char * const *attrs,
3757 uint32_t dsdb_flags)
3760 struct ldb_request *req;
3761 struct ldb_result *res;
3763 res = talloc_zero(mem_ctx, struct ldb_result);
3765 return ldb_oom(ldb);
3768 ret = ldb_build_search_req(&req, ldb, res,
3775 ldb_search_default_callback,
3777 if (ret != LDB_SUCCESS) {
3782 ret = dsdb_request_add_controls(req, dsdb_flags);
3783 if (ret != LDB_SUCCESS) {
3788 ret = ldb_request(ldb, req);
3789 if (ret == LDB_SUCCESS) {
3790 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3794 if (ret != LDB_SUCCESS) {
3804 search for attrs on one DN, by the GUID of the DN, allowing for
3807 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3808 TALLOC_CTX *mem_ctx,
3809 struct ldb_result **_res,
3810 const struct GUID *guid,
3811 const char * const *attrs,
3812 uint32_t dsdb_flags)
3814 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3818 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3819 if (!ldb_dn_validate(dn)) {
3820 talloc_free(tmp_ctx);
3821 return LDB_ERR_INVALID_DN_SYNTAX;
3824 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3825 talloc_free(tmp_ctx);
3830 general search with dsdb_flags for controls
3832 int dsdb_search(struct ldb_context *ldb,
3833 TALLOC_CTX *mem_ctx,
3834 struct ldb_result **_res,
3835 struct ldb_dn *basedn,
3836 enum ldb_scope scope,
3837 const char * const *attrs,
3838 uint32_t dsdb_flags,
3839 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3842 struct ldb_request *req;
3843 struct ldb_result *res;
3845 char *expression = NULL;
3846 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3848 res = talloc_zero(tmp_ctx, struct ldb_result);
3850 talloc_free(tmp_ctx);
3851 return ldb_oom(ldb);
3855 va_start(ap, exp_fmt);
3856 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3860 talloc_free(tmp_ctx);
3861 return ldb_oom(ldb);
3865 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3872 ldb_search_default_callback,
3874 if (ret != LDB_SUCCESS) {
3875 talloc_free(tmp_ctx);
3879 ret = dsdb_request_add_controls(req, dsdb_flags);
3880 if (ret != LDB_SUCCESS) {
3881 talloc_free(tmp_ctx);
3882 ldb_reset_err_string(ldb);
3886 ret = ldb_request(ldb, req);
3887 if (ret == LDB_SUCCESS) {
3888 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3891 if (ret != LDB_SUCCESS) {
3892 talloc_free(tmp_ctx);
3896 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3897 if (res->count == 0) {
3898 talloc_free(tmp_ctx);
3899 ldb_reset_err_string(ldb);
3900 return LDB_ERR_NO_SUCH_OBJECT;
3902 if (res->count != 1) {
3903 talloc_free(tmp_ctx);
3904 ldb_reset_err_string(ldb);
3905 return LDB_ERR_CONSTRAINT_VIOLATION;
3909 *_res = talloc_steal(mem_ctx, res);
3910 talloc_free(tmp_ctx);
3917 general search with dsdb_flags for controls
3918 returns exactly 1 record or an error
3920 int dsdb_search_one(struct ldb_context *ldb,
3921 TALLOC_CTX *mem_ctx,
3922 struct ldb_message **msg,
3923 struct ldb_dn *basedn,
3924 enum ldb_scope scope,
3925 const char * const *attrs,
3926 uint32_t dsdb_flags,
3927 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3930 struct ldb_result *res;
3932 char *expression = NULL;
3933 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3935 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3937 res = talloc_zero(tmp_ctx, struct ldb_result);
3939 talloc_free(tmp_ctx);
3940 return ldb_oom(ldb);
3944 va_start(ap, exp_fmt);
3945 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3949 talloc_free(tmp_ctx);
3950 return ldb_oom(ldb);
3952 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3953 dsdb_flags, "%s", expression);
3955 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3959 if (ret != LDB_SUCCESS) {
3960 talloc_free(tmp_ctx);
3964 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3965 talloc_free(tmp_ctx);
3970 /* returns back the forest DNS name */
3971 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3973 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3974 ldb_get_root_basedn(ldb));
3977 if (forest_name == NULL) {
3981 p = strchr(forest_name, '/');
3990 validate that an DSA GUID belongs to the specified user sid.
3991 The user SID must be a domain controller account (either RODC or
3994 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3995 const struct GUID *dsa_guid,
3996 const struct dom_sid *sid)
3999 - find DN of record with the DSA GUID in the
4000 configuration partition (objectGUID)
4001 - remove "NTDS Settings" component from DN
4002 - do a base search on that DN for serverReference with
4004 - extract objectSid from resulting serverReference
4006 - check this sid matches the sid argument
4008 struct ldb_dn *config_dn;
4009 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4010 struct ldb_message *msg;
4011 const char *attrs1[] = { NULL };
4012 const char *attrs2[] = { "serverReference", NULL };
4014 struct ldb_dn *dn, *account_dn;
4015 struct dom_sid sid2;
4018 config_dn = ldb_get_config_basedn(ldb);
4020 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4021 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4022 if (ret != LDB_SUCCESS) {
4023 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4024 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4025 talloc_free(tmp_ctx);
4026 return ldb_operr(ldb);
4030 if (!ldb_dn_remove_child_components(dn, 1)) {
4031 talloc_free(tmp_ctx);
4032 return ldb_operr(ldb);
4035 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4036 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4037 "(objectClass=server)");
4038 if (ret != LDB_SUCCESS) {
4039 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4040 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4041 talloc_free(tmp_ctx);
4042 return ldb_operr(ldb);
4045 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4046 if (account_dn == NULL) {
4047 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4048 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4049 talloc_free(tmp_ctx);
4050 return ldb_operr(ldb);
4053 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4054 if (!NT_STATUS_IS_OK(status)) {
4055 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4056 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4057 talloc_free(tmp_ctx);
4058 return ldb_operr(ldb);
4061 if (!dom_sid_equal(sid, &sid2)) {
4062 /* someone is trying to spoof another account */
4063 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4064 GUID_string(tmp_ctx, dsa_guid),
4065 dom_sid_string(tmp_ctx, sid),
4066 dom_sid_string(tmp_ctx, &sid2)));
4067 talloc_free(tmp_ctx);
4068 return ldb_operr(ldb);
4071 talloc_free(tmp_ctx);
4075 static const char *secret_attributes[] = {
4078 "initialAuthIncoming",
4079 "initialAuthOutgoing",
4083 "supplementalCredentials",
4084 "trustAuthIncoming",
4085 "trustAuthOutgoing",
4091 check if the attribute belongs to the RODC filtered attribute set
4092 Note that attributes that are in the filtered attribute set are the
4093 ones that _are_ always sent to a RODC
4095 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4097 /* they never get secret attributes */
4098 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4102 /* they do get non-secret critical attributes */
4103 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4107 /* they do get non-secret attributes marked as being in the FAS */
4108 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4112 /* other attributes are denied */
4116 /* return fsmo role dn and role owner dn for a particular role*/
4117 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4118 struct ldb_context *ldb,
4120 struct ldb_dn **fsmo_role_dn,
4121 struct ldb_dn **role_owner_dn)
4125 case DREPL_NAMING_MASTER:
4126 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4127 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4128 if (ret != LDB_SUCCESS) {
4129 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4130 ldb_errstring(ldb)));
4131 talloc_free(tmp_ctx);
4132 return WERR_DS_DRA_INTERNAL_ERROR;
4135 case DREPL_INFRASTRUCTURE_MASTER:
4136 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4137 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4138 if (ret != LDB_SUCCESS) {
4139 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4140 ldb_errstring(ldb)));
4141 talloc_free(tmp_ctx);
4142 return WERR_DS_DRA_INTERNAL_ERROR;
4145 case DREPL_RID_MASTER:
4146 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4147 if (ret != LDB_SUCCESS) {
4148 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4149 talloc_free(tmp_ctx);
4150 return WERR_DS_DRA_INTERNAL_ERROR;
4153 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4154 if (ret != LDB_SUCCESS) {
4155 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4156 ldb_errstring(ldb)));
4157 talloc_free(tmp_ctx);
4158 return WERR_DS_DRA_INTERNAL_ERROR;
4161 case DREPL_SCHEMA_MASTER:
4162 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4163 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4164 if (ret != LDB_SUCCESS) {
4165 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4166 ldb_errstring(ldb)));
4167 talloc_free(tmp_ctx);
4168 return WERR_DS_DRA_INTERNAL_ERROR;
4171 case DREPL_PDC_MASTER:
4172 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4173 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4174 if (ret != LDB_SUCCESS) {
4175 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4176 ldb_errstring(ldb)));
4177 talloc_free(tmp_ctx);
4178 return WERR_DS_DRA_INTERNAL_ERROR;
4182 return WERR_DS_DRA_INTERNAL_ERROR;
4187 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4188 TALLOC_CTX *mem_ctx,
4189 struct ldb_dn *server_dn)
4192 struct ldb_result *res = NULL;
4193 const char * const attrs[] = { "dNSHostName", NULL};
4195 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4199 if (ldb_ret != LDB_SUCCESS) {
4200 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4201 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4205 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4209 returns true if an attribute is in the filter,
4210 false otherwise, provided that attribute value is provided with the expression
4212 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4216 switch (tree->operation) {
4219 for (i=0;i<tree->u.list.num_elements;i++) {
4220 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4226 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4227 case LDB_OP_EQUALITY:
4228 case LDB_OP_GREATER:
4231 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4235 case LDB_OP_SUBSTRING:
4236 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4240 case LDB_OP_PRESENT:
4241 /* (attrname=*) is not filtered out */
4243 case LDB_OP_EXTENDED:
4244 if (tree->u.extended.attr &&
4245 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4253 bool is_attr_in_list(const char * const * attrs, const char *attr)
4257 for (i = 0; attrs[i]; i++) {
4258 if (ldb_attr_cmp(attrs[i], attr) == 0)