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 "dsdb/samdb/ldb_modules/util.h"
46 #include "librpc/gen_ndr/irpc.h"
49 search the sam for the specified attributes in a specific domain, filter on
50 objectSid being in domain_sid.
52 int samdb_search_domain(struct ldb_context *sam_ldb,
54 struct ldb_dn *basedn,
55 struct ldb_message ***res,
56 const char * const *attrs,
57 const struct dom_sid *domain_sid,
58 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
64 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
65 res, attrs, format, ap);
71 struct dom_sid *entry_sid;
73 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
75 if ((entry_sid == NULL) ||
76 (!dom_sid_in_domain(domain_sid, entry_sid))) {
77 /* Delete that entry from the result set */
78 (*res)[i] = (*res)[count-1];
80 talloc_free(entry_sid);
83 talloc_free(entry_sid);
91 search the sam for a single string attribute in exactly 1 record
93 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
95 struct ldb_dn *basedn,
96 const char *attr_name,
97 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
100 const char *attrs[2] = { NULL, NULL };
101 struct ldb_message **res = NULL;
103 attrs[0] = attr_name;
105 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
107 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
108 attr_name, format, count));
115 return samdb_result_string(res[0], attr_name, NULL);
119 search the sam for a single string attribute in exactly 1 record
121 const char *samdb_search_string(struct ldb_context *sam_ldb,
123 struct ldb_dn *basedn,
124 const char *attr_name,
125 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
130 va_start(ap, format);
131 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
137 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
139 struct ldb_dn *basedn,
140 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
144 struct ldb_message **res = NULL;
147 va_start(ap, format);
148 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
151 if (count != 1) return NULL;
153 ret = talloc_steal(mem_ctx, res[0]->dn);
160 search the sam for a dom_sid attribute in exactly 1 record
162 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
164 struct ldb_dn *basedn,
165 const char *attr_name,
166 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
170 struct ldb_message **res;
171 const char *attrs[2] = { NULL, NULL };
174 attrs[0] = attr_name;
176 va_start(ap, format);
177 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
180 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
181 attr_name, format, count));
187 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
193 return the count of the number of records in the sam matching the query
195 int samdb_search_count(struct ldb_context *sam_ldb,
196 struct ldb_dn *basedn,
197 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
200 struct ldb_message **res;
201 const char *attrs[] = { NULL };
203 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
205 va_start(ap, format);
206 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
208 talloc_free(tmp_ctx);
215 search the sam for a single integer attribute in exactly 1 record
217 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
219 unsigned int default_value,
220 struct ldb_dn *basedn,
221 const char *attr_name,
222 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
226 struct ldb_message **res;
227 const char *attrs[2] = { NULL, NULL };
229 attrs[0] = attr_name;
231 va_start(ap, format);
232 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
236 return default_value;
239 return samdb_result_uint(res[0], attr_name, default_value);
243 search the sam for a single signed 64 bit integer attribute in exactly 1 record
245 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
247 int64_t default_value,
248 struct ldb_dn *basedn,
249 const char *attr_name,
250 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
254 struct ldb_message **res;
255 const char *attrs[2] = { NULL, NULL };
257 attrs[0] = attr_name;
259 va_start(ap, format);
260 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
264 return default_value;
267 return samdb_result_int64(res[0], attr_name, default_value);
271 search the sam for multipe records each giving a single string attribute
272 return the number of matches, or -1 on error
274 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
276 struct ldb_dn *basedn,
278 const char *attr_name,
279 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
283 const char *attrs[2] = { NULL, NULL };
284 struct ldb_message **res = NULL;
286 attrs[0] = attr_name;
288 va_start(ap, format);
289 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
296 /* make sure its single valued */
297 for (i=0;i<count;i++) {
298 if (res[i]->num_elements != 1) {
299 DEBUG(1,("samdb: search for %s %s not single valued\n",
306 *strs = talloc_array(mem_ctx, const char *, count+1);
312 for (i=0;i<count;i++) {
313 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
315 (*strs)[count] = NULL;
321 pull a uint from a result set.
323 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
325 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
329 pull a (signed) int64 from a result set.
331 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
333 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
337 pull a string from a result set.
339 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
340 const char *default_value)
342 return ldb_msg_find_attr_as_string(msg, attr, default_value);
345 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
346 const char *attr, struct ldb_dn *default_value)
348 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
350 return default_value;
356 pull a rid from a objectSid in a result set.
358 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
359 const char *attr, uint32_t default_value)
364 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
366 return default_value;
368 rid = sid->sub_auths[sid->num_auths-1];
374 pull a dom_sid structure from a objectSid in a result set.
376 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
379 const struct ldb_val *v;
381 enum ndr_err_code ndr_err;
382 v = ldb_msg_find_ldb_val(msg, attr);
386 sid = talloc(mem_ctx, struct dom_sid);
390 ndr_err = ndr_pull_struct_blob(v, sid, sid,
391 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
400 pull a guid structure from a objectGUID in a result set.
402 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
404 const struct ldb_val *v;
408 v = ldb_msg_find_ldb_val(msg, attr);
409 if (!v) return GUID_zero();
411 status = GUID_from_ndr_blob(v, &guid);
412 if (!NT_STATUS_IS_OK(status)) {
420 pull a sid prefix from a objectSid in a result set.
421 this is used to find the domain sid for a user
423 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
426 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
427 if (!sid || sid->num_auths < 1) return NULL;
433 pull a NTTIME in a result set.
435 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
436 NTTIME default_value)
438 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
442 * Windows stores 0 for lastLogoff.
443 * But when a MS DC return the lastLogoff (as Logoff Time)
444 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
445 * cause windows 2008 and newer version to fail for SMB requests
447 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
449 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
452 ret = 0x7FFFFFFFFFFFFFFFULL;
458 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
459 * indicate an account doesn't expire.
461 * When Windows initially creates an account, it sets
462 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
463 * when changing from an account having a specific expiration date to
464 * that account never expiring, it sets accountExpires = 0.
466 * Consolidate that logic here to allow clearer logic for account expiry in
467 * the rest of the code.
469 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
471 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
475 ret = 0x7FFFFFFFFFFFFFFFULL;
481 pull a uint64_t from a result set.
483 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
484 uint64_t default_value)
486 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
491 construct the allow_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
496 struct ldb_dn *domain_dn,
497 struct ldb_message *msg,
500 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
503 if (attr_time == 0) {
507 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
509 /* yes, this is a -= not a += as minPwdAge is stored as the negative
510 of the number of 100-nano-seconds */
511 attr_time -= minPwdAge;
517 construct the force_password_change field from the PwdLastSet
518 attribute, the userAccountControl and the domain password settings
520 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
522 struct ldb_dn *domain_dn,
523 struct ldb_message *msg)
525 int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
526 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
527 "userAccountControl",
531 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
532 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
533 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
534 return 0x7FFFFFFFFFFFFFFFULL;
537 if (attr_time == 0) {
540 if (attr_time == -1) {
541 return 0x7FFFFFFFFFFFFFFFULL;
544 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
546 if (maxPwdAge == 0) {
547 return 0x7FFFFFFFFFFFFFFFULL;
549 attr_time -= maxPwdAge;
556 pull a samr_Password structutre from a result set.
558 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
560 struct samr_Password *hash = NULL;
561 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
562 if (val && (val->length >= sizeof(hash->hash))) {
563 hash = talloc(mem_ctx, struct samr_Password);
564 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
570 pull an array of samr_Password structures from a result set.
572 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
573 const char *attr, struct samr_Password **hashes)
575 unsigned int count, i;
576 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
582 count = val->length / 16;
587 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
592 for (i=0;i<count;i++) {
593 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
599 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
600 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
602 struct samr_Password *lmPwdHash, *ntPwdHash;
605 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
608 } else if (num_nt > 1) {
609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
611 *nt_pwd = &ntPwdHash[0];
615 /* Ensure that if we have turned off LM
616 * authentication, that we never use the LM hash, even
618 if (lpcfg_lanman_auth(lp_ctx)) {
620 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
623 } else if (num_lm > 1) {
624 return NT_STATUS_INTERNAL_DB_CORRUPTION;
626 *lm_pwd = &lmPwdHash[0];
636 pull a samr_LogonHours structutre from a result set.
638 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
640 struct samr_LogonHours hours;
641 size_t units_per_week = 168;
642 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
647 units_per_week = val->length * 8;
650 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
654 hours.units_per_week = units_per_week;
655 memset(hours.bits, 0xFF, units_per_week/8);
657 memcpy(hours.bits, val->data, val->length);
664 pull a set of account_flags from a result set.
666 This requires that the attributes:
671 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
672 struct ldb_message *msg, struct ldb_dn *domain_dn)
674 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
675 uint32_t acct_flags = ds_uf2acb(userAccountControl);
676 NTTIME must_change_time;
679 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
682 /* Test account expire time */
683 unix_to_nt_time(&now, time(NULL));
684 /* check for expired password */
685 if (must_change_time < now) {
686 acct_flags |= ACB_PW_EXPIRED;
691 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
692 struct ldb_message *msg,
695 struct lsa_BinaryString s;
696 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
704 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
708 s.length = s.size = val->length;
709 memcpy(s.array, val->data, val->length);
714 /* Find an attribute, with a particular value */
716 /* The current callers of this function expect a very specific
717 * behaviour: In particular, objectClass subclass equivilance is not
718 * wanted. This means that we should not lookup the schema for the
719 * comparison function */
720 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
721 const struct ldb_message *msg,
722 const char *name, const char *value)
725 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
731 for (i=0;i<el->num_values;i++) {
732 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
741 * This is intended for use by the "password hash" module since there
742 * password changes can be specified through one message element with the
743 * new password (to set) and another one with the old password (to unset).
745 * The first which sets a password (new value) can have flags
746 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
747 * for entries). The latter (old value) has always specified
748 * LDB_FLAG_MOD_DELETE.
750 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
751 * doesn't contain only one value (this is the Windows Server behaviour)
752 * otherwise LDB_SUCCESS.
754 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
756 const struct ldb_val **new_val,
757 const struct ldb_val **old_val)
768 for (i = 0; i < msg->num_elements; i++) {
769 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
770 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
771 *old_val = &msg->elements[i].values[0];
773 *new_val = &msg->elements[i].values[0];
781 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
783 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
784 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
789 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
791 struct ldb_message_element *el;
793 el = ldb_msg_find_element(msg, name);
798 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
804 add a string element to a message
806 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
807 const char *attr_name, const char *str)
809 char *s = talloc_strdup(mem_ctx, str);
810 char *a = talloc_strdup(mem_ctx, attr_name);
811 if (s == NULL || a == NULL) {
812 return ldb_oom(sam_ldb);
814 return ldb_msg_add_string(msg, a, s);
818 add a dom_sid element to a message
820 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, struct dom_sid *sid)
824 enum ndr_err_code ndr_err;
826 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
828 (ndr_push_flags_fn_t)ndr_push_dom_sid);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 return ldb_operr(sam_ldb);
832 return ldb_msg_add_value(msg, attr_name, &v, NULL);
837 add a delete element operation to a message
839 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name)
842 /* we use an empty replace rather than a delete, as it allows for
843 dsdb_replace() to be used everywhere */
844 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
848 add an add attribute value to a message or enhance an existing attribute
849 which has the same name and the add flag set.
851 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
852 struct ldb_message *msg, const char *attr_name,
855 struct ldb_message_element *el;
856 struct ldb_val val, *vals;
862 v = talloc_strdup(mem_ctx, value);
864 return ldb_oom(sam_ldb);
867 val.data = (uint8_t *) v;
868 val.length = strlen(v);
870 if (val.length == 0) {
871 /* allow empty strings as non-existent attributes */
875 for (i = 0; i < msg->num_elements; i++) {
876 el = &msg->elements[i];
877 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
878 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
884 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
886 if (ret != LDB_SUCCESS) {
891 vals = talloc_realloc(msg, el->values, struct ldb_val,
894 return ldb_oom(sam_ldb);
897 el->values[el->num_values] = val;
904 add a delete attribute value to a message or enhance an existing attribute
905 which has the same name and the delete flag set.
907 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
908 struct ldb_message *msg, const char *attr_name,
911 struct ldb_message_element *el;
912 struct ldb_val val, *vals;
918 v = talloc_strdup(mem_ctx, value);
920 return ldb_oom(sam_ldb);
923 val.data = (uint8_t *) v;
924 val.length = strlen(v);
926 if (val.length == 0) {
927 /* allow empty strings as non-existent attributes */
931 for (i = 0; i < msg->num_elements; i++) {
932 el = &msg->elements[i];
933 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
934 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
940 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
942 if (ret != LDB_SUCCESS) {
947 vals = talloc_realloc(msg, el->values, struct ldb_val,
950 return ldb_oom(sam_ldb);
953 el->values[el->num_values] = val;
960 add a int element to a message
962 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, int v)
965 const char *s = talloc_asprintf(mem_ctx, "%d", v);
966 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
970 add a unsigned int element to a message
972 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
973 const char *attr_name, unsigned int v)
975 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
979 add a (signed) int64_t element to a message
981 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
982 const char *attr_name, int64_t v)
984 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
985 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
989 add a uint64_t element to a message
991 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992 const char *attr_name, uint64_t v)
994 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
998 add a samr_Password element to a message
1000 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001 const char *attr_name, const struct samr_Password *hash)
1004 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1006 return ldb_oom(sam_ldb);
1009 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1013 add a samr_Password array to a message
1015 int samdb_msg_add_hashes(struct ldb_context *ldb,
1016 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1017 const char *attr_name, struct samr_Password *hashes,
1022 val.data = talloc_array_size(mem_ctx, 16, count);
1023 val.length = count*16;
1025 return ldb_oom(ldb);
1027 for (i=0;i<count;i++) {
1028 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1030 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1034 add a acct_flags element to a message
1036 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037 const char *attr_name, uint32_t v)
1039 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1043 add a logon_hours element to a message
1045 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1046 const char *attr_name, struct samr_LogonHours *hours)
1049 val.length = hours->units_per_week / 8;
1050 val.data = hours->bits;
1051 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1055 add a parameters element to a message
1057 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1058 const char *attr_name, struct lsa_BinaryString *parameters)
1061 val.length = parameters->length;
1062 val.data = (uint8_t *)parameters->array;
1063 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1066 add a general value element to a message
1068 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1069 const char *attr_name, const struct ldb_val *val)
1071 return ldb_msg_add_value(msg, attr_name, val, NULL);
1075 sets a general value element to a message
1077 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1078 const char *attr_name, const struct ldb_val *val)
1080 struct ldb_message_element *el;
1082 el = ldb_msg_find_element(msg, attr_name);
1086 return ldb_msg_add_value(msg, attr_name, val, NULL);
1090 set a string element in a message
1092 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1093 const char *attr_name, const char *str)
1095 struct ldb_message_element *el;
1097 el = ldb_msg_find_element(msg, attr_name);
1101 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1105 * sets a signed integer in a message
1107 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1108 struct ldb_message *msg, const char *attr_name, int v)
1110 struct ldb_message_element *el;
1112 el = ldb_msg_find_element(msg, attr_name);
1116 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1120 * sets an unsigned integer in a message
1122 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1123 struct ldb_message *msg, const char *attr_name,
1126 struct ldb_message_element *el;
1128 el = ldb_msg_find_element(msg, attr_name);
1132 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1136 * Handle ldb_request in transaction
1138 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1139 struct ldb_request *req)
1143 ret = ldb_transaction_start(sam_ldb);
1144 if (ret != LDB_SUCCESS) {
1148 ret = ldb_request(sam_ldb, req);
1149 if (ret == LDB_SUCCESS) {
1150 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1153 if (ret == LDB_SUCCESS) {
1154 return ldb_transaction_commit(sam_ldb);
1156 ldb_transaction_cancel(sam_ldb);
1162 return a default security descriptor
1164 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1166 struct security_descriptor *sd;
1168 sd = security_descriptor_initialise(mem_ctx);
1173 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1175 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1176 struct ldb_dn *aggregate_dn;
1181 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1182 if (!aggregate_dn) {
1185 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1188 return aggregate_dn;
1191 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1193 struct ldb_dn *new_dn;
1195 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1196 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1197 talloc_free(new_dn);
1203 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1205 struct ldb_dn *new_dn;
1207 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1208 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1209 talloc_free(new_dn);
1215 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1217 struct ldb_dn *new_dn;
1219 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1220 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1221 talloc_free(new_dn);
1228 work out the domain sid for the current open ldb
1230 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1232 TALLOC_CTX *tmp_ctx;
1233 const struct dom_sid *domain_sid;
1234 const char *attrs[] = {
1238 struct ldb_result *res;
1241 /* see if we have a cached copy */
1242 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1247 tmp_ctx = talloc_new(ldb);
1248 if (tmp_ctx == NULL) {
1252 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1254 if (ret != LDB_SUCCESS) {
1258 if (res->count != 1) {
1262 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1263 if (domain_sid == NULL) {
1267 /* cache the domain_sid in the ldb */
1268 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1272 talloc_steal(ldb, domain_sid);
1273 talloc_free(tmp_ctx);
1278 talloc_free(tmp_ctx);
1283 get domain sid from cache
1285 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1287 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1290 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1292 TALLOC_CTX *tmp_ctx;
1293 struct dom_sid *dom_sid_new;
1294 struct dom_sid *dom_sid_old;
1296 /* see if we have a cached copy */
1297 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1298 "cache.domain_sid"), struct dom_sid);
1300 tmp_ctx = talloc_new(ldb);
1301 if (tmp_ctx == NULL) {
1305 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1310 /* cache the domain_sid in the ldb */
1311 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1315 talloc_steal(ldb, dom_sid_new);
1316 talloc_free(tmp_ctx);
1317 talloc_free(dom_sid_old);
1322 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1323 talloc_free(tmp_ctx);
1327 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1329 TALLOC_CTX *tmp_ctx;
1330 struct ldb_dn *ntds_settings_dn_new;
1331 struct ldb_dn *ntds_settings_dn_old;
1333 /* see if we have a cached copy */
1334 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1335 "cache.ntds_settings_dn"), struct ldb_dn);
1337 tmp_ctx = talloc_new(ldb);
1338 if (tmp_ctx == NULL) {
1342 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1343 if (!ntds_settings_dn_new) {
1347 /* cache the domain_sid in the ldb */
1348 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1352 talloc_steal(ldb, ntds_settings_dn_new);
1353 talloc_free(tmp_ctx);
1354 talloc_free(ntds_settings_dn_old);
1359 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1360 talloc_free(tmp_ctx);
1364 /* Obtain the short name of the flexible single master operator
1365 * (FSMO), such as the PDC Emulator */
1366 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1369 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1370 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1371 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1372 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1374 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1375 /* Ensure this matches the format. This gives us a
1376 * bit more confidence that a 'cn' value will be a
1381 return (char *)val->data;
1387 work out the ntds settings dn for the current open ldb
1389 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1391 TALLOC_CTX *tmp_ctx;
1392 const char *root_attrs[] = { "dsServiceName", NULL };
1394 struct ldb_result *root_res;
1395 struct ldb_dn *settings_dn;
1397 /* see if we have a cached copy */
1398 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1403 tmp_ctx = talloc_new(ldb);
1404 if (tmp_ctx == NULL) {
1408 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1410 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1411 ldb_errstring(ldb)));
1415 if (root_res->count != 1) {
1419 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1421 /* cache the domain_sid in the ldb */
1422 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1426 talloc_steal(ldb, settings_dn);
1427 talloc_free(tmp_ctx);
1432 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1433 talloc_free(tmp_ctx);
1438 work out the ntds settings invocationId for the current open ldb
1440 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1442 TALLOC_CTX *tmp_ctx;
1443 const char *attrs[] = { "invocationId", NULL };
1445 struct ldb_result *res;
1446 struct GUID *invocation_id;
1448 /* see if we have a cached copy */
1449 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1450 if (invocation_id) {
1451 return invocation_id;
1454 tmp_ctx = talloc_new(ldb);
1455 if (tmp_ctx == NULL) {
1459 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1464 if (res->count != 1) {
1468 invocation_id = talloc(tmp_ctx, struct GUID);
1469 if (!invocation_id) {
1473 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1475 /* cache the domain_sid in the ldb */
1476 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1480 talloc_steal(ldb, invocation_id);
1481 talloc_free(tmp_ctx);
1483 return invocation_id;
1486 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1487 talloc_free(tmp_ctx);
1491 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1493 TALLOC_CTX *tmp_ctx;
1494 struct GUID *invocation_id_new;
1495 struct GUID *invocation_id_old;
1497 /* see if we have a cached copy */
1498 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1499 "cache.invocation_id");
1501 tmp_ctx = talloc_new(ldb);
1502 if (tmp_ctx == NULL) {
1506 invocation_id_new = talloc(tmp_ctx, struct GUID);
1507 if (!invocation_id_new) {
1511 *invocation_id_new = *invocation_id_in;
1513 /* cache the domain_sid in the ldb */
1514 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1518 talloc_steal(ldb, invocation_id_new);
1519 talloc_free(tmp_ctx);
1520 talloc_free(invocation_id_old);
1525 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1526 talloc_free(tmp_ctx);
1531 work out the ntds settings objectGUID for the current open ldb
1533 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1535 TALLOC_CTX *tmp_ctx;
1536 const char *attrs[] = { "objectGUID", NULL };
1538 struct ldb_result *res;
1539 struct GUID *ntds_guid;
1541 /* see if we have a cached copy */
1542 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1547 tmp_ctx = talloc_new(ldb);
1548 if (tmp_ctx == NULL) {
1552 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1557 if (res->count != 1) {
1561 ntds_guid = talloc(tmp_ctx, struct GUID);
1566 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1568 /* cache the domain_sid in the ldb */
1569 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1573 talloc_steal(ldb, ntds_guid);
1574 talloc_free(tmp_ctx);
1579 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1580 talloc_free(tmp_ctx);
1584 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1586 TALLOC_CTX *tmp_ctx;
1587 struct GUID *ntds_guid_new;
1588 struct GUID *ntds_guid_old;
1590 /* see if we have a cached copy */
1591 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1593 tmp_ctx = talloc_new(ldb);
1594 if (tmp_ctx == NULL) {
1598 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1599 if (!ntds_guid_new) {
1603 *ntds_guid_new = *ntds_guid_in;
1605 /* cache the domain_sid in the ldb */
1606 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1610 talloc_steal(ldb, ntds_guid_new);
1611 talloc_free(tmp_ctx);
1612 talloc_free(ntds_guid_old);
1617 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1618 talloc_free(tmp_ctx);
1623 work out the server dn for the current open ldb
1625 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1627 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1631 work out the server dn for the current open ldb
1633 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1635 struct ldb_dn *server_dn;
1636 struct ldb_dn *servers_dn;
1637 struct ldb_dn *server_site_dn;
1639 /* TODO: there must be a saner way to do this!! */
1640 server_dn = samdb_server_dn(ldb, mem_ctx);
1641 if (!server_dn) return NULL;
1643 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1644 talloc_free(server_dn);
1645 if (!servers_dn) return NULL;
1647 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1648 talloc_free(servers_dn);
1650 return server_site_dn;
1654 find the site name from a computers DN record
1656 int samdb_find_site_for_computer(struct ldb_context *ldb,
1657 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1658 const char **site_name)
1662 const struct ldb_val *rdn_val;
1666 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1667 if (ret != LDB_SUCCESS) {
1671 if (!ldb_dn_remove_child_components(dn, 2)) {
1673 return LDB_ERR_INVALID_DN_SYNTAX;
1675 rdn_val = ldb_dn_get_rdn_val(dn);
1676 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1679 return LDB_ERR_OPERATIONS_ERROR;
1685 find the NTDS GUID from a computers DN record
1687 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1688 struct GUID *ntds_guid)
1693 *ntds_guid = GUID_zero();
1695 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1696 if (ret != LDB_SUCCESS) {
1700 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1702 return LDB_ERR_OPERATIONS_ERROR;
1705 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1711 find a 'reference' DN that points at another object
1712 (eg. serverReference, rIDManagerReference etc)
1714 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1715 const char *attribute, struct ldb_dn **dn)
1717 const char *attrs[2];
1718 struct ldb_result *res;
1721 attrs[0] = attribute;
1724 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1725 if (ret != LDB_SUCCESS) {
1729 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1731 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1732 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1733 ldb_dn_get_linearized(base));
1735 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1736 ldb_dn_get_linearized(base));
1739 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1747 find our machine account via the serverReference attribute in the
1750 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1752 struct ldb_dn *server_dn;
1755 server_dn = samdb_server_dn(ldb, mem_ctx);
1756 if (server_dn == NULL) {
1757 return LDB_ERR_NO_SUCH_OBJECT;
1760 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1761 talloc_free(server_dn);
1767 find the RID Manager$ DN via the rIDManagerReference attribute in the
1770 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1772 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1773 "rIDManagerReference", dn);
1777 find the RID Set DN via the rIDSetReferences attribute in our
1780 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1782 struct ldb_dn *server_ref_dn;
1785 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1786 if (ret != LDB_SUCCESS) {
1789 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1790 talloc_free(server_ref_dn);
1794 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1796 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1803 return (const char *) val->data;
1807 * Finds the client site by using the client's IP address.
1808 * The "subnet_name" returns the name of the subnet if parameter != NULL
1810 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1811 const char *ip_address, char **subnet_name)
1813 const char *attrs[] = { "cn", "siteObject", NULL };
1814 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1815 struct ldb_result *res;
1816 const struct ldb_val *val;
1817 const char *site_name = NULL, *l_subnet_name = NULL;
1818 const char *allow_list[2] = { NULL, NULL };
1819 unsigned int i, count;
1823 * if we don't have a client ip e.g. ncalrpc
1824 * the server site is the client site
1826 if (ip_address == NULL) {
1827 return samdb_server_site_name(ldb, mem_ctx);
1830 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1831 if (sites_container_dn == NULL) {
1835 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1836 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1837 talloc_free(sites_container_dn);
1838 talloc_free(subnets_dn);
1842 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1844 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1846 } else if (ret != LDB_SUCCESS) {
1847 talloc_free(sites_container_dn);
1848 talloc_free(subnets_dn);
1854 for (i = 0; i < count; i++) {
1855 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1858 allow_list[0] = l_subnet_name;
1860 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1861 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1864 if (sites_dn == NULL) {
1865 /* No reference, maybe another subnet matches */
1869 /* "val" cannot be NULL here since "sites_dn" != NULL */
1870 val = ldb_dn_get_rdn_val(sites_dn);
1871 site_name = talloc_strdup(mem_ctx,
1872 (const char *) val->data);
1874 talloc_free(sites_dn);
1880 if (site_name == NULL) {
1881 /* This is the Windows Server fallback rule: when no subnet
1882 * exists and we have only one site available then use it (it
1883 * is for sure the same as our server site). If more sites do
1884 * exist then we don't know which one to use and set the site
1886 cnt = samdb_search_count(ldb, sites_container_dn,
1887 "(objectClass=site)");
1889 site_name = samdb_server_site_name(ldb, mem_ctx);
1891 site_name = talloc_strdup(mem_ctx, "");
1893 l_subnet_name = NULL;
1896 if (subnet_name != NULL) {
1897 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1900 talloc_free(sites_container_dn);
1901 talloc_free(subnets_dn);
1908 work out if we are the PDC for the domain of the current open ldb
1910 bool samdb_is_pdc(struct ldb_context *ldb)
1912 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1914 struct ldb_result *dom_res;
1915 TALLOC_CTX *tmp_ctx;
1919 tmp_ctx = talloc_new(ldb);
1920 if (tmp_ctx == NULL) {
1921 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1925 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1926 if (ret != LDB_SUCCESS) {
1927 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1928 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1929 ldb_errstring(ldb)));
1932 if (dom_res->count != 1) {
1936 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1938 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1944 talloc_free(tmp_ctx);
1949 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1950 talloc_free(tmp_ctx);
1955 work out if we are a Global Catalog server for the domain of the current open ldb
1957 bool samdb_is_gc(struct ldb_context *ldb)
1959 const char *attrs[] = { "options", NULL };
1961 struct ldb_result *res;
1962 TALLOC_CTX *tmp_ctx;
1964 tmp_ctx = talloc_new(ldb);
1965 if (tmp_ctx == NULL) {
1966 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1970 /* Query cn=ntds settings,.... */
1971 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1972 if (ret != LDB_SUCCESS) {
1973 talloc_free(tmp_ctx);
1976 if (res->count != 1) {
1977 talloc_free(tmp_ctx);
1981 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1982 talloc_free(tmp_ctx);
1984 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1985 if (options & 0x000000001) {
1991 /* Find a domain object in the parents of a particular DN. */
1992 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1993 struct ldb_dn **parent_dn, const char **errstring)
1995 TALLOC_CTX *local_ctx;
1996 struct ldb_dn *sdn = dn;
1997 struct ldb_result *res = NULL;
1998 int ret = LDB_SUCCESS;
1999 const char *attrs[] = { NULL };
2001 local_ctx = talloc_new(mem_ctx);
2002 if (local_ctx == NULL) return ldb_oom(ldb);
2004 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
2005 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
2006 "(|(objectClass=domain)(objectClass=builtinDomain))");
2007 if (ret == LDB_SUCCESS) {
2008 if (res->count == 1) {
2016 if (ret != LDB_SUCCESS) {
2017 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2018 ldb_dn_get_linearized(dn),
2019 ldb_dn_get_linearized(sdn),
2020 ldb_errstring(ldb));
2021 talloc_free(local_ctx);
2024 if (res->count != 1) {
2025 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2026 ldb_dn_get_linearized(dn));
2027 DEBUG(0,(__location__ ": %s\n", *errstring));
2028 talloc_free(local_ctx);
2029 return LDB_ERR_CONSTRAINT_VIOLATION;
2032 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2033 talloc_free(local_ctx);
2039 * Performs checks on a user password (plaintext UNIX format - attribute
2040 * "password"). The remaining parameters have to be extracted from the domain
2043 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2045 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2046 const uint32_t pwdProperties,
2047 const uint32_t minPwdLength)
2049 /* checks if the "minPwdLength" property is satisfied */
2050 if (minPwdLength > password->length)
2051 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2053 /* checks the password complexity */
2054 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2055 && (password->data != NULL)
2056 && (!check_password_quality((const char *) password->data)))
2057 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2059 return SAMR_VALIDATION_STATUS_SUCCESS;
2063 * Callback for "samdb_set_password" password change
2065 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2070 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2073 if (ares->error != LDB_SUCCESS) {
2075 req->context = talloc_steal(req,
2076 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2078 return ldb_request_done(req, ret);
2081 if (ares->type != LDB_REPLY_DONE) {
2083 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2086 req->context = talloc_steal(req,
2087 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2089 return ldb_request_done(req, LDB_SUCCESS);
2093 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2094 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2095 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2096 * user change or not. The "rejectReason" gives some more informations if the
2099 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2100 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2102 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2103 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2104 const DATA_BLOB *new_password,
2105 const struct samr_Password *lmNewHash,
2106 const struct samr_Password *ntNewHash,
2107 const struct samr_Password *lmOldHash,
2108 const struct samr_Password *ntOldHash,
2109 enum samPwdChangeReason *reject_reason,
2110 struct samr_DomInfo1 **_dominfo)
2112 struct ldb_message *msg;
2113 struct ldb_message_element *el;
2114 struct ldb_request *req;
2115 struct dsdb_control_password_change_status *pwd_stat = NULL;
2117 NTSTATUS status = NT_STATUS_OK;
2119 #define CHECK_RET(x) \
2120 if (x != LDB_SUCCESS) { \
2122 return NT_STATUS_NO_MEMORY; \
2125 msg = ldb_msg_new(mem_ctx);
2127 return NT_STATUS_NO_MEMORY;
2130 if ((new_password != NULL)
2131 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2132 /* we have the password as plaintext UTF16 */
2133 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2134 "clearTextPassword", new_password));
2135 el = ldb_msg_find_element(msg, "clearTextPassword");
2136 el->flags = LDB_FLAG_MOD_REPLACE;
2137 } else if ((new_password == NULL)
2138 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2139 /* we have a password as LM and/or NT hash */
2140 if (lmNewHash != NULL) {
2141 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2142 "dBCSPwd", lmNewHash));
2143 el = ldb_msg_find_element(msg, "dBCSPwd");
2144 el->flags = LDB_FLAG_MOD_REPLACE;
2146 if (ntNewHash != NULL) {
2147 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2148 "unicodePwd", ntNewHash));
2149 el = ldb_msg_find_element(msg, "unicodePwd");
2150 el->flags = LDB_FLAG_MOD_REPLACE;
2153 /* the password wasn't specified correctly */
2155 return NT_STATUS_INVALID_PARAMETER;
2158 /* build modify request */
2159 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2160 samdb_set_password_callback, NULL);
2161 if (ret != LDB_SUCCESS) {
2163 return NT_STATUS_NO_MEMORY;
2166 /* A password change operation */
2167 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2168 struct dsdb_control_password_change *change;
2170 change = talloc(req, struct dsdb_control_password_change);
2171 if (change == NULL) {
2174 return NT_STATUS_NO_MEMORY;
2177 change->old_nt_pwd_hash = ntOldHash;
2178 change->old_lm_pwd_hash = lmOldHash;
2180 ret = ldb_request_add_control(req,
2181 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2183 if (ret != LDB_SUCCESS) {
2186 return NT_STATUS_NO_MEMORY;
2189 ret = ldb_request_add_control(req,
2190 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2192 if (ret != LDB_SUCCESS) {
2195 return NT_STATUS_NO_MEMORY;
2197 ret = ldb_request_add_control(req,
2198 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2200 if (ret != LDB_SUCCESS) {
2203 return NT_STATUS_NO_MEMORY;
2206 ret = dsdb_autotransaction_request(ldb, req);
2208 if (req->context != NULL) {
2209 pwd_stat = talloc_steal(mem_ctx,
2210 ((struct ldb_control *)req->context)->data);
2216 /* Sets the domain info (if requested) */
2217 if (_dominfo != NULL) {
2218 struct samr_DomInfo1 *dominfo;
2220 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2221 if (dominfo == NULL) {
2222 return NT_STATUS_NO_MEMORY;
2225 if (pwd_stat != NULL) {
2226 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2227 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2228 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2229 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2230 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2233 *_dominfo = dominfo;
2236 if (reject_reason != NULL) {
2237 if (pwd_stat != NULL) {
2238 *reject_reason = pwd_stat->reject_reason;
2240 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2244 if (pwd_stat != NULL) {
2245 talloc_free(pwd_stat);
2248 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2249 const char *errmsg = ldb_errstring(ldb);
2250 char *endptr = NULL;
2251 WERROR werr = WERR_GENERAL_FAILURE;
2252 status = NT_STATUS_UNSUCCESSFUL;
2253 if (errmsg != NULL) {
2254 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2256 if (endptr != errmsg) {
2257 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2258 status = NT_STATUS_WRONG_PASSWORD;
2260 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2261 status = NT_STATUS_PASSWORD_RESTRICTION;
2264 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2265 /* don't let the caller know if an account doesn't exist */
2266 status = NT_STATUS_WRONG_PASSWORD;
2267 } else if (ret != LDB_SUCCESS) {
2268 status = NT_STATUS_UNSUCCESSFUL;
2275 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2276 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2277 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2278 * user change or not. The "rejectReason" gives some more informations if the
2281 * This wrapper function for "samdb_set_password" takes a SID as input rather
2284 * This call encapsulates a new LDB transaction for changing the password;
2285 * therefore the user hasn't to start a new one.
2287 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2288 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2289 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2290 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2292 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2293 const struct dom_sid *user_sid,
2294 const DATA_BLOB *new_password,
2295 const struct samr_Password *lmNewHash,
2296 const struct samr_Password *ntNewHash,
2297 const struct samr_Password *lmOldHash,
2298 const struct samr_Password *ntOldHash,
2299 enum samPwdChangeReason *reject_reason,
2300 struct samr_DomInfo1 **_dominfo)
2303 struct ldb_dn *user_dn;
2306 ret = ldb_transaction_start(ldb);
2307 if (ret != LDB_SUCCESS) {
2308 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2309 return NT_STATUS_TRANSACTION_ABORTED;
2312 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2313 "(&(objectSid=%s)(objectClass=user))",
2314 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2316 ldb_transaction_cancel(ldb);
2317 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2318 dom_sid_string(mem_ctx, user_sid)));
2319 return NT_STATUS_NO_SUCH_USER;
2322 nt_status = samdb_set_password(ldb, mem_ctx,
2325 lmNewHash, ntNewHash,
2326 lmOldHash, ntOldHash,
2327 reject_reason, _dominfo);
2328 if (!NT_STATUS_IS_OK(nt_status)) {
2329 ldb_transaction_cancel(ldb);
2330 talloc_free(user_dn);
2334 ret = ldb_transaction_commit(ldb);
2335 if (ret != LDB_SUCCESS) {
2336 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2337 ldb_dn_get_linearized(user_dn),
2338 ldb_errstring(ldb)));
2339 talloc_free(user_dn);
2340 return NT_STATUS_TRANSACTION_ABORTED;
2343 talloc_free(user_dn);
2344 return NT_STATUS_OK;
2348 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2349 struct dom_sid *sid, struct ldb_dn **ret_dn)
2351 struct ldb_message *msg;
2352 struct ldb_dn *basedn;
2356 sidstr = dom_sid_string(mem_ctx, sid);
2357 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2359 /* We might have to create a ForeignSecurityPrincipal, even if this user
2360 * is in our own domain */
2362 msg = ldb_msg_new(sidstr);
2364 talloc_free(sidstr);
2365 return NT_STATUS_NO_MEMORY;
2368 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2369 ldb_get_default_basedn(sam_ctx),
2370 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2372 if (ret != LDB_SUCCESS) {
2373 DEBUG(0, ("Failed to find DN for "
2374 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2375 talloc_free(sidstr);
2376 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2379 /* add core elements to the ldb_message for the alias */
2381 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2382 talloc_free(sidstr);
2383 return NT_STATUS_NO_MEMORY;
2386 samdb_msg_add_string(sam_ctx, msg, msg,
2388 "foreignSecurityPrincipal");
2390 /* create the alias */
2391 ret = ldb_add(sam_ctx, msg);
2392 if (ret != LDB_SUCCESS) {
2393 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2395 ldb_dn_get_linearized(msg->dn),
2396 ldb_errstring(sam_ctx)));
2397 talloc_free(sidstr);
2398 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2401 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2402 talloc_free(sidstr);
2404 return NT_STATUS_OK;
2409 Find the DN of a domain, assuming it to be a dotted.dns name
2412 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2415 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2416 const char *binary_encoded;
2417 const char **split_realm;
2424 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2426 talloc_free(tmp_ctx);
2429 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2430 for (i=0; split_realm[i]; i++) {
2431 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2432 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2433 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2434 binary_encoded, ldb_dn_get_linearized(dn)));
2435 talloc_free(tmp_ctx);
2439 if (!ldb_dn_validate(dn)) {
2440 DEBUG(2, ("Failed to validated DN %s\n",
2441 ldb_dn_get_linearized(dn)));
2442 talloc_free(tmp_ctx);
2445 talloc_free(tmp_ctx);
2450 Find the DN of a domain, be it the netbios or DNS name
2452 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2453 const char *domain_name)
2455 const char * const domain_ref_attrs[] = {
2458 const char * const domain_ref2_attrs[] = {
2461 struct ldb_result *res_domain_ref;
2462 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2463 /* find the domain's DN */
2464 int ret_domain = ldb_search(ldb, mem_ctx,
2466 samdb_partitions_dn(ldb, mem_ctx),
2469 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2471 if (ret_domain != LDB_SUCCESS) {
2475 if (res_domain_ref->count == 0) {
2476 ret_domain = ldb_search(ldb, mem_ctx,
2478 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2481 "(objectclass=domain)");
2482 if (ret_domain != LDB_SUCCESS) {
2486 if (res_domain_ref->count == 1) {
2487 return res_domain_ref->msgs[0]->dn;
2492 if (res_domain_ref->count > 1) {
2493 DEBUG(0,("Found %d records matching domain [%s]\n",
2494 ret_domain, domain_name));
2498 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2504 use a GUID to find a DN
2506 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2507 TALLOC_CTX *mem_ctx,
2508 const struct GUID *guid, struct ldb_dn **dn)
2511 struct ldb_result *res;
2512 const char *attrs[] = { NULL };
2513 char *guid_str = GUID_string(mem_ctx, guid);
2516 return ldb_operr(ldb);
2519 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2520 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2521 DSDB_SEARCH_SHOW_EXTENDED_DN |
2522 DSDB_SEARCH_ONE_ONLY,
2523 "objectGUID=%s", guid_str);
2524 talloc_free(guid_str);
2525 if (ret != LDB_SUCCESS) {
2529 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2536 use a DN to find a GUID with a given attribute name
2538 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2539 struct ldb_dn *dn, const char *attribute,
2543 struct ldb_result *res;
2544 const char *attrs[2];
2545 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2547 attrs[0] = attribute;
2550 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2551 DSDB_SEARCH_SHOW_DELETED |
2552 DSDB_SEARCH_SHOW_RECYCLED);
2553 if (ret != LDB_SUCCESS) {
2554 talloc_free(tmp_ctx);
2557 if (res->count < 1) {
2558 talloc_free(tmp_ctx);
2559 return LDB_ERR_NO_SUCH_OBJECT;
2561 *guid = samdb_result_guid(res->msgs[0], attribute);
2562 talloc_free(tmp_ctx);
2567 use a DN to find a GUID
2569 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2570 struct ldb_dn *dn, struct GUID *guid)
2572 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2578 adds the given GUID to the given ldb_message. This value is added
2579 for the given attr_name (may be either "objectGUID" or "parentGUID").
2581 int dsdb_msg_add_guid(struct ldb_message *msg,
2583 const char *attr_name)
2588 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2590 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2591 if (!NT_STATUS_IS_OK(status)) {
2592 ret = LDB_ERR_OPERATIONS_ERROR;
2596 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2597 if (ret != LDB_SUCCESS) {
2598 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2606 talloc_free(tmp_ctx);
2613 use a DN to find a SID
2615 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2616 struct ldb_dn *dn, struct dom_sid *sid)
2619 struct ldb_result *res;
2620 const char *attrs[] = { "objectSid", NULL };
2621 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2626 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2627 DSDB_SEARCH_SHOW_DELETED |
2628 DSDB_SEARCH_SHOW_RECYCLED);
2629 if (ret != LDB_SUCCESS) {
2630 talloc_free(tmp_ctx);
2633 if (res->count < 1) {
2634 talloc_free(tmp_ctx);
2635 return LDB_ERR_NO_SUCH_OBJECT;
2637 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2639 talloc_free(tmp_ctx);
2640 return LDB_ERR_NO_SUCH_OBJECT;
2643 talloc_free(tmp_ctx);
2648 use a SID to find a DN
2650 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2651 TALLOC_CTX *mem_ctx,
2652 struct dom_sid *sid, struct ldb_dn **dn)
2655 struct ldb_result *res;
2656 const char *attrs[] = { NULL };
2657 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2660 return ldb_operr(ldb);
2663 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2664 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2665 DSDB_SEARCH_SHOW_EXTENDED_DN |
2666 DSDB_SEARCH_ONE_ONLY,
2667 "objectSid=%s", sid_str);
2668 talloc_free(sid_str);
2669 if (ret != LDB_SUCCESS) {
2673 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2680 load a repsFromTo blob list for a given partition GUID
2681 attr must be "repsFrom" or "repsTo"
2683 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2684 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2686 const char *attrs[] = { attr, NULL };
2687 struct ldb_result *res = NULL;
2688 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2690 struct ldb_message_element *el;
2695 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2697 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2698 talloc_free(tmp_ctx);
2699 return WERR_DS_DRA_INTERNAL_ERROR;
2702 el = ldb_msg_find_element(res->msgs[0], attr);
2704 /* it's OK to be empty */
2705 talloc_free(tmp_ctx);
2709 *count = el->num_values;
2710 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2712 talloc_free(tmp_ctx);
2713 return WERR_DS_DRA_INTERNAL_ERROR;
2716 for (i=0; i<(*count); i++) {
2717 enum ndr_err_code ndr_err;
2718 ndr_err = ndr_pull_struct_blob(&el->values[i],
2721 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2723 talloc_free(tmp_ctx);
2724 return WERR_DS_DRA_INTERNAL_ERROR;
2728 talloc_free(tmp_ctx);
2734 save the repsFromTo blob list for a given partition GUID
2735 attr must be "repsFrom" or "repsTo"
2737 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2738 const char *attr, struct repsFromToBlob *r, uint32_t count)
2740 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2741 struct ldb_message *msg;
2742 struct ldb_message_element *el;
2745 msg = ldb_msg_new(tmp_ctx);
2747 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2751 el->values = talloc_array(msg, struct ldb_val, count);
2756 for (i=0; i<count; i++) {
2758 enum ndr_err_code ndr_err;
2760 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2762 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2763 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2771 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2772 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2776 talloc_free(tmp_ctx);
2781 talloc_free(tmp_ctx);
2782 return WERR_DS_DRA_INTERNAL_ERROR;
2787 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2788 object for a partition
2790 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2791 uint64_t *uSN, uint64_t *urgent_uSN)
2793 struct ldb_request *req;
2795 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2796 struct dsdb_control_current_partition *p_ctrl;
2797 struct ldb_result *res;
2799 res = talloc_zero(tmp_ctx, struct ldb_result);
2801 talloc_free(tmp_ctx);
2802 return ldb_oom(ldb);
2805 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2806 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2810 res, ldb_search_default_callback,
2812 if (ret != LDB_SUCCESS) {
2813 talloc_free(tmp_ctx);
2817 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2818 if (p_ctrl == NULL) {
2819 talloc_free(tmp_ctx);
2820 return ldb_oom(ldb);
2822 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2825 ret = ldb_request_add_control(req,
2826 DSDB_CONTROL_CURRENT_PARTITION_OID,
2828 if (ret != LDB_SUCCESS) {
2829 talloc_free(tmp_ctx);
2833 /* Run the new request */
2834 ret = ldb_request(ldb, req);
2836 if (ret == LDB_SUCCESS) {
2837 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2840 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2841 /* it hasn't been created yet, which means
2842 an implicit value of zero */
2844 talloc_free(tmp_ctx);
2848 if (ret != LDB_SUCCESS) {
2849 talloc_free(tmp_ctx);
2853 if (res->count < 1) {
2859 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2861 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2865 talloc_free(tmp_ctx);
2870 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2871 const struct drsuapi_DsReplicaCursor2 *c2)
2873 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2876 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2877 const struct drsuapi_DsReplicaCursor *c2)
2879 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2884 see if a computer identified by its invocationId is a RODC
2886 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2888 /* 1) find the DN for this servers NTDSDSA object
2889 2) search for the msDS-isRODC attribute
2890 3) if not present then not a RODC
2891 4) if present and TRUE then is a RODC
2893 struct ldb_dn *config_dn;
2894 const char *attrs[] = { "msDS-isRODC", NULL };
2896 struct ldb_result *res;
2897 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2899 config_dn = ldb_get_config_basedn(sam_ctx);
2901 talloc_free(tmp_ctx);
2902 return ldb_operr(sam_ctx);
2905 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2906 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2908 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2910 talloc_free(tmp_ctx);
2914 if (ret != LDB_SUCCESS) {
2915 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2916 GUID_string(tmp_ctx, objectGUID)));
2918 talloc_free(tmp_ctx);
2922 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2923 *is_rodc = (ret == 1);
2925 talloc_free(tmp_ctx);
2931 see if we are a RODC
2933 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2935 const struct GUID *objectGUID;
2939 /* see if we have a cached copy */
2940 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2946 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2948 return ldb_operr(sam_ctx);
2951 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2952 if (ret != LDB_SUCCESS) {
2956 cached = talloc(sam_ctx, bool);
2957 if (cached == NULL) {
2958 return ldb_oom(sam_ctx);
2962 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2963 if (ret != LDB_SUCCESS) {
2964 talloc_free(cached);
2965 return ldb_operr(sam_ctx);
2971 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2973 TALLOC_CTX *tmp_ctx;
2976 tmp_ctx = talloc_new(ldb);
2977 if (tmp_ctx == NULL) {
2981 cached = talloc(tmp_ctx, bool);
2987 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2991 talloc_steal(ldb, cached);
2992 talloc_free(tmp_ctx);
2996 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2997 talloc_free(tmp_ctx);
3003 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
3005 flags are DS_NTDS_OPTION_*
3007 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3009 TALLOC_CTX *tmp_ctx;
3010 const char *attrs[] = { "options", NULL };
3012 struct ldb_result *res;
3014 tmp_ctx = talloc_new(ldb);
3015 if (tmp_ctx == NULL) {
3019 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3020 if (ret != LDB_SUCCESS) {
3024 if (res->count != 1) {
3028 *options = samdb_result_uint(res->msgs[0], "options", 0);
3030 talloc_free(tmp_ctx);
3035 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3036 talloc_free(tmp_ctx);
3037 return LDB_ERR_NO_SUCH_OBJECT;
3040 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3042 const char *attrs[] = { "objectCategory", NULL };
3044 struct ldb_result *res;
3046 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3047 if (ret != LDB_SUCCESS) {
3051 if (res->count != 1) {
3055 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
3058 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3063 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3064 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3066 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3068 char **tokens, *ret;
3071 tokens = str_list_make(mem_ctx, cn, " -_");
3075 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3076 tokens[0][0] = tolower(tokens[0][0]);
3077 for (i = 1; i < str_list_length((const char **)tokens); i++)
3078 tokens[i][0] = toupper(tokens[i][0]);
3080 ret = talloc_strdup(mem_ctx, tokens[0]);
3081 for (i = 1; i < str_list_length((const char **)tokens); i++)
3082 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3084 talloc_free(tokens);
3090 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3092 int dsdb_functional_level(struct ldb_context *ldb)
3094 int *domainFunctionality =
3095 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3096 if (!domainFunctionality) {
3097 /* this is expected during initial provision */
3098 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3099 return DS_DOMAIN_FUNCTION_2000;
3101 return *domainFunctionality;
3105 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3107 int dsdb_forest_functional_level(struct ldb_context *ldb)
3109 int *forestFunctionality =
3110 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3111 if (!forestFunctionality) {
3112 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3113 return DS_DOMAIN_FUNCTION_2000;
3115 return *forestFunctionality;
3119 set a GUID in an extended DN structure
3121 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3127 status = GUID_to_ndr_blob(guid, dn, &v);
3128 if (!NT_STATUS_IS_OK(status)) {
3129 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3132 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3138 return a GUID from a extended DN structure
3140 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3142 const struct ldb_val *v;
3144 v = ldb_dn_get_extended_component(dn, component_name);
3146 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3149 return GUID_from_ndr_blob(v, guid);
3153 return a uint64_t from a extended DN structure
3155 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3157 const struct ldb_val *v;
3160 v = ldb_dn_get_extended_component(dn, component_name);
3162 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3164 s = talloc_strndup(dn, (const char *)v->data, v->length);
3165 NT_STATUS_HAVE_NO_MEMORY(s);
3167 *val = strtoull(s, NULL, 0);
3170 return NT_STATUS_OK;
3174 return a NTTIME from a extended DN structure
3176 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3178 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3182 return a uint32_t from a extended DN structure
3184 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3186 const struct ldb_val *v;
3189 v = ldb_dn_get_extended_component(dn, component_name);
3191 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3194 s = talloc_strndup(dn, (const char *)v->data, v->length);
3195 NT_STATUS_HAVE_NO_MEMORY(s);
3197 *val = strtoul(s, NULL, 0);
3200 return NT_STATUS_OK;
3204 return a dom_sid from a extended DN structure
3206 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3208 const struct ldb_val *sid_blob;
3209 struct TALLOC_CTX *tmp_ctx;
3210 enum ndr_err_code ndr_err;
3212 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3214 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3217 tmp_ctx = talloc_new(NULL);
3219 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3220 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3221 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3222 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3223 talloc_free(tmp_ctx);
3227 talloc_free(tmp_ctx);
3228 return NT_STATUS_OK;
3233 return RMD_FLAGS directly from a ldb_dn
3234 returns 0 if not found
3236 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3238 const struct ldb_val *v;
3240 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3241 if (!v || v->length > sizeof(buf)-1) return 0;
3242 strncpy(buf, (const char *)v->data, v->length);
3244 return strtoul(buf, NULL, 10);
3248 return RMD_FLAGS directly from a ldb_val for a DN
3249 returns 0 if RMD_FLAGS is not found
3251 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3257 if (val->length < 13) {
3260 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3264 flags = strtoul(p+11, &end, 10);
3265 if (!end || *end != '>') {
3266 /* it must end in a > */
3273 return true if a ldb_val containing a DN in storage form is deleted
3275 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3277 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3281 return true if a ldb_val containing a DN in storage form is
3282 in the upgraded w2k3 linked attribute format
3284 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3286 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3290 return a DN for a wellknown GUID
3292 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3293 struct ldb_dn *nc_root, const char *wk_guid,
3294 struct ldb_dn **wkguid_dn)
3296 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3297 const char *attrs[] = { NULL };
3300 struct ldb_result *res;
3302 /* construct the magic WKGUID DN */
3303 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3304 wk_guid, ldb_dn_get_linearized(nc_root));
3306 talloc_free(tmp_ctx);
3307 return ldb_operr(samdb);
3310 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3311 DSDB_SEARCH_SHOW_DELETED |
3312 DSDB_SEARCH_SHOW_RECYCLED);
3313 if (ret != LDB_SUCCESS) {
3314 talloc_free(tmp_ctx);
3318 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3319 talloc_free(tmp_ctx);
3324 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3326 return ldb_dn_compare(*dn1, *dn2);
3330 find a NC root given a DN within the NC
3332 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3333 struct ldb_dn **nc_root)
3335 const char *root_attrs[] = { "namingContexts", NULL };
3336 TALLOC_CTX *tmp_ctx;
3338 struct ldb_message_element *el;
3339 struct ldb_result *root_res;
3341 struct ldb_dn **nc_dns;
3343 tmp_ctx = talloc_new(samdb);
3344 if (tmp_ctx == NULL) {
3345 return ldb_oom(samdb);
3348 ret = ldb_search(samdb, tmp_ctx, &root_res,
3349 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3350 if (ret != LDB_SUCCESS) {
3351 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3352 talloc_free(tmp_ctx);
3356 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3358 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3359 ldb_errstring(samdb)));
3360 talloc_free(tmp_ctx);
3361 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3364 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3366 talloc_free(tmp_ctx);
3367 return ldb_oom(samdb);
3370 for (i=0; i<el->num_values; i++) {
3371 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3372 if (nc_dns[i] == NULL) {
3373 talloc_free(tmp_ctx);
3374 return ldb_operr(samdb);
3378 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3380 for (i=0; i<el->num_values; i++) {
3381 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3382 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3383 talloc_free(tmp_ctx);
3388 talloc_free(tmp_ctx);
3389 return LDB_ERR_NO_SUCH_OBJECT;
3394 find the deleted objects DN for any object, by looking for the NC
3395 root, then looking up the wellknown GUID
3397 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3398 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3399 struct ldb_dn **do_dn)
3401 struct ldb_dn *nc_root;
3404 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3405 if (ret != LDB_SUCCESS) {
3409 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3410 talloc_free(nc_root);
3415 return the tombstoneLifetime, in days
3417 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3420 dn = ldb_get_config_basedn(ldb);
3422 return LDB_ERR_NO_SUCH_OBJECT;
3424 dn = ldb_dn_copy(ldb, dn);
3426 return ldb_operr(ldb);
3428 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3429 be a wellknown GUID for this */
3430 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3432 return ldb_operr(ldb);
3435 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3441 compare a ldb_val to a string case insensitively
3443 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3445 size_t len = strlen(s);
3447 if (len > v->length) return 1;
3448 ret = strncasecmp(s, (const char *)v->data, v->length);
3449 if (ret != 0) return ret;
3450 if (v->length > len && v->data[len] != 0) {
3458 load the UDV for a partition in v2 format
3459 The list is returned sorted, and with our local cursor added
3461 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3462 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3464 static const char *attrs[] = { "replUpToDateVector", NULL };
3465 struct ldb_result *r;
3466 const struct ldb_val *ouv_value;
3469 uint64_t highest_usn;
3470 const struct GUID *our_invocation_id;
3471 struct timeval now = timeval_current();
3473 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3474 if (ret != LDB_SUCCESS) {
3478 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3480 enum ndr_err_code ndr_err;
3481 struct replUpToDateVectorBlob ouv;
3483 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3484 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3485 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3487 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3489 if (ouv.version != 2) {
3490 /* we always store as version 2, and
3491 * replUpToDateVector is not replicated
3493 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3496 *count = ouv.ctr.ctr2.count;
3497 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3505 our_invocation_id = samdb_ntds_invocation_id(samdb);
3506 if (!our_invocation_id) {
3507 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3508 talloc_free(*cursors);
3509 return ldb_operr(samdb);
3512 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3513 if (ret != LDB_SUCCESS) {
3514 /* nothing to add - this can happen after a vampire */
3515 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3519 for (i=0; i<*count; i++) {
3520 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3521 (*cursors)[i].highest_usn = highest_usn;
3522 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3523 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3528 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3530 return ldb_oom(samdb);
3533 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3534 (*cursors)[*count].highest_usn = highest_usn;
3535 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3538 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3544 load the UDV for a partition in version 1 format
3545 The list is returned sorted, and with our local cursor added
3547 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3548 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3550 struct drsuapi_DsReplicaCursor2 *v2;
3554 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3555 if (ret != LDB_SUCCESS) {
3565 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3566 if (*cursors == NULL) {
3568 return ldb_oom(samdb);
3571 for (i=0; i<*count; i++) {
3572 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3573 (*cursors)[i].highest_usn = v2[i].highest_usn;
3580 add a set of controls to a ldb_request structure based on a set of
3581 flags. See util.h for a list of available flags
3583 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3586 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3587 struct ldb_search_options_control *options;
3588 /* Using the phantom root control allows us to search all partitions */
3589 options = talloc(req, struct ldb_search_options_control);
3590 if (options == NULL) {
3591 return LDB_ERR_OPERATIONS_ERROR;
3593 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3595 ret = ldb_request_add_control(req,
3596 LDB_CONTROL_SEARCH_OPTIONS_OID,
3598 if (ret != LDB_SUCCESS) {
3603 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3604 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3605 if (ret != LDB_SUCCESS) {
3610 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3611 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3612 if (ret != LDB_SUCCESS) {
3617 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3618 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3619 if (ret != LDB_SUCCESS) {
3624 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3625 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3626 if (!extended_ctrl) {
3627 return LDB_ERR_OPERATIONS_ERROR;
3629 extended_ctrl->type = 1;
3631 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3632 if (ret != LDB_SUCCESS) {
3637 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3638 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3639 if (ret != LDB_SUCCESS) {
3644 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3645 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3646 if (ret != LDB_SUCCESS) {
3651 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3652 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3653 if (ret != LDB_SUCCESS) {
3658 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3659 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3660 if (ret != LDB_SUCCESS) {
3665 if (dsdb_flags & DSDB_TREE_DELETE) {
3666 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3667 if (ret != LDB_SUCCESS) {
3676 an add with a set of controls
3678 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3679 uint32_t dsdb_flags)
3681 struct ldb_request *req;
3684 ret = ldb_build_add_req(&req, ldb, ldb,
3688 ldb_op_default_callback,
3691 if (ret != LDB_SUCCESS) return ret;
3693 ret = dsdb_request_add_controls(req, dsdb_flags);
3694 if (ret != LDB_SUCCESS) {
3699 ret = dsdb_autotransaction_request(ldb, req);
3706 a modify with a set of controls
3708 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3709 uint32_t dsdb_flags)
3711 struct ldb_request *req;
3714 ret = ldb_build_mod_req(&req, ldb, ldb,
3718 ldb_op_default_callback,
3721 if (ret != LDB_SUCCESS) return ret;
3723 ret = dsdb_request_add_controls(req, dsdb_flags);
3724 if (ret != LDB_SUCCESS) {
3729 ret = dsdb_autotransaction_request(ldb, req);
3736 like dsdb_modify() but set all the element flags to
3737 LDB_FLAG_MOD_REPLACE
3739 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3743 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3744 for (i=0;i<msg->num_elements;i++) {
3745 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3748 return dsdb_modify(ldb, msg, dsdb_flags);
3753 search for attrs on one DN, allowing for dsdb_flags controls
3755 int dsdb_search_dn(struct ldb_context *ldb,
3756 TALLOC_CTX *mem_ctx,
3757 struct ldb_result **_res,
3758 struct ldb_dn *basedn,
3759 const char * const *attrs,
3760 uint32_t dsdb_flags)
3763 struct ldb_request *req;
3764 struct ldb_result *res;
3766 res = talloc_zero(mem_ctx, struct ldb_result);
3768 return ldb_oom(ldb);
3771 ret = ldb_build_search_req(&req, ldb, res,
3778 ldb_search_default_callback,
3780 if (ret != LDB_SUCCESS) {
3785 ret = dsdb_request_add_controls(req, dsdb_flags);
3786 if (ret != LDB_SUCCESS) {
3791 ret = ldb_request(ldb, req);
3792 if (ret == LDB_SUCCESS) {
3793 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3797 if (ret != LDB_SUCCESS) {
3807 search for attrs on one DN, by the GUID of the DN, allowing for
3810 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3811 TALLOC_CTX *mem_ctx,
3812 struct ldb_result **_res,
3813 const struct GUID *guid,
3814 const char * const *attrs,
3815 uint32_t dsdb_flags)
3817 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3821 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3822 if (!ldb_dn_validate(dn)) {
3823 talloc_free(tmp_ctx);
3824 return LDB_ERR_INVALID_DN_SYNTAX;
3827 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3828 talloc_free(tmp_ctx);
3833 general search with dsdb_flags for controls
3835 int dsdb_search(struct ldb_context *ldb,
3836 TALLOC_CTX *mem_ctx,
3837 struct ldb_result **_res,
3838 struct ldb_dn *basedn,
3839 enum ldb_scope scope,
3840 const char * const *attrs,
3841 uint32_t dsdb_flags,
3842 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3845 struct ldb_request *req;
3846 struct ldb_result *res;
3848 char *expression = NULL;
3849 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3851 res = talloc_zero(tmp_ctx, struct ldb_result);
3853 talloc_free(tmp_ctx);
3854 return ldb_oom(ldb);
3858 va_start(ap, exp_fmt);
3859 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3863 talloc_free(tmp_ctx);
3864 return ldb_oom(ldb);
3868 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3875 ldb_search_default_callback,
3877 if (ret != LDB_SUCCESS) {
3878 talloc_free(tmp_ctx);
3882 ret = dsdb_request_add_controls(req, dsdb_flags);
3883 if (ret != LDB_SUCCESS) {
3884 talloc_free(tmp_ctx);
3885 ldb_reset_err_string(ldb);
3889 ret = ldb_request(ldb, req);
3890 if (ret == LDB_SUCCESS) {
3891 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3894 if (ret != LDB_SUCCESS) {
3895 talloc_free(tmp_ctx);
3899 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3900 if (res->count == 0) {
3901 talloc_free(tmp_ctx);
3902 ldb_reset_err_string(ldb);
3903 return LDB_ERR_NO_SUCH_OBJECT;
3905 if (res->count != 1) {
3906 talloc_free(tmp_ctx);
3907 ldb_reset_err_string(ldb);
3908 return LDB_ERR_CONSTRAINT_VIOLATION;
3912 *_res = talloc_steal(mem_ctx, res);
3913 talloc_free(tmp_ctx);
3920 general search with dsdb_flags for controls
3921 returns exactly 1 record or an error
3923 int dsdb_search_one(struct ldb_context *ldb,
3924 TALLOC_CTX *mem_ctx,
3925 struct ldb_message **msg,
3926 struct ldb_dn *basedn,
3927 enum ldb_scope scope,
3928 const char * const *attrs,
3929 uint32_t dsdb_flags,
3930 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3933 struct ldb_result *res;
3935 char *expression = NULL;
3936 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3938 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3940 res = talloc_zero(tmp_ctx, struct ldb_result);
3942 talloc_free(tmp_ctx);
3943 return ldb_oom(ldb);
3947 va_start(ap, exp_fmt);
3948 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3952 talloc_free(tmp_ctx);
3953 return ldb_oom(ldb);
3955 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3956 dsdb_flags, "%s", expression);
3958 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3962 if (ret != LDB_SUCCESS) {
3963 talloc_free(tmp_ctx);
3967 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3968 talloc_free(tmp_ctx);
3973 /* returns back the forest DNS name */
3974 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3976 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3977 ldb_get_root_basedn(ldb));
3980 if (forest_name == NULL) {
3984 p = strchr(forest_name, '/');
3993 validate that an DSA GUID belongs to the specified user sid.
3994 The user SID must be a domain controller account (either RODC or
3997 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3998 const struct GUID *dsa_guid,
3999 const struct dom_sid *sid)
4002 - find DN of record with the DSA GUID in the
4003 configuration partition (objectGUID)
4004 - remove "NTDS Settings" component from DN
4005 - do a base search on that DN for serverReference with
4007 - extract objectSid from resulting serverReference
4009 - check this sid matches the sid argument
4011 struct ldb_dn *config_dn;
4012 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4013 struct ldb_message *msg;
4014 const char *attrs1[] = { NULL };
4015 const char *attrs2[] = { "serverReference", NULL };
4017 struct ldb_dn *dn, *account_dn;
4018 struct dom_sid sid2;
4021 config_dn = ldb_get_config_basedn(ldb);
4023 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4024 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4025 if (ret != LDB_SUCCESS) {
4026 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4027 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4028 talloc_free(tmp_ctx);
4029 return ldb_operr(ldb);
4033 if (!ldb_dn_remove_child_components(dn, 1)) {
4034 talloc_free(tmp_ctx);
4035 return ldb_operr(ldb);
4038 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4039 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4040 "(objectClass=server)");
4041 if (ret != LDB_SUCCESS) {
4042 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4043 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4044 talloc_free(tmp_ctx);
4045 return ldb_operr(ldb);
4048 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4049 if (account_dn == NULL) {
4050 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4051 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4052 talloc_free(tmp_ctx);
4053 return ldb_operr(ldb);
4056 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4057 if (!NT_STATUS_IS_OK(status)) {
4058 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4059 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4060 talloc_free(tmp_ctx);
4061 return ldb_operr(ldb);
4064 if (!dom_sid_equal(sid, &sid2)) {
4065 /* someone is trying to spoof another account */
4066 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4067 GUID_string(tmp_ctx, dsa_guid),
4068 dom_sid_string(tmp_ctx, sid),
4069 dom_sid_string(tmp_ctx, &sid2)));
4070 talloc_free(tmp_ctx);
4071 return ldb_operr(ldb);
4074 talloc_free(tmp_ctx);
4078 static const char *secret_attributes[] = {
4081 "initialAuthIncoming",
4082 "initialAuthOutgoing",
4086 "supplementalCredentials",
4087 "trustAuthIncoming",
4088 "trustAuthOutgoing",
4094 check if the attribute belongs to the RODC filtered attribute set
4095 Note that attributes that are in the filtered attribute set are the
4096 ones that _are_ always sent to a RODC
4098 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4100 /* they never get secret attributes */
4101 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4105 /* they do get non-secret critical attributes */
4106 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4110 /* they do get non-secret attributes marked as being in the FAS */
4111 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4115 /* other attributes are denied */
4119 /* return fsmo role dn and role owner dn for a particular role*/
4120 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4121 struct ldb_context *ldb,
4123 struct ldb_dn **fsmo_role_dn,
4124 struct ldb_dn **role_owner_dn)
4128 case DREPL_NAMING_MASTER:
4129 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4130 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4131 if (ret != LDB_SUCCESS) {
4132 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4133 ldb_errstring(ldb)));
4134 talloc_free(tmp_ctx);
4135 return WERR_DS_DRA_INTERNAL_ERROR;
4138 case DREPL_INFRASTRUCTURE_MASTER:
4139 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4140 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4141 if (ret != LDB_SUCCESS) {
4142 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4143 ldb_errstring(ldb)));
4144 talloc_free(tmp_ctx);
4145 return WERR_DS_DRA_INTERNAL_ERROR;
4148 case DREPL_RID_MASTER:
4149 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4150 if (ret != LDB_SUCCESS) {
4151 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4152 talloc_free(tmp_ctx);
4153 return WERR_DS_DRA_INTERNAL_ERROR;
4156 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4157 if (ret != LDB_SUCCESS) {
4158 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4159 ldb_errstring(ldb)));
4160 talloc_free(tmp_ctx);
4161 return WERR_DS_DRA_INTERNAL_ERROR;
4164 case DREPL_SCHEMA_MASTER:
4165 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4166 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4167 if (ret != LDB_SUCCESS) {
4168 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4169 ldb_errstring(ldb)));
4170 talloc_free(tmp_ctx);
4171 return WERR_DS_DRA_INTERNAL_ERROR;
4174 case DREPL_PDC_MASTER:
4175 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4176 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4177 if (ret != LDB_SUCCESS) {
4178 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4179 ldb_errstring(ldb)));
4180 talloc_free(tmp_ctx);
4181 return WERR_DS_DRA_INTERNAL_ERROR;
4185 return WERR_DS_DRA_INTERNAL_ERROR;
4190 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4191 TALLOC_CTX *mem_ctx,
4192 struct ldb_dn *server_dn)
4195 struct ldb_result *res = NULL;
4196 const char * const attrs[] = { "dNSHostName", NULL};
4198 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4202 if (ldb_ret != LDB_SUCCESS) {
4203 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4204 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4208 return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
4212 returns true if an attribute is in the filter,
4213 false otherwise, provided that attribute value is provided with the expression
4215 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4219 switch (tree->operation) {
4222 for (i=0;i<tree->u.list.num_elements;i++) {
4223 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4229 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4230 case LDB_OP_EQUALITY:
4231 case LDB_OP_GREATER:
4234 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4238 case LDB_OP_SUBSTRING:
4239 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4243 case LDB_OP_PRESENT:
4244 /* (attrname=*) is not filtered out */
4246 case LDB_OP_EXTENDED:
4247 if (tree->u.extended.attr &&
4248 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {