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 * Handle ldb_request in transaction
1107 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1108 struct ldb_request *req)
1112 ret = ldb_transaction_start(sam_ldb);
1113 if (ret != LDB_SUCCESS) {
1117 ret = ldb_request(sam_ldb, req);
1118 if (ret == LDB_SUCCESS) {
1119 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1122 if (ret == LDB_SUCCESS) {
1123 return ldb_transaction_commit(sam_ldb);
1125 ldb_transaction_cancel(sam_ldb);
1131 return a default security descriptor
1133 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1135 struct security_descriptor *sd;
1137 sd = security_descriptor_initialise(mem_ctx);
1142 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1144 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1145 struct ldb_dn *aggregate_dn;
1150 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1151 if (!aggregate_dn) {
1154 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1157 return aggregate_dn;
1160 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1162 struct ldb_dn *new_dn;
1164 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1165 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1166 talloc_free(new_dn);
1172 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1174 struct ldb_dn *new_dn;
1176 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1177 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1178 talloc_free(new_dn);
1184 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1186 struct ldb_dn *new_dn;
1188 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1189 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1190 talloc_free(new_dn);
1197 work out the domain sid for the current open ldb
1199 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1201 TALLOC_CTX *tmp_ctx;
1202 const struct dom_sid *domain_sid;
1203 const char *attrs[] = {
1207 struct ldb_result *res;
1210 /* see if we have a cached copy */
1211 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1216 tmp_ctx = talloc_new(ldb);
1217 if (tmp_ctx == NULL) {
1221 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1223 if (ret != LDB_SUCCESS) {
1227 if (res->count != 1) {
1231 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1232 if (domain_sid == NULL) {
1236 /* cache the domain_sid in the ldb */
1237 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1241 talloc_steal(ldb, domain_sid);
1242 talloc_free(tmp_ctx);
1247 talloc_free(tmp_ctx);
1252 get domain sid from cache
1254 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1256 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1259 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1261 TALLOC_CTX *tmp_ctx;
1262 struct dom_sid *dom_sid_new;
1263 struct dom_sid *dom_sid_old;
1265 /* see if we have a cached copy */
1266 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1267 "cache.domain_sid"), struct dom_sid);
1269 tmp_ctx = talloc_new(ldb);
1270 if (tmp_ctx == NULL) {
1274 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1279 /* cache the domain_sid in the ldb */
1280 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1284 talloc_steal(ldb, dom_sid_new);
1285 talloc_free(tmp_ctx);
1286 talloc_free(dom_sid_old);
1291 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1292 talloc_free(tmp_ctx);
1296 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1298 TALLOC_CTX *tmp_ctx;
1299 struct ldb_dn *ntds_settings_dn_new;
1300 struct ldb_dn *ntds_settings_dn_old;
1302 /* see if we have a cached copy */
1303 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1304 "cache.ntds_settings_dn"), struct ldb_dn);
1306 tmp_ctx = talloc_new(ldb);
1307 if (tmp_ctx == NULL) {
1311 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1312 if (!ntds_settings_dn_new) {
1316 /* cache the domain_sid in the ldb */
1317 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1321 talloc_steal(ldb, ntds_settings_dn_new);
1322 talloc_free(tmp_ctx);
1323 talloc_free(ntds_settings_dn_old);
1328 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1329 talloc_free(tmp_ctx);
1333 /* Obtain the short name of the flexible single master operator
1334 * (FSMO), such as the PDC Emulator */
1335 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1338 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1339 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1340 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1341 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1343 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1344 /* Ensure this matches the format. This gives us a
1345 * bit more confidence that a 'cn' value will be a
1350 return (char *)val->data;
1356 work out the ntds settings dn for the current open ldb
1358 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1360 TALLOC_CTX *tmp_ctx;
1361 const char *root_attrs[] = { "dsServiceName", NULL };
1363 struct ldb_result *root_res;
1364 struct ldb_dn *settings_dn;
1366 /* see if we have a cached copy */
1367 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1372 tmp_ctx = talloc_new(ldb);
1373 if (tmp_ctx == NULL) {
1377 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1379 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1380 ldb_errstring(ldb)));
1384 if (root_res->count != 1) {
1388 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1390 /* cache the domain_sid in the ldb */
1391 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1395 talloc_steal(ldb, settings_dn);
1396 talloc_free(tmp_ctx);
1401 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1402 talloc_free(tmp_ctx);
1407 work out the ntds settings invocationId for the current open ldb
1409 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1411 TALLOC_CTX *tmp_ctx;
1412 const char *attrs[] = { "invocationId", NULL };
1414 struct ldb_result *res;
1415 struct GUID *invocation_id;
1417 /* see if we have a cached copy */
1418 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1419 if (invocation_id) {
1420 return invocation_id;
1423 tmp_ctx = talloc_new(ldb);
1424 if (tmp_ctx == NULL) {
1428 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1433 if (res->count != 1) {
1437 invocation_id = talloc(tmp_ctx, struct GUID);
1438 if (!invocation_id) {
1442 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1444 /* cache the domain_sid in the ldb */
1445 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1449 talloc_steal(ldb, invocation_id);
1450 talloc_free(tmp_ctx);
1452 return invocation_id;
1455 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1456 talloc_free(tmp_ctx);
1460 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1462 TALLOC_CTX *tmp_ctx;
1463 struct GUID *invocation_id_new;
1464 struct GUID *invocation_id_old;
1466 /* see if we have a cached copy */
1467 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1468 "cache.invocation_id");
1470 tmp_ctx = talloc_new(ldb);
1471 if (tmp_ctx == NULL) {
1475 invocation_id_new = talloc(tmp_ctx, struct GUID);
1476 if (!invocation_id_new) {
1480 *invocation_id_new = *invocation_id_in;
1482 /* cache the domain_sid in the ldb */
1483 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1487 talloc_steal(ldb, invocation_id_new);
1488 talloc_free(tmp_ctx);
1489 talloc_free(invocation_id_old);
1494 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1495 talloc_free(tmp_ctx);
1500 work out the ntds settings objectGUID for the current open ldb
1502 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1504 TALLOC_CTX *tmp_ctx;
1505 const char *attrs[] = { "objectGUID", NULL };
1507 struct ldb_result *res;
1508 struct GUID *ntds_guid;
1510 /* see if we have a cached copy */
1511 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1516 tmp_ctx = talloc_new(ldb);
1517 if (tmp_ctx == NULL) {
1521 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1526 if (res->count != 1) {
1530 ntds_guid = talloc(tmp_ctx, struct GUID);
1535 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1537 /* cache the domain_sid in the ldb */
1538 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1542 talloc_steal(ldb, ntds_guid);
1543 talloc_free(tmp_ctx);
1548 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1549 talloc_free(tmp_ctx);
1553 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1555 TALLOC_CTX *tmp_ctx;
1556 struct GUID *ntds_guid_new;
1557 struct GUID *ntds_guid_old;
1559 /* see if we have a cached copy */
1560 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1562 tmp_ctx = talloc_new(ldb);
1563 if (tmp_ctx == NULL) {
1567 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1568 if (!ntds_guid_new) {
1572 *ntds_guid_new = *ntds_guid_in;
1574 /* cache the domain_sid in the ldb */
1575 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1579 talloc_steal(ldb, ntds_guid_new);
1580 talloc_free(tmp_ctx);
1581 talloc_free(ntds_guid_old);
1586 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1587 talloc_free(tmp_ctx);
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1600 work out the server dn for the current open ldb
1602 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1604 struct ldb_dn *server_dn;
1605 struct ldb_dn *servers_dn;
1606 struct ldb_dn *server_site_dn;
1608 /* TODO: there must be a saner way to do this!! */
1609 server_dn = samdb_server_dn(ldb, mem_ctx);
1610 if (!server_dn) return NULL;
1612 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1613 talloc_free(server_dn);
1614 if (!servers_dn) return NULL;
1616 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1617 talloc_free(servers_dn);
1619 return server_site_dn;
1623 find the site name from a computers DN record
1625 int samdb_find_site_for_computer(struct ldb_context *ldb,
1626 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1627 const char **site_name)
1631 const struct ldb_val *rdn_val;
1635 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1636 if (ret != LDB_SUCCESS) {
1640 if (!ldb_dn_remove_child_components(dn, 2)) {
1642 return LDB_ERR_INVALID_DN_SYNTAX;
1644 rdn_val = ldb_dn_get_rdn_val(dn);
1645 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1648 return LDB_ERR_OPERATIONS_ERROR;
1654 find the NTDS GUID from a computers DN record
1656 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1657 struct GUID *ntds_guid)
1662 *ntds_guid = GUID_zero();
1664 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1665 if (ret != LDB_SUCCESS) {
1669 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1671 return LDB_ERR_OPERATIONS_ERROR;
1674 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1680 find a 'reference' DN that points at another object
1681 (eg. serverReference, rIDManagerReference etc)
1683 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1684 const char *attribute, struct ldb_dn **dn)
1686 const char *attrs[2];
1687 struct ldb_result *res;
1690 attrs[0] = attribute;
1693 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1694 if (ret != LDB_SUCCESS) {
1698 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1700 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1701 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1702 ldb_dn_get_linearized(base));
1704 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1705 ldb_dn_get_linearized(base));
1708 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1716 find our machine account via the serverReference attribute in the
1719 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1721 struct ldb_dn *server_dn;
1724 server_dn = samdb_server_dn(ldb, mem_ctx);
1725 if (server_dn == NULL) {
1726 return LDB_ERR_NO_SUCH_OBJECT;
1729 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1730 talloc_free(server_dn);
1736 find the RID Manager$ DN via the rIDManagerReference attribute in the
1739 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1741 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1742 "rIDManagerReference", dn);
1746 find the RID Set DN via the rIDSetReferences attribute in our
1749 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1751 struct ldb_dn *server_ref_dn;
1754 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1755 if (ret != LDB_SUCCESS) {
1758 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1759 talloc_free(server_ref_dn);
1763 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1765 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1772 return (const char *) val->data;
1776 * Finds the client site by using the client's IP address.
1777 * The "subnet_name" returns the name of the subnet if parameter != NULL
1779 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1780 const char *ip_address, char **subnet_name)
1782 const char *attrs[] = { "cn", "siteObject", NULL };
1783 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1784 struct ldb_result *res;
1785 const struct ldb_val *val;
1786 const char *site_name = NULL, *l_subnet_name = NULL;
1787 const char *allow_list[2] = { NULL, NULL };
1788 unsigned int i, count;
1792 * if we don't have a client ip e.g. ncalrpc
1793 * the server site is the client site
1795 if (ip_address == NULL) {
1796 return samdb_server_site_name(ldb, mem_ctx);
1799 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1800 if (sites_container_dn == NULL) {
1804 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1805 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1806 talloc_free(sites_container_dn);
1807 talloc_free(subnets_dn);
1811 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1813 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1815 } else if (ret != LDB_SUCCESS) {
1816 talloc_free(sites_container_dn);
1817 talloc_free(subnets_dn);
1823 for (i = 0; i < count; i++) {
1824 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1827 allow_list[0] = l_subnet_name;
1829 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1830 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1833 if (sites_dn == NULL) {
1834 /* No reference, maybe another subnet matches */
1838 /* "val" cannot be NULL here since "sites_dn" != NULL */
1839 val = ldb_dn_get_rdn_val(sites_dn);
1840 site_name = talloc_strdup(mem_ctx,
1841 (const char *) val->data);
1843 talloc_free(sites_dn);
1849 if (site_name == NULL) {
1850 /* This is the Windows Server fallback rule: when no subnet
1851 * exists and we have only one site available then use it (it
1852 * is for sure the same as our server site). If more sites do
1853 * exist then we don't know which one to use and set the site
1855 cnt = samdb_search_count(ldb, sites_container_dn,
1856 "(objectClass=site)");
1858 site_name = samdb_server_site_name(ldb, mem_ctx);
1860 site_name = talloc_strdup(mem_ctx, "");
1862 l_subnet_name = NULL;
1865 if (subnet_name != NULL) {
1866 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1869 talloc_free(sites_container_dn);
1870 talloc_free(subnets_dn);
1877 work out if we are the PDC for the domain of the current open ldb
1879 bool samdb_is_pdc(struct ldb_context *ldb)
1881 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1883 struct ldb_result *dom_res;
1884 TALLOC_CTX *tmp_ctx;
1888 tmp_ctx = talloc_new(ldb);
1889 if (tmp_ctx == NULL) {
1890 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1894 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1895 if (ret != LDB_SUCCESS) {
1896 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1897 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1898 ldb_errstring(ldb)));
1901 if (dom_res->count != 1) {
1905 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1907 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1913 talloc_free(tmp_ctx);
1918 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1919 talloc_free(tmp_ctx);
1924 work out if we are a Global Catalog server for the domain of the current open ldb
1926 bool samdb_is_gc(struct ldb_context *ldb)
1928 const char *attrs[] = { "options", NULL };
1930 struct ldb_result *res;
1931 TALLOC_CTX *tmp_ctx;
1933 tmp_ctx = talloc_new(ldb);
1934 if (tmp_ctx == NULL) {
1935 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1939 /* Query cn=ntds settings,.... */
1940 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1941 if (ret != LDB_SUCCESS) {
1942 talloc_free(tmp_ctx);
1945 if (res->count != 1) {
1946 talloc_free(tmp_ctx);
1950 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1951 talloc_free(tmp_ctx);
1953 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1954 if (options & 0x000000001) {
1960 /* Find a domain object in the parents of a particular DN. */
1961 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1962 struct ldb_dn **parent_dn, const char **errstring)
1964 TALLOC_CTX *local_ctx;
1965 struct ldb_dn *sdn = dn;
1966 struct ldb_result *res = NULL;
1967 int ret = LDB_SUCCESS;
1968 const char *attrs[] = { NULL };
1970 local_ctx = talloc_new(mem_ctx);
1971 if (local_ctx == NULL) return ldb_oom(ldb);
1973 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1974 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1975 "(|(objectClass=domain)(objectClass=builtinDomain))");
1976 if (ret == LDB_SUCCESS) {
1977 if (res->count == 1) {
1985 if (ret != LDB_SUCCESS) {
1986 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1987 ldb_dn_get_linearized(dn),
1988 ldb_dn_get_linearized(sdn),
1989 ldb_errstring(ldb));
1990 talloc_free(local_ctx);
1993 if (res->count != 1) {
1994 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1995 ldb_dn_get_linearized(dn));
1996 DEBUG(0,(__location__ ": %s\n", *errstring));
1997 talloc_free(local_ctx);
1998 return LDB_ERR_CONSTRAINT_VIOLATION;
2001 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2002 talloc_free(local_ctx);
2008 * Performs checks on a user password (plaintext UNIX format - attribute
2009 * "password"). The remaining parameters have to be extracted from the domain
2012 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2014 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2015 const uint32_t pwdProperties,
2016 const uint32_t minPwdLength)
2018 /* checks if the "minPwdLength" property is satisfied */
2019 if (minPwdLength > password->length)
2020 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2022 /* checks the password complexity */
2023 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2024 && (password->data != NULL)
2025 && (!check_password_quality((const char *) password->data)))
2026 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2028 return SAMR_VALIDATION_STATUS_SUCCESS;
2032 * Callback for "samdb_set_password" password change
2034 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2039 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2042 if (ares->error != LDB_SUCCESS) {
2044 req->context = talloc_steal(req,
2045 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2047 return ldb_request_done(req, ret);
2050 if (ares->type != LDB_REPLY_DONE) {
2052 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2055 req->context = talloc_steal(req,
2056 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2058 return ldb_request_done(req, LDB_SUCCESS);
2062 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2063 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2064 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2065 * user change or not. The "rejectReason" gives some more informations if the
2068 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2069 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2071 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2072 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2073 const DATA_BLOB *new_password,
2074 const struct samr_Password *lmNewHash,
2075 const struct samr_Password *ntNewHash,
2076 const struct samr_Password *lmOldHash,
2077 const struct samr_Password *ntOldHash,
2078 enum samPwdChangeReason *reject_reason,
2079 struct samr_DomInfo1 **_dominfo)
2081 struct ldb_message *msg;
2082 struct ldb_message_element *el;
2083 struct ldb_request *req;
2084 struct dsdb_control_password_change_status *pwd_stat = NULL;
2086 NTSTATUS status = NT_STATUS_OK;
2088 #define CHECK_RET(x) \
2089 if (x != LDB_SUCCESS) { \
2091 return NT_STATUS_NO_MEMORY; \
2094 msg = ldb_msg_new(mem_ctx);
2096 return NT_STATUS_NO_MEMORY;
2099 if ((new_password != NULL)
2100 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2101 /* we have the password as plaintext UTF16 */
2102 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2103 "clearTextPassword", new_password));
2104 el = ldb_msg_find_element(msg, "clearTextPassword");
2105 el->flags = LDB_FLAG_MOD_REPLACE;
2106 } else if ((new_password == NULL)
2107 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2108 /* we have a password as LM and/or NT hash */
2109 if (lmNewHash != NULL) {
2110 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2111 "dBCSPwd", lmNewHash));
2112 el = ldb_msg_find_element(msg, "dBCSPwd");
2113 el->flags = LDB_FLAG_MOD_REPLACE;
2115 if (ntNewHash != NULL) {
2116 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2117 "unicodePwd", ntNewHash));
2118 el = ldb_msg_find_element(msg, "unicodePwd");
2119 el->flags = LDB_FLAG_MOD_REPLACE;
2122 /* the password wasn't specified correctly */
2124 return NT_STATUS_INVALID_PARAMETER;
2127 /* build modify request */
2128 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2129 samdb_set_password_callback, NULL);
2130 if (ret != LDB_SUCCESS) {
2132 return NT_STATUS_NO_MEMORY;
2135 /* A password change operation */
2136 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2137 struct dsdb_control_password_change *change;
2139 change = talloc(req, struct dsdb_control_password_change);
2140 if (change == NULL) {
2143 return NT_STATUS_NO_MEMORY;
2146 change->old_nt_pwd_hash = ntOldHash;
2147 change->old_lm_pwd_hash = lmOldHash;
2149 ret = ldb_request_add_control(req,
2150 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2152 if (ret != LDB_SUCCESS) {
2155 return NT_STATUS_NO_MEMORY;
2158 ret = ldb_request_add_control(req,
2159 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2161 if (ret != LDB_SUCCESS) {
2164 return NT_STATUS_NO_MEMORY;
2166 ret = ldb_request_add_control(req,
2167 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2169 if (ret != LDB_SUCCESS) {
2172 return NT_STATUS_NO_MEMORY;
2175 ret = dsdb_autotransaction_request(ldb, req);
2177 if (req->context != NULL) {
2178 pwd_stat = talloc_steal(mem_ctx,
2179 ((struct ldb_control *)req->context)->data);
2185 /* Sets the domain info (if requested) */
2186 if (_dominfo != NULL) {
2187 struct samr_DomInfo1 *dominfo;
2189 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2190 if (dominfo == NULL) {
2191 return NT_STATUS_NO_MEMORY;
2194 if (pwd_stat != NULL) {
2195 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2196 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2197 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2198 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2199 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2202 *_dominfo = dominfo;
2205 if (reject_reason != NULL) {
2206 if (pwd_stat != NULL) {
2207 *reject_reason = pwd_stat->reject_reason;
2209 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2213 if (pwd_stat != NULL) {
2214 talloc_free(pwd_stat);
2217 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2218 const char *errmsg = ldb_errstring(ldb);
2219 char *endptr = NULL;
2220 WERROR werr = WERR_GENERAL_FAILURE;
2221 status = NT_STATUS_UNSUCCESSFUL;
2222 if (errmsg != NULL) {
2223 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2225 if (endptr != errmsg) {
2226 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2227 status = NT_STATUS_WRONG_PASSWORD;
2229 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2230 status = NT_STATUS_PASSWORD_RESTRICTION;
2233 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2234 /* don't let the caller know if an account doesn't exist */
2235 status = NT_STATUS_WRONG_PASSWORD;
2236 } else if (ret != LDB_SUCCESS) {
2237 status = NT_STATUS_UNSUCCESSFUL;
2244 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2245 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2246 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2247 * user change or not. The "rejectReason" gives some more informations if the
2250 * This wrapper function for "samdb_set_password" takes a SID as input rather
2253 * This call encapsulates a new LDB transaction for changing the password;
2254 * therefore the user hasn't to start a new one.
2256 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2257 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2258 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2259 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2261 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2262 const struct dom_sid *user_sid,
2263 const DATA_BLOB *new_password,
2264 const struct samr_Password *lmNewHash,
2265 const struct samr_Password *ntNewHash,
2266 const struct samr_Password *lmOldHash,
2267 const struct samr_Password *ntOldHash,
2268 enum samPwdChangeReason *reject_reason,
2269 struct samr_DomInfo1 **_dominfo)
2272 struct ldb_dn *user_dn;
2275 ret = ldb_transaction_start(ldb);
2276 if (ret != LDB_SUCCESS) {
2277 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2278 return NT_STATUS_TRANSACTION_ABORTED;
2281 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2282 "(&(objectSid=%s)(objectClass=user))",
2283 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2285 ldb_transaction_cancel(ldb);
2286 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2287 dom_sid_string(mem_ctx, user_sid)));
2288 return NT_STATUS_NO_SUCH_USER;
2291 nt_status = samdb_set_password(ldb, mem_ctx,
2294 lmNewHash, ntNewHash,
2295 lmOldHash, ntOldHash,
2296 reject_reason, _dominfo);
2297 if (!NT_STATUS_IS_OK(nt_status)) {
2298 ldb_transaction_cancel(ldb);
2299 talloc_free(user_dn);
2303 ret = ldb_transaction_commit(ldb);
2304 if (ret != LDB_SUCCESS) {
2305 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2306 ldb_dn_get_linearized(user_dn),
2307 ldb_errstring(ldb)));
2308 talloc_free(user_dn);
2309 return NT_STATUS_TRANSACTION_ABORTED;
2312 talloc_free(user_dn);
2313 return NT_STATUS_OK;
2317 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2318 struct dom_sid *sid, struct ldb_dn **ret_dn)
2320 struct ldb_message *msg;
2321 struct ldb_dn *basedn;
2325 sidstr = dom_sid_string(mem_ctx, sid);
2326 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2328 /* We might have to create a ForeignSecurityPrincipal, even if this user
2329 * is in our own domain */
2331 msg = ldb_msg_new(sidstr);
2333 talloc_free(sidstr);
2334 return NT_STATUS_NO_MEMORY;
2337 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2338 ldb_get_default_basedn(sam_ctx),
2339 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2341 if (ret != LDB_SUCCESS) {
2342 DEBUG(0, ("Failed to find DN for "
2343 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2344 talloc_free(sidstr);
2345 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2348 /* add core elements to the ldb_message for the alias */
2350 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2351 talloc_free(sidstr);
2352 return NT_STATUS_NO_MEMORY;
2355 samdb_msg_add_string(sam_ctx, msg, msg,
2357 "foreignSecurityPrincipal");
2359 /* create the alias */
2360 ret = ldb_add(sam_ctx, msg);
2361 if (ret != LDB_SUCCESS) {
2362 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2364 ldb_dn_get_linearized(msg->dn),
2365 ldb_errstring(sam_ctx)));
2366 talloc_free(sidstr);
2367 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2370 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2371 talloc_free(sidstr);
2373 return NT_STATUS_OK;
2378 Find the DN of a domain, assuming it to be a dotted.dns name
2381 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2384 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2385 const char *binary_encoded;
2386 const char **split_realm;
2393 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2395 talloc_free(tmp_ctx);
2398 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2399 for (i=0; split_realm[i]; i++) {
2400 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2401 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2402 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2403 binary_encoded, ldb_dn_get_linearized(dn)));
2404 talloc_free(tmp_ctx);
2408 if (!ldb_dn_validate(dn)) {
2409 DEBUG(2, ("Failed to validated DN %s\n",
2410 ldb_dn_get_linearized(dn)));
2411 talloc_free(tmp_ctx);
2414 talloc_free(tmp_ctx);
2419 Find the DN of a domain, be it the netbios or DNS name
2421 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2422 const char *domain_name)
2424 const char * const domain_ref_attrs[] = {
2427 const char * const domain_ref2_attrs[] = {
2430 struct ldb_result *res_domain_ref;
2431 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2432 /* find the domain's DN */
2433 int ret_domain = ldb_search(ldb, mem_ctx,
2435 samdb_partitions_dn(ldb, mem_ctx),
2438 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2440 if (ret_domain != LDB_SUCCESS) {
2444 if (res_domain_ref->count == 0) {
2445 ret_domain = ldb_search(ldb, mem_ctx,
2447 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2450 "(objectclass=domain)");
2451 if (ret_domain != LDB_SUCCESS) {
2455 if (res_domain_ref->count == 1) {
2456 return res_domain_ref->msgs[0]->dn;
2461 if (res_domain_ref->count > 1) {
2462 DEBUG(0,("Found %d records matching domain [%s]\n",
2463 ret_domain, domain_name));
2467 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2473 use a GUID to find a DN
2475 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2476 TALLOC_CTX *mem_ctx,
2477 const struct GUID *guid, struct ldb_dn **dn)
2480 struct ldb_result *res;
2481 const char *attrs[] = { NULL };
2482 char *guid_str = GUID_string(mem_ctx, guid);
2485 return ldb_operr(ldb);
2488 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2489 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2490 DSDB_SEARCH_SHOW_EXTENDED_DN |
2491 DSDB_SEARCH_ONE_ONLY,
2492 "objectGUID=%s", guid_str);
2493 talloc_free(guid_str);
2494 if (ret != LDB_SUCCESS) {
2498 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2505 use a DN to find a GUID with a given attribute name
2507 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2508 struct ldb_dn *dn, const char *attribute,
2512 struct ldb_result *res;
2513 const char *attrs[2];
2514 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2516 attrs[0] = attribute;
2519 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2520 DSDB_SEARCH_SHOW_RECYCLED);
2521 if (ret != LDB_SUCCESS) {
2522 talloc_free(tmp_ctx);
2525 if (res->count < 1) {
2526 talloc_free(tmp_ctx);
2527 return LDB_ERR_NO_SUCH_OBJECT;
2529 *guid = samdb_result_guid(res->msgs[0], attribute);
2530 talloc_free(tmp_ctx);
2535 use a DN to find a GUID
2537 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2538 struct ldb_dn *dn, struct GUID *guid)
2540 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2546 adds the given GUID to the given ldb_message. This value is added
2547 for the given attr_name (may be either "objectGUID" or "parentGUID").
2549 int dsdb_msg_add_guid(struct ldb_message *msg,
2551 const char *attr_name)
2556 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2558 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2559 if (!NT_STATUS_IS_OK(status)) {
2560 ret = LDB_ERR_OPERATIONS_ERROR;
2564 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2565 if (ret != LDB_SUCCESS) {
2566 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2574 talloc_free(tmp_ctx);
2581 use a DN to find a SID
2583 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2584 struct ldb_dn *dn, struct dom_sid *sid)
2587 struct ldb_result *res;
2588 const char *attrs[] = { "objectSid", NULL };
2589 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2594 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2595 DSDB_SEARCH_SHOW_RECYCLED);
2596 if (ret != LDB_SUCCESS) {
2597 talloc_free(tmp_ctx);
2600 if (res->count < 1) {
2601 talloc_free(tmp_ctx);
2602 return LDB_ERR_NO_SUCH_OBJECT;
2604 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2606 talloc_free(tmp_ctx);
2607 return LDB_ERR_NO_SUCH_OBJECT;
2610 talloc_free(tmp_ctx);
2615 use a SID to find a DN
2617 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2618 TALLOC_CTX *mem_ctx,
2619 struct dom_sid *sid, struct ldb_dn **dn)
2622 struct ldb_result *res;
2623 const char *attrs[] = { NULL };
2624 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2627 return ldb_operr(ldb);
2630 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2631 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2632 DSDB_SEARCH_SHOW_EXTENDED_DN |
2633 DSDB_SEARCH_ONE_ONLY,
2634 "objectSid=%s", sid_str);
2635 talloc_free(sid_str);
2636 if (ret != LDB_SUCCESS) {
2640 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2647 load a repsFromTo blob list for a given partition GUID
2648 attr must be "repsFrom" or "repsTo"
2650 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2651 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2653 const char *attrs[] = { attr, NULL };
2654 struct ldb_result *res = NULL;
2655 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2657 struct ldb_message_element *el;
2662 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2664 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2665 talloc_free(tmp_ctx);
2666 return WERR_DS_DRA_INTERNAL_ERROR;
2669 el = ldb_msg_find_element(res->msgs[0], attr);
2671 /* it's OK to be empty */
2672 talloc_free(tmp_ctx);
2676 *count = el->num_values;
2677 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2679 talloc_free(tmp_ctx);
2680 return WERR_DS_DRA_INTERNAL_ERROR;
2683 for (i=0; i<(*count); i++) {
2684 enum ndr_err_code ndr_err;
2685 ndr_err = ndr_pull_struct_blob(&el->values[i],
2688 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2689 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2690 talloc_free(tmp_ctx);
2691 return WERR_DS_DRA_INTERNAL_ERROR;
2695 talloc_free(tmp_ctx);
2701 save the repsFromTo blob list for a given partition GUID
2702 attr must be "repsFrom" or "repsTo"
2704 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2705 const char *attr, struct repsFromToBlob *r, uint32_t count)
2707 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2708 struct ldb_message *msg;
2709 struct ldb_message_element *el;
2712 msg = ldb_msg_new(tmp_ctx);
2714 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2718 el->values = talloc_array(msg, struct ldb_val, count);
2723 for (i=0; i<count; i++) {
2725 enum ndr_err_code ndr_err;
2727 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2729 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2730 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2738 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2739 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2743 talloc_free(tmp_ctx);
2748 talloc_free(tmp_ctx);
2749 return WERR_DS_DRA_INTERNAL_ERROR;
2754 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2755 object for a partition
2757 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2758 uint64_t *uSN, uint64_t *urgent_uSN)
2760 struct ldb_request *req;
2762 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2763 struct dsdb_control_current_partition *p_ctrl;
2764 struct ldb_result *res;
2766 res = talloc_zero(tmp_ctx, struct ldb_result);
2768 talloc_free(tmp_ctx);
2769 return ldb_oom(ldb);
2772 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2773 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2777 res, ldb_search_default_callback,
2779 if (ret != LDB_SUCCESS) {
2780 talloc_free(tmp_ctx);
2784 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2785 if (p_ctrl == NULL) {
2786 talloc_free(tmp_ctx);
2787 return ldb_oom(ldb);
2789 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2792 ret = ldb_request_add_control(req,
2793 DSDB_CONTROL_CURRENT_PARTITION_OID,
2795 if (ret != LDB_SUCCESS) {
2796 talloc_free(tmp_ctx);
2800 /* Run the new request */
2801 ret = ldb_request(ldb, req);
2803 if (ret == LDB_SUCCESS) {
2804 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2807 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2808 /* it hasn't been created yet, which means
2809 an implicit value of zero */
2811 talloc_free(tmp_ctx);
2815 if (ret != LDB_SUCCESS) {
2816 talloc_free(tmp_ctx);
2820 if (res->count < 1) {
2826 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2828 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2832 talloc_free(tmp_ctx);
2837 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2838 const struct drsuapi_DsReplicaCursor2 *c2)
2840 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2843 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2844 const struct drsuapi_DsReplicaCursor *c2)
2846 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2851 see if a computer identified by its invocationId is a RODC
2853 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2855 /* 1) find the DN for this servers NTDSDSA object
2856 2) search for the msDS-isRODC attribute
2857 3) if not present then not a RODC
2858 4) if present and TRUE then is a RODC
2860 struct ldb_dn *config_dn;
2861 const char *attrs[] = { "msDS-isRODC", NULL };
2863 struct ldb_result *res;
2864 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2866 config_dn = ldb_get_config_basedn(sam_ctx);
2868 talloc_free(tmp_ctx);
2869 return ldb_operr(sam_ctx);
2872 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2873 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2875 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2877 talloc_free(tmp_ctx);
2881 if (ret != LDB_SUCCESS) {
2882 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2883 GUID_string(tmp_ctx, objectGUID)));
2885 talloc_free(tmp_ctx);
2889 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2890 *is_rodc = (ret == 1);
2892 talloc_free(tmp_ctx);
2898 see if we are a RODC
2900 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2902 const struct GUID *objectGUID;
2906 /* see if we have a cached copy */
2907 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2913 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2915 return ldb_operr(sam_ctx);
2918 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2919 if (ret != LDB_SUCCESS) {
2923 cached = talloc(sam_ctx, bool);
2924 if (cached == NULL) {
2925 return ldb_oom(sam_ctx);
2929 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2930 if (ret != LDB_SUCCESS) {
2931 talloc_free(cached);
2932 return ldb_operr(sam_ctx);
2938 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2940 TALLOC_CTX *tmp_ctx;
2943 tmp_ctx = talloc_new(ldb);
2944 if (tmp_ctx == NULL) {
2948 cached = talloc(tmp_ctx, bool);
2954 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2958 talloc_steal(ldb, cached);
2959 talloc_free(tmp_ctx);
2963 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2964 talloc_free(tmp_ctx);
2970 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2972 flags are DS_NTDS_OPTION_*
2974 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2976 TALLOC_CTX *tmp_ctx;
2977 const char *attrs[] = { "options", NULL };
2979 struct ldb_result *res;
2981 tmp_ctx = talloc_new(ldb);
2982 if (tmp_ctx == NULL) {
2986 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2987 if (ret != LDB_SUCCESS) {
2991 if (res->count != 1) {
2995 *options = samdb_result_uint(res->msgs[0], "options", 0);
2997 talloc_free(tmp_ctx);
3002 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3003 talloc_free(tmp_ctx);
3004 return LDB_ERR_NO_SUCH_OBJECT;
3007 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3009 const char *attrs[] = { "objectCategory", NULL };
3011 struct ldb_result *res;
3013 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3014 if (ret != LDB_SUCCESS) {
3018 if (res->count != 1) {
3022 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
3025 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3030 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3031 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3033 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3035 char **tokens, *ret;
3038 tokens = str_list_make(mem_ctx, cn, " -_");
3042 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3043 tokens[0][0] = tolower(tokens[0][0]);
3044 for (i = 1; i < str_list_length((const char **)tokens); i++)
3045 tokens[i][0] = toupper(tokens[i][0]);
3047 ret = talloc_strdup(mem_ctx, tokens[0]);
3048 for (i = 1; i < str_list_length((const char **)tokens); i++)
3049 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3051 talloc_free(tokens);
3057 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3059 int dsdb_functional_level(struct ldb_context *ldb)
3061 int *domainFunctionality =
3062 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3063 if (!domainFunctionality) {
3064 /* this is expected during initial provision */
3065 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3066 return DS_DOMAIN_FUNCTION_2000;
3068 return *domainFunctionality;
3072 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3074 int dsdb_forest_functional_level(struct ldb_context *ldb)
3076 int *forestFunctionality =
3077 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3078 if (!forestFunctionality) {
3079 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3080 return DS_DOMAIN_FUNCTION_2000;
3082 return *forestFunctionality;
3086 set a GUID in an extended DN structure
3088 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3094 status = GUID_to_ndr_blob(guid, dn, &v);
3095 if (!NT_STATUS_IS_OK(status)) {
3096 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3099 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3105 return a GUID from a extended DN structure
3107 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3109 const struct ldb_val *v;
3111 v = ldb_dn_get_extended_component(dn, component_name);
3113 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3116 return GUID_from_ndr_blob(v, guid);
3120 return a uint64_t from a extended DN structure
3122 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3124 const struct ldb_val *v;
3127 v = ldb_dn_get_extended_component(dn, component_name);
3129 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3131 s = talloc_strndup(dn, (const char *)v->data, v->length);
3132 NT_STATUS_HAVE_NO_MEMORY(s);
3134 *val = strtoull(s, NULL, 0);
3137 return NT_STATUS_OK;
3141 return a NTTIME from a extended DN structure
3143 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3145 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3149 return a uint32_t from a extended DN structure
3151 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3153 const struct ldb_val *v;
3156 v = ldb_dn_get_extended_component(dn, component_name);
3158 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3161 s = talloc_strndup(dn, (const char *)v->data, v->length);
3162 NT_STATUS_HAVE_NO_MEMORY(s);
3164 *val = strtoul(s, NULL, 0);
3167 return NT_STATUS_OK;
3171 return a dom_sid from a extended DN structure
3173 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3175 const struct ldb_val *sid_blob;
3176 struct TALLOC_CTX *tmp_ctx;
3177 enum ndr_err_code ndr_err;
3179 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3181 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3184 tmp_ctx = talloc_new(NULL);
3186 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3187 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3189 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3190 talloc_free(tmp_ctx);
3194 talloc_free(tmp_ctx);
3195 return NT_STATUS_OK;
3200 return RMD_FLAGS directly from a ldb_dn
3201 returns 0 if not found
3203 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3205 const struct ldb_val *v;
3207 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3208 if (!v || v->length > sizeof(buf)-1) return 0;
3209 strncpy(buf, (const char *)v->data, v->length);
3211 return strtoul(buf, NULL, 10);
3215 return RMD_FLAGS directly from a ldb_val for a DN
3216 returns 0 if RMD_FLAGS is not found
3218 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3224 if (val->length < 13) {
3227 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3231 flags = strtoul(p+11, &end, 10);
3232 if (!end || *end != '>') {
3233 /* it must end in a > */
3240 return true if a ldb_val containing a DN in storage form is deleted
3242 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3244 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3248 return true if a ldb_val containing a DN in storage form is
3249 in the upgraded w2k3 linked attribute format
3251 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3253 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3257 return a DN for a wellknown GUID
3259 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3260 struct ldb_dn *nc_root, const char *wk_guid,
3261 struct ldb_dn **wkguid_dn)
3263 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3264 const char *attrs[] = { NULL };
3267 struct ldb_result *res;
3269 /* construct the magic WKGUID DN */
3270 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3271 wk_guid, ldb_dn_get_linearized(nc_root));
3273 talloc_free(tmp_ctx);
3274 return ldb_operr(samdb);
3277 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3278 DSDB_SEARCH_SHOW_RECYCLED);
3279 if (ret != LDB_SUCCESS) {
3280 talloc_free(tmp_ctx);
3284 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3285 talloc_free(tmp_ctx);
3290 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3292 return ldb_dn_compare(*dn1, *dn2);
3296 find a NC root given a DN within the NC
3298 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3299 struct ldb_dn **nc_root)
3301 const char *root_attrs[] = { "namingContexts", NULL };
3302 TALLOC_CTX *tmp_ctx;
3304 struct ldb_message_element *el;
3305 struct ldb_result *root_res;
3307 struct ldb_dn **nc_dns;
3309 tmp_ctx = talloc_new(samdb);
3310 if (tmp_ctx == NULL) {
3311 return ldb_oom(samdb);
3314 ret = ldb_search(samdb, tmp_ctx, &root_res,
3315 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3316 if (ret != LDB_SUCCESS) {
3317 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3318 talloc_free(tmp_ctx);
3322 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3324 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3325 ldb_errstring(samdb)));
3326 talloc_free(tmp_ctx);
3327 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3330 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3332 talloc_free(tmp_ctx);
3333 return ldb_oom(samdb);
3336 for (i=0; i<el->num_values; i++) {
3337 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3338 if (nc_dns[i] == NULL) {
3339 talloc_free(tmp_ctx);
3340 return ldb_operr(samdb);
3344 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3346 for (i=0; i<el->num_values; i++) {
3347 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3348 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3349 talloc_free(tmp_ctx);
3354 talloc_free(tmp_ctx);
3355 return LDB_ERR_NO_SUCH_OBJECT;
3360 find the deleted objects DN for any object, by looking for the NC
3361 root, then looking up the wellknown GUID
3363 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3364 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3365 struct ldb_dn **do_dn)
3367 struct ldb_dn *nc_root;
3370 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3371 if (ret != LDB_SUCCESS) {
3375 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3376 talloc_free(nc_root);
3381 return the tombstoneLifetime, in days
3383 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3386 dn = ldb_get_config_basedn(ldb);
3388 return LDB_ERR_NO_SUCH_OBJECT;
3390 dn = ldb_dn_copy(ldb, dn);
3392 return ldb_operr(ldb);
3394 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3395 be a wellknown GUID for this */
3396 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3398 return ldb_operr(ldb);
3401 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3407 compare a ldb_val to a string case insensitively
3409 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3411 size_t len = strlen(s);
3413 if (len > v->length) return 1;
3414 ret = strncasecmp(s, (const char *)v->data, v->length);
3415 if (ret != 0) return ret;
3416 if (v->length > len && v->data[len] != 0) {
3424 load the UDV for a partition in v2 format
3425 The list is returned sorted, and with our local cursor added
3427 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3428 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3430 static const char *attrs[] = { "replUpToDateVector", NULL };
3431 struct ldb_result *r;
3432 const struct ldb_val *ouv_value;
3435 uint64_t highest_usn;
3436 const struct GUID *our_invocation_id;
3437 struct timeval now = timeval_current();
3439 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3440 if (ret != LDB_SUCCESS) {
3444 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3446 enum ndr_err_code ndr_err;
3447 struct replUpToDateVectorBlob ouv;
3449 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3450 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3451 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3453 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3455 if (ouv.version != 2) {
3456 /* we always store as version 2, and
3457 * replUpToDateVector is not replicated
3459 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3462 *count = ouv.ctr.ctr2.count;
3463 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3471 our_invocation_id = samdb_ntds_invocation_id(samdb);
3472 if (!our_invocation_id) {
3473 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3474 talloc_free(*cursors);
3475 return ldb_operr(samdb);
3478 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3479 if (ret != LDB_SUCCESS) {
3480 /* nothing to add - this can happen after a vampire */
3481 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3485 for (i=0; i<*count; i++) {
3486 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3487 (*cursors)[i].highest_usn = highest_usn;
3488 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3489 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3494 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3496 return ldb_oom(samdb);
3499 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3500 (*cursors)[*count].highest_usn = highest_usn;
3501 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3504 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3510 load the UDV for a partition in version 1 format
3511 The list is returned sorted, and with our local cursor added
3513 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3514 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3516 struct drsuapi_DsReplicaCursor2 *v2;
3520 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3521 if (ret != LDB_SUCCESS) {
3531 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3532 if (*cursors == NULL) {
3534 return ldb_oom(samdb);
3537 for (i=0; i<*count; i++) {
3538 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3539 (*cursors)[i].highest_usn = v2[i].highest_usn;
3546 add a set of controls to a ldb_request structure based on a set of
3547 flags. See util.h for a list of available flags
3549 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3552 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3553 struct ldb_search_options_control *options;
3554 /* Using the phantom root control allows us to search all partitions */
3555 options = talloc(req, struct ldb_search_options_control);
3556 if (options == NULL) {
3557 return LDB_ERR_OPERATIONS_ERROR;
3559 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3561 ret = ldb_request_add_control(req,
3562 LDB_CONTROL_SEARCH_OPTIONS_OID,
3564 if (ret != LDB_SUCCESS) {
3569 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3570 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3571 if (ret != LDB_SUCCESS) {
3576 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3577 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, true, NULL);
3578 if (ret != LDB_SUCCESS) {
3583 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3584 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3585 if (ret != LDB_SUCCESS) {
3590 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3591 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3592 if (!extended_ctrl) {
3593 return LDB_ERR_OPERATIONS_ERROR;
3595 extended_ctrl->type = 1;
3597 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3598 if (ret != LDB_SUCCESS) {
3603 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3604 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3605 if (ret != LDB_SUCCESS) {
3610 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3611 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3612 if (ret != LDB_SUCCESS) {
3617 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3618 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3619 if (ret != LDB_SUCCESS) {
3624 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3625 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3626 if (ret != LDB_SUCCESS) {
3631 if (dsdb_flags & DSDB_TREE_DELETE) {
3632 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3633 if (ret != LDB_SUCCESS) {
3642 an add with a set of controls
3644 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3645 uint32_t dsdb_flags)
3647 struct ldb_request *req;
3650 ret = ldb_build_add_req(&req, ldb, ldb,
3654 ldb_op_default_callback,
3657 if (ret != LDB_SUCCESS) return ret;
3659 ret = dsdb_request_add_controls(req, dsdb_flags);
3660 if (ret != LDB_SUCCESS) {
3665 ret = dsdb_autotransaction_request(ldb, req);
3672 a modify with a set of controls
3674 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3675 uint32_t dsdb_flags)
3677 struct ldb_request *req;
3680 ret = ldb_build_mod_req(&req, ldb, ldb,
3684 ldb_op_default_callback,
3687 if (ret != LDB_SUCCESS) return ret;
3689 ret = dsdb_request_add_controls(req, dsdb_flags);
3690 if (ret != LDB_SUCCESS) {
3695 ret = dsdb_autotransaction_request(ldb, req);
3702 like dsdb_modify() but set all the element flags to
3703 LDB_FLAG_MOD_REPLACE
3705 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3709 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3710 for (i=0;i<msg->num_elements;i++) {
3711 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3714 return dsdb_modify(ldb, msg, dsdb_flags);
3719 search for attrs on one DN, allowing for dsdb_flags controls
3721 int dsdb_search_dn(struct ldb_context *ldb,
3722 TALLOC_CTX *mem_ctx,
3723 struct ldb_result **_res,
3724 struct ldb_dn *basedn,
3725 const char * const *attrs,
3726 uint32_t dsdb_flags)
3729 struct ldb_request *req;
3730 struct ldb_result *res;
3732 res = talloc_zero(mem_ctx, struct ldb_result);
3734 return ldb_oom(ldb);
3737 ret = ldb_build_search_req(&req, ldb, res,
3744 ldb_search_default_callback,
3746 if (ret != LDB_SUCCESS) {
3751 ret = dsdb_request_add_controls(req, dsdb_flags);
3752 if (ret != LDB_SUCCESS) {
3757 ret = ldb_request(ldb, req);
3758 if (ret == LDB_SUCCESS) {
3759 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3763 if (ret != LDB_SUCCESS) {
3773 search for attrs on one DN, by the GUID of the DN, allowing for
3776 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3777 TALLOC_CTX *mem_ctx,
3778 struct ldb_result **_res,
3779 const struct GUID *guid,
3780 const char * const *attrs,
3781 uint32_t dsdb_flags)
3783 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3787 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3788 if (!ldb_dn_validate(dn)) {
3789 talloc_free(tmp_ctx);
3790 return LDB_ERR_INVALID_DN_SYNTAX;
3793 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3794 talloc_free(tmp_ctx);
3799 general search with dsdb_flags for controls
3801 int dsdb_search(struct ldb_context *ldb,
3802 TALLOC_CTX *mem_ctx,
3803 struct ldb_result **_res,
3804 struct ldb_dn *basedn,
3805 enum ldb_scope scope,
3806 const char * const *attrs,
3807 uint32_t dsdb_flags,
3808 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3811 struct ldb_request *req;
3812 struct ldb_result *res;
3814 char *expression = NULL;
3815 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3817 res = talloc_zero(tmp_ctx, struct ldb_result);
3819 talloc_free(tmp_ctx);
3820 return ldb_oom(ldb);
3824 va_start(ap, exp_fmt);
3825 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3829 talloc_free(tmp_ctx);
3830 return ldb_oom(ldb);
3834 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3841 ldb_search_default_callback,
3843 if (ret != LDB_SUCCESS) {
3844 talloc_free(tmp_ctx);
3848 ret = dsdb_request_add_controls(req, dsdb_flags);
3849 if (ret != LDB_SUCCESS) {
3850 talloc_free(tmp_ctx);
3851 ldb_reset_err_string(ldb);
3855 ret = ldb_request(ldb, req);
3856 if (ret == LDB_SUCCESS) {
3857 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3860 if (ret != LDB_SUCCESS) {
3861 talloc_free(tmp_ctx);
3865 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3866 if (res->count == 0) {
3867 talloc_free(tmp_ctx);
3868 ldb_reset_err_string(ldb);
3869 return LDB_ERR_NO_SUCH_OBJECT;
3871 if (res->count != 1) {
3872 talloc_free(tmp_ctx);
3873 ldb_reset_err_string(ldb);
3874 return LDB_ERR_CONSTRAINT_VIOLATION;
3878 *_res = talloc_steal(mem_ctx, res);
3879 talloc_free(tmp_ctx);
3886 general search with dsdb_flags for controls
3887 returns exactly 1 record or an error
3889 int dsdb_search_one(struct ldb_context *ldb,
3890 TALLOC_CTX *mem_ctx,
3891 struct ldb_message **msg,
3892 struct ldb_dn *basedn,
3893 enum ldb_scope scope,
3894 const char * const *attrs,
3895 uint32_t dsdb_flags,
3896 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3899 struct ldb_result *res;
3901 char *expression = NULL;
3902 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3904 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3906 res = talloc_zero(tmp_ctx, struct ldb_result);
3908 talloc_free(tmp_ctx);
3909 return ldb_oom(ldb);
3913 va_start(ap, exp_fmt);
3914 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3918 talloc_free(tmp_ctx);
3919 return ldb_oom(ldb);
3921 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3922 dsdb_flags, "%s", expression);
3924 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3928 if (ret != LDB_SUCCESS) {
3929 talloc_free(tmp_ctx);
3933 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3934 talloc_free(tmp_ctx);
3939 /* returns back the forest DNS name */
3940 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3942 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3943 ldb_get_root_basedn(ldb));
3946 if (forest_name == NULL) {
3950 p = strchr(forest_name, '/');
3959 validate that an DSA GUID belongs to the specified user sid.
3960 The user SID must be a domain controller account (either RODC or
3963 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3964 const struct GUID *dsa_guid,
3965 const struct dom_sid *sid)
3968 - find DN of record with the DSA GUID in the
3969 configuration partition (objectGUID)
3970 - remove "NTDS Settings" component from DN
3971 - do a base search on that DN for serverReference with
3973 - extract objectSid from resulting serverReference
3975 - check this sid matches the sid argument
3977 struct ldb_dn *config_dn;
3978 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3979 struct ldb_message *msg;
3980 const char *attrs1[] = { NULL };
3981 const char *attrs2[] = { "serverReference", NULL };
3983 struct ldb_dn *dn, *account_dn;
3984 struct dom_sid sid2;
3987 config_dn = ldb_get_config_basedn(ldb);
3989 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3990 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3991 if (ret != LDB_SUCCESS) {
3992 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3993 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3994 talloc_free(tmp_ctx);
3995 return ldb_operr(ldb);
3999 if (!ldb_dn_remove_child_components(dn, 1)) {
4000 talloc_free(tmp_ctx);
4001 return ldb_operr(ldb);
4004 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4005 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4006 "(objectClass=server)");
4007 if (ret != LDB_SUCCESS) {
4008 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4009 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4010 talloc_free(tmp_ctx);
4011 return ldb_operr(ldb);
4014 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4015 if (account_dn == NULL) {
4016 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4017 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4018 talloc_free(tmp_ctx);
4019 return ldb_operr(ldb);
4022 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4023 if (!NT_STATUS_IS_OK(status)) {
4024 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4025 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4026 talloc_free(tmp_ctx);
4027 return ldb_operr(ldb);
4030 if (!dom_sid_equal(sid, &sid2)) {
4031 /* someone is trying to spoof another account */
4032 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4033 GUID_string(tmp_ctx, dsa_guid),
4034 dom_sid_string(tmp_ctx, sid),
4035 dom_sid_string(tmp_ctx, &sid2)));
4036 talloc_free(tmp_ctx);
4037 return ldb_operr(ldb);
4040 talloc_free(tmp_ctx);
4044 static const char *secret_attributes[] = {
4047 "initialAuthIncoming",
4048 "initialAuthOutgoing",
4052 "supplementalCredentials",
4053 "trustAuthIncoming",
4054 "trustAuthOutgoing",
4060 check if the attribute belongs to the RODC filtered attribute set
4061 Note that attributes that are in the filtered attribute set are the
4062 ones that _are_ always sent to a RODC
4064 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4066 /* they never get secret attributes */
4067 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4071 /* they do get non-secret critical attributes */
4072 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4076 /* they do get non-secret attributes marked as being in the FAS */
4077 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4081 /* other attributes are denied */
4085 /* return fsmo role dn and role owner dn for a particular role*/
4086 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4087 struct ldb_context *ldb,
4089 struct ldb_dn **fsmo_role_dn,
4090 struct ldb_dn **role_owner_dn)
4094 case DREPL_NAMING_MASTER:
4095 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4096 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4097 if (ret != LDB_SUCCESS) {
4098 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4099 ldb_errstring(ldb)));
4100 talloc_free(tmp_ctx);
4101 return WERR_DS_DRA_INTERNAL_ERROR;
4104 case DREPL_INFRASTRUCTURE_MASTER:
4105 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4106 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4107 if (ret != LDB_SUCCESS) {
4108 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4109 ldb_errstring(ldb)));
4110 talloc_free(tmp_ctx);
4111 return WERR_DS_DRA_INTERNAL_ERROR;
4114 case DREPL_RID_MASTER:
4115 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4116 if (ret != LDB_SUCCESS) {
4117 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4118 talloc_free(tmp_ctx);
4119 return WERR_DS_DRA_INTERNAL_ERROR;
4122 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4123 if (ret != LDB_SUCCESS) {
4124 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4125 ldb_errstring(ldb)));
4126 talloc_free(tmp_ctx);
4127 return WERR_DS_DRA_INTERNAL_ERROR;
4130 case DREPL_SCHEMA_MASTER:
4131 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4132 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4133 if (ret != LDB_SUCCESS) {
4134 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4135 ldb_errstring(ldb)));
4136 talloc_free(tmp_ctx);
4137 return WERR_DS_DRA_INTERNAL_ERROR;
4140 case DREPL_PDC_MASTER:
4141 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4142 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4143 if (ret != LDB_SUCCESS) {
4144 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4145 ldb_errstring(ldb)));
4146 talloc_free(tmp_ctx);
4147 return WERR_DS_DRA_INTERNAL_ERROR;
4151 return WERR_DS_DRA_INTERNAL_ERROR;
4156 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4157 TALLOC_CTX *mem_ctx,
4158 struct ldb_dn *server_dn)
4161 struct ldb_result *res = NULL;
4162 const char * const attrs[] = { "dNSHostName", NULL};
4164 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4168 if (ldb_ret != LDB_SUCCESS) {
4169 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4170 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4174 return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
4178 returns true if an attribute is in the filter,
4179 false otherwise, provided that attribute value is provided with the expression
4181 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4185 switch (tree->operation) {
4188 for (i=0;i<tree->u.list.num_elements;i++) {
4189 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4195 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4196 case LDB_OP_EQUALITY:
4197 case LDB_OP_GREATER:
4200 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4204 case LDB_OP_SUBSTRING:
4205 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4209 case LDB_OP_PRESENT:
4210 /* (attrname=*) is not filtered out */
4212 case LDB_OP_EXTENDED:
4213 if (tree->u.extended.attr &&
4214 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {