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, DSDB_SEARCH_SHOW_DELETED);
2520 if (ret != LDB_SUCCESS) {
2521 talloc_free(tmp_ctx);
2524 if (res->count < 1) {
2525 talloc_free(tmp_ctx);
2526 return LDB_ERR_NO_SUCH_OBJECT;
2528 *guid = samdb_result_guid(res->msgs[0], attribute);
2529 talloc_free(tmp_ctx);
2534 use a DN to find a GUID
2536 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2537 struct ldb_dn *dn, struct GUID *guid)
2539 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2545 adds the given GUID to the given ldb_message. This value is added
2546 for the given attr_name (may be either "objectGUID" or "parentGUID").
2548 int dsdb_msg_add_guid(struct ldb_message *msg,
2550 const char *attr_name)
2555 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2557 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2558 if (!NT_STATUS_IS_OK(status)) {
2559 ret = LDB_ERR_OPERATIONS_ERROR;
2563 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2564 if (ret != LDB_SUCCESS) {
2565 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2573 talloc_free(tmp_ctx);
2580 use a DN to find a SID
2582 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2583 struct ldb_dn *dn, struct dom_sid *sid)
2586 struct ldb_result *res;
2587 const char *attrs[] = { "objectSid", NULL };
2588 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2593 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2594 if (ret != LDB_SUCCESS) {
2595 talloc_free(tmp_ctx);
2598 if (res->count < 1) {
2599 talloc_free(tmp_ctx);
2600 return LDB_ERR_NO_SUCH_OBJECT;
2602 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2604 talloc_free(tmp_ctx);
2605 return LDB_ERR_NO_SUCH_OBJECT;
2608 talloc_free(tmp_ctx);
2613 use a SID to find a DN
2615 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2616 TALLOC_CTX *mem_ctx,
2617 struct dom_sid *sid, struct ldb_dn **dn)
2620 struct ldb_result *res;
2621 const char *attrs[] = { NULL };
2622 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2625 return ldb_operr(ldb);
2628 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2629 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2630 DSDB_SEARCH_SHOW_EXTENDED_DN |
2631 DSDB_SEARCH_ONE_ONLY,
2632 "objectSid=%s", sid_str);
2633 talloc_free(sid_str);
2634 if (ret != LDB_SUCCESS) {
2638 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2645 load a repsFromTo blob list for a given partition GUID
2646 attr must be "repsFrom" or "repsTo"
2648 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2649 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2651 const char *attrs[] = { attr, NULL };
2652 struct ldb_result *res = NULL;
2653 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2655 struct ldb_message_element *el;
2660 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2662 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2663 talloc_free(tmp_ctx);
2664 return WERR_DS_DRA_INTERNAL_ERROR;
2667 el = ldb_msg_find_element(res->msgs[0], attr);
2669 /* it's OK to be empty */
2670 talloc_free(tmp_ctx);
2674 *count = el->num_values;
2675 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2677 talloc_free(tmp_ctx);
2678 return WERR_DS_DRA_INTERNAL_ERROR;
2681 for (i=0; i<(*count); i++) {
2682 enum ndr_err_code ndr_err;
2683 ndr_err = ndr_pull_struct_blob(&el->values[i],
2686 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2687 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2688 talloc_free(tmp_ctx);
2689 return WERR_DS_DRA_INTERNAL_ERROR;
2693 talloc_free(tmp_ctx);
2699 save the repsFromTo blob list for a given partition GUID
2700 attr must be "repsFrom" or "repsTo"
2702 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2703 const char *attr, struct repsFromToBlob *r, uint32_t count)
2705 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2706 struct ldb_message *msg;
2707 struct ldb_message_element *el;
2710 msg = ldb_msg_new(tmp_ctx);
2712 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2716 el->values = talloc_array(msg, struct ldb_val, count);
2721 for (i=0; i<count; i++) {
2723 enum ndr_err_code ndr_err;
2725 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2727 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2728 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2736 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2737 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2741 talloc_free(tmp_ctx);
2746 talloc_free(tmp_ctx);
2747 return WERR_DS_DRA_INTERNAL_ERROR;
2752 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2753 object for a partition
2755 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2756 uint64_t *uSN, uint64_t *urgent_uSN)
2758 struct ldb_request *req;
2760 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2761 struct dsdb_control_current_partition *p_ctrl;
2762 struct ldb_result *res;
2764 res = talloc_zero(tmp_ctx, struct ldb_result);
2766 talloc_free(tmp_ctx);
2767 return ldb_oom(ldb);
2770 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2771 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2775 res, ldb_search_default_callback,
2777 if (ret != LDB_SUCCESS) {
2778 talloc_free(tmp_ctx);
2782 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2783 if (p_ctrl == NULL) {
2784 talloc_free(tmp_ctx);
2785 return ldb_oom(ldb);
2787 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2790 ret = ldb_request_add_control(req,
2791 DSDB_CONTROL_CURRENT_PARTITION_OID,
2793 if (ret != LDB_SUCCESS) {
2794 talloc_free(tmp_ctx);
2798 /* Run the new request */
2799 ret = ldb_request(ldb, req);
2801 if (ret == LDB_SUCCESS) {
2802 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2805 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2806 /* it hasn't been created yet, which means
2807 an implicit value of zero */
2809 talloc_free(tmp_ctx);
2813 if (ret != LDB_SUCCESS) {
2814 talloc_free(tmp_ctx);
2818 if (res->count < 1) {
2824 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2826 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2830 talloc_free(tmp_ctx);
2835 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2836 const struct drsuapi_DsReplicaCursor2 *c2)
2838 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2841 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2842 const struct drsuapi_DsReplicaCursor *c2)
2844 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2849 see if a computer identified by its invocationId is a RODC
2851 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2853 /* 1) find the DN for this servers NTDSDSA object
2854 2) search for the msDS-isRODC attribute
2855 3) if not present then not a RODC
2856 4) if present and TRUE then is a RODC
2858 struct ldb_dn *config_dn;
2859 const char *attrs[] = { "msDS-isRODC", NULL };
2861 struct ldb_result *res;
2862 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2864 config_dn = ldb_get_config_basedn(sam_ctx);
2866 talloc_free(tmp_ctx);
2867 return ldb_operr(sam_ctx);
2870 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2871 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2873 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2875 talloc_free(tmp_ctx);
2879 if (ret != LDB_SUCCESS) {
2880 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2881 GUID_string(tmp_ctx, objectGUID)));
2883 talloc_free(tmp_ctx);
2887 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2888 *is_rodc = (ret == 1);
2890 talloc_free(tmp_ctx);
2896 see if we are a RODC
2898 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2900 const struct GUID *objectGUID;
2904 /* see if we have a cached copy */
2905 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2911 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2913 return ldb_operr(sam_ctx);
2916 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2917 if (ret != LDB_SUCCESS) {
2921 cached = talloc(sam_ctx, bool);
2922 if (cached == NULL) {
2923 return ldb_oom(sam_ctx);
2927 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2928 if (ret != LDB_SUCCESS) {
2929 talloc_free(cached);
2930 return ldb_operr(sam_ctx);
2936 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2938 TALLOC_CTX *tmp_ctx;
2941 tmp_ctx = talloc_new(ldb);
2942 if (tmp_ctx == NULL) {
2946 cached = talloc(tmp_ctx, bool);
2952 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2956 talloc_steal(ldb, cached);
2957 talloc_free(tmp_ctx);
2961 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2962 talloc_free(tmp_ctx);
2968 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2970 flags are DS_NTDS_OPTION_*
2972 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2974 TALLOC_CTX *tmp_ctx;
2975 const char *attrs[] = { "options", NULL };
2977 struct ldb_result *res;
2979 tmp_ctx = talloc_new(ldb);
2980 if (tmp_ctx == NULL) {
2984 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2985 if (ret != LDB_SUCCESS) {
2989 if (res->count != 1) {
2993 *options = samdb_result_uint(res->msgs[0], "options", 0);
2995 talloc_free(tmp_ctx);
3000 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3001 talloc_free(tmp_ctx);
3002 return LDB_ERR_NO_SUCH_OBJECT;
3005 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3007 const char *attrs[] = { "objectCategory", NULL };
3009 struct ldb_result *res;
3011 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3012 if (ret != LDB_SUCCESS) {
3016 if (res->count != 1) {
3020 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
3023 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3028 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3029 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3031 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3033 char **tokens, *ret;
3036 tokens = str_list_make(mem_ctx, cn, " -_");
3040 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3041 tokens[0][0] = tolower(tokens[0][0]);
3042 for (i = 1; i < str_list_length((const char **)tokens); i++)
3043 tokens[i][0] = toupper(tokens[i][0]);
3045 ret = talloc_strdup(mem_ctx, tokens[0]);
3046 for (i = 1; i < str_list_length((const char **)tokens); i++)
3047 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3049 talloc_free(tokens);
3055 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3057 int dsdb_functional_level(struct ldb_context *ldb)
3059 int *domainFunctionality =
3060 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3061 if (!domainFunctionality) {
3062 /* this is expected during initial provision */
3063 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3064 return DS_DOMAIN_FUNCTION_2000;
3066 return *domainFunctionality;
3070 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3072 int dsdb_forest_functional_level(struct ldb_context *ldb)
3074 int *forestFunctionality =
3075 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3076 if (!forestFunctionality) {
3077 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3078 return DS_DOMAIN_FUNCTION_2000;
3080 return *forestFunctionality;
3084 set a GUID in an extended DN structure
3086 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3092 status = GUID_to_ndr_blob(guid, dn, &v);
3093 if (!NT_STATUS_IS_OK(status)) {
3094 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3097 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3103 return a GUID from a extended DN structure
3105 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3107 const struct ldb_val *v;
3109 v = ldb_dn_get_extended_component(dn, component_name);
3111 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3114 return GUID_from_ndr_blob(v, guid);
3118 return a uint64_t from a extended DN structure
3120 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3122 const struct ldb_val *v;
3125 v = ldb_dn_get_extended_component(dn, component_name);
3127 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3129 s = talloc_strndup(dn, (const char *)v->data, v->length);
3130 NT_STATUS_HAVE_NO_MEMORY(s);
3132 *val = strtoull(s, NULL, 0);
3135 return NT_STATUS_OK;
3139 return a NTTIME from a extended DN structure
3141 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3143 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3147 return a uint32_t from a extended DN structure
3149 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3151 const struct ldb_val *v;
3154 v = ldb_dn_get_extended_component(dn, component_name);
3156 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3159 s = talloc_strndup(dn, (const char *)v->data, v->length);
3160 NT_STATUS_HAVE_NO_MEMORY(s);
3162 *val = strtoul(s, NULL, 0);
3165 return NT_STATUS_OK;
3169 return a dom_sid from a extended DN structure
3171 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3173 const struct ldb_val *sid_blob;
3174 struct TALLOC_CTX *tmp_ctx;
3175 enum ndr_err_code ndr_err;
3177 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3179 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3182 tmp_ctx = talloc_new(NULL);
3184 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3185 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3186 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3187 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3188 talloc_free(tmp_ctx);
3192 talloc_free(tmp_ctx);
3193 return NT_STATUS_OK;
3198 return RMD_FLAGS directly from a ldb_dn
3199 returns 0 if not found
3201 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3203 const struct ldb_val *v;
3205 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3206 if (!v || v->length > sizeof(buf)-1) return 0;
3207 strncpy(buf, (const char *)v->data, v->length);
3209 return strtoul(buf, NULL, 10);
3213 return RMD_FLAGS directly from a ldb_val for a DN
3214 returns 0 if RMD_FLAGS is not found
3216 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3222 if (val->length < 13) {
3225 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3229 flags = strtoul(p+11, &end, 10);
3230 if (!end || *end != '>') {
3231 /* it must end in a > */
3238 return true if a ldb_val containing a DN in storage form is deleted
3240 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3242 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3246 return true if a ldb_val containing a DN in storage form is
3247 in the upgraded w2k3 linked attribute format
3249 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3251 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3255 return a DN for a wellknown GUID
3257 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3258 struct ldb_dn *nc_root, const char *wk_guid,
3259 struct ldb_dn **wkguid_dn)
3261 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3262 const char *attrs[] = { NULL };
3265 struct ldb_result *res;
3267 /* construct the magic WKGUID DN */
3268 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3269 wk_guid, ldb_dn_get_linearized(nc_root));
3271 talloc_free(tmp_ctx);
3272 return ldb_operr(samdb);
3275 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3276 if (ret != LDB_SUCCESS) {
3277 talloc_free(tmp_ctx);
3281 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3282 talloc_free(tmp_ctx);
3287 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3289 return ldb_dn_compare(*dn1, *dn2);
3293 find a NC root given a DN within the NC
3295 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3296 struct ldb_dn **nc_root)
3298 const char *root_attrs[] = { "namingContexts", NULL };
3299 TALLOC_CTX *tmp_ctx;
3301 struct ldb_message_element *el;
3302 struct ldb_result *root_res;
3304 struct ldb_dn **nc_dns;
3306 tmp_ctx = talloc_new(samdb);
3307 if (tmp_ctx == NULL) {
3308 return ldb_oom(samdb);
3311 ret = ldb_search(samdb, tmp_ctx, &root_res,
3312 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3313 if (ret != LDB_SUCCESS) {
3314 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3315 talloc_free(tmp_ctx);
3319 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3321 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3322 ldb_errstring(samdb)));
3323 talloc_free(tmp_ctx);
3324 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3327 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3329 talloc_free(tmp_ctx);
3330 return ldb_oom(samdb);
3333 for (i=0; i<el->num_values; i++) {
3334 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3335 if (nc_dns[i] == NULL) {
3336 talloc_free(tmp_ctx);
3337 return ldb_operr(samdb);
3341 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3343 for (i=0; i<el->num_values; i++) {
3344 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3345 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3346 talloc_free(tmp_ctx);
3351 talloc_free(tmp_ctx);
3352 return LDB_ERR_NO_SUCH_OBJECT;
3357 find the deleted objects DN for any object, by looking for the NC
3358 root, then looking up the wellknown GUID
3360 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3361 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3362 struct ldb_dn **do_dn)
3364 struct ldb_dn *nc_root;
3367 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3368 if (ret != LDB_SUCCESS) {
3372 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3373 talloc_free(nc_root);
3378 return the tombstoneLifetime, in days
3380 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3383 dn = ldb_get_config_basedn(ldb);
3385 return LDB_ERR_NO_SUCH_OBJECT;
3387 dn = ldb_dn_copy(ldb, dn);
3389 return ldb_operr(ldb);
3391 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3392 be a wellknown GUID for this */
3393 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3395 return ldb_operr(ldb);
3398 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3404 compare a ldb_val to a string case insensitively
3406 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3408 size_t len = strlen(s);
3410 if (len > v->length) return 1;
3411 ret = strncasecmp(s, (const char *)v->data, v->length);
3412 if (ret != 0) return ret;
3413 if (v->length > len && v->data[len] != 0) {
3421 load the UDV for a partition in v2 format
3422 The list is returned sorted, and with our local cursor added
3424 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3425 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3427 static const char *attrs[] = { "replUpToDateVector", NULL };
3428 struct ldb_result *r;
3429 const struct ldb_val *ouv_value;
3432 uint64_t highest_usn;
3433 const struct GUID *our_invocation_id;
3434 struct timeval now = timeval_current();
3436 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3437 if (ret != LDB_SUCCESS) {
3441 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3443 enum ndr_err_code ndr_err;
3444 struct replUpToDateVectorBlob ouv;
3446 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3447 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3448 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3450 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3452 if (ouv.version != 2) {
3453 /* we always store as version 2, and
3454 * replUpToDateVector is not replicated
3456 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3459 *count = ouv.ctr.ctr2.count;
3460 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3468 our_invocation_id = samdb_ntds_invocation_id(samdb);
3469 if (!our_invocation_id) {
3470 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3471 talloc_free(*cursors);
3472 return ldb_operr(samdb);
3475 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3476 if (ret != LDB_SUCCESS) {
3477 /* nothing to add - this can happen after a vampire */
3478 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3482 for (i=0; i<*count; i++) {
3483 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3484 (*cursors)[i].highest_usn = highest_usn;
3485 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3486 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3491 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3493 return ldb_oom(samdb);
3496 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3497 (*cursors)[*count].highest_usn = highest_usn;
3498 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3501 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3507 load the UDV for a partition in version 1 format
3508 The list is returned sorted, and with our local cursor added
3510 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3511 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3513 struct drsuapi_DsReplicaCursor2 *v2;
3517 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3518 if (ret != LDB_SUCCESS) {
3528 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3529 if (*cursors == NULL) {
3531 return ldb_oom(samdb);
3534 for (i=0; i<*count; i++) {
3535 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3536 (*cursors)[i].highest_usn = v2[i].highest_usn;
3543 add a set of controls to a ldb_request structure based on a set of
3544 flags. See util.h for a list of available flags
3546 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3549 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3550 struct ldb_search_options_control *options;
3551 /* Using the phantom root control allows us to search all partitions */
3552 options = talloc(req, struct ldb_search_options_control);
3553 if (options == NULL) {
3554 return LDB_ERR_OPERATIONS_ERROR;
3556 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3558 ret = ldb_request_add_control(req,
3559 LDB_CONTROL_SEARCH_OPTIONS_OID,
3561 if (ret != LDB_SUCCESS) {
3566 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3567 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3568 if (ret != LDB_SUCCESS) {
3573 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3574 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, true, NULL);
3575 if (ret != LDB_SUCCESS) {
3580 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3581 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3582 if (ret != LDB_SUCCESS) {
3587 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3588 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3589 if (!extended_ctrl) {
3590 return LDB_ERR_OPERATIONS_ERROR;
3592 extended_ctrl->type = 1;
3594 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3595 if (ret != LDB_SUCCESS) {
3600 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3601 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3602 if (ret != LDB_SUCCESS) {
3607 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3608 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3609 if (ret != LDB_SUCCESS) {
3614 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3615 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3616 if (ret != LDB_SUCCESS) {
3621 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3622 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3623 if (ret != LDB_SUCCESS) {
3628 if (dsdb_flags & DSDB_TREE_DELETE) {
3629 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3630 if (ret != LDB_SUCCESS) {
3639 an add with a set of controls
3641 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3642 uint32_t dsdb_flags)
3644 struct ldb_request *req;
3647 ret = ldb_build_add_req(&req, ldb, ldb,
3651 ldb_op_default_callback,
3654 if (ret != LDB_SUCCESS) return ret;
3656 ret = dsdb_request_add_controls(req, dsdb_flags);
3657 if (ret != LDB_SUCCESS) {
3662 ret = dsdb_autotransaction_request(ldb, req);
3669 a modify with a set of controls
3671 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3672 uint32_t dsdb_flags)
3674 struct ldb_request *req;
3677 ret = ldb_build_mod_req(&req, ldb, ldb,
3681 ldb_op_default_callback,
3684 if (ret != LDB_SUCCESS) return ret;
3686 ret = dsdb_request_add_controls(req, dsdb_flags);
3687 if (ret != LDB_SUCCESS) {
3692 ret = dsdb_autotransaction_request(ldb, req);
3699 like dsdb_modify() but set all the element flags to
3700 LDB_FLAG_MOD_REPLACE
3702 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3706 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3707 for (i=0;i<msg->num_elements;i++) {
3708 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3711 return dsdb_modify(ldb, msg, dsdb_flags);
3716 search for attrs on one DN, allowing for dsdb_flags controls
3718 int dsdb_search_dn(struct ldb_context *ldb,
3719 TALLOC_CTX *mem_ctx,
3720 struct ldb_result **_res,
3721 struct ldb_dn *basedn,
3722 const char * const *attrs,
3723 uint32_t dsdb_flags)
3726 struct ldb_request *req;
3727 struct ldb_result *res;
3729 res = talloc_zero(mem_ctx, struct ldb_result);
3731 return ldb_oom(ldb);
3734 ret = ldb_build_search_req(&req, ldb, res,
3741 ldb_search_default_callback,
3743 if (ret != LDB_SUCCESS) {
3748 ret = dsdb_request_add_controls(req, dsdb_flags);
3749 if (ret != LDB_SUCCESS) {
3754 ret = ldb_request(ldb, req);
3755 if (ret == LDB_SUCCESS) {
3756 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3760 if (ret != LDB_SUCCESS) {
3770 search for attrs on one DN, by the GUID of the DN, allowing for
3773 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3774 TALLOC_CTX *mem_ctx,
3775 struct ldb_result **_res,
3776 const struct GUID *guid,
3777 const char * const *attrs,
3778 uint32_t dsdb_flags)
3780 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3784 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3785 if (!ldb_dn_validate(dn)) {
3786 talloc_free(tmp_ctx);
3787 return LDB_ERR_INVALID_DN_SYNTAX;
3790 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3791 talloc_free(tmp_ctx);
3796 general search with dsdb_flags for controls
3798 int dsdb_search(struct ldb_context *ldb,
3799 TALLOC_CTX *mem_ctx,
3800 struct ldb_result **_res,
3801 struct ldb_dn *basedn,
3802 enum ldb_scope scope,
3803 const char * const *attrs,
3804 uint32_t dsdb_flags,
3805 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3808 struct ldb_request *req;
3809 struct ldb_result *res;
3811 char *expression = NULL;
3812 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3814 res = talloc_zero(tmp_ctx, struct ldb_result);
3816 talloc_free(tmp_ctx);
3817 return ldb_oom(ldb);
3821 va_start(ap, exp_fmt);
3822 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3826 talloc_free(tmp_ctx);
3827 return ldb_oom(ldb);
3831 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3838 ldb_search_default_callback,
3840 if (ret != LDB_SUCCESS) {
3841 talloc_free(tmp_ctx);
3845 ret = dsdb_request_add_controls(req, dsdb_flags);
3846 if (ret != LDB_SUCCESS) {
3847 talloc_free(tmp_ctx);
3848 ldb_reset_err_string(ldb);
3852 ret = ldb_request(ldb, req);
3853 if (ret == LDB_SUCCESS) {
3854 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3857 if (ret != LDB_SUCCESS) {
3858 talloc_free(tmp_ctx);
3862 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3863 if (res->count == 0) {
3864 talloc_free(tmp_ctx);
3865 ldb_reset_err_string(ldb);
3866 return LDB_ERR_NO_SUCH_OBJECT;
3868 if (res->count != 1) {
3869 talloc_free(tmp_ctx);
3870 ldb_reset_err_string(ldb);
3871 return LDB_ERR_CONSTRAINT_VIOLATION;
3875 *_res = talloc_steal(mem_ctx, res);
3876 talloc_free(tmp_ctx);
3883 general search with dsdb_flags for controls
3884 returns exactly 1 record or an error
3886 int dsdb_search_one(struct ldb_context *ldb,
3887 TALLOC_CTX *mem_ctx,
3888 struct ldb_message **msg,
3889 struct ldb_dn *basedn,
3890 enum ldb_scope scope,
3891 const char * const *attrs,
3892 uint32_t dsdb_flags,
3893 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3896 struct ldb_result *res;
3898 char *expression = NULL;
3899 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3901 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3903 res = talloc_zero(tmp_ctx, struct ldb_result);
3905 talloc_free(tmp_ctx);
3906 return ldb_oom(ldb);
3910 va_start(ap, exp_fmt);
3911 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3915 talloc_free(tmp_ctx);
3916 return ldb_oom(ldb);
3918 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3919 dsdb_flags, "%s", expression);
3921 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3925 if (ret != LDB_SUCCESS) {
3926 talloc_free(tmp_ctx);
3930 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3931 talloc_free(tmp_ctx);
3936 /* returns back the forest DNS name */
3937 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3939 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3940 ldb_get_root_basedn(ldb));
3943 if (forest_name == NULL) {
3947 p = strchr(forest_name, '/');
3956 validate that an DSA GUID belongs to the specified user sid.
3957 The user SID must be a domain controller account (either RODC or
3960 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3961 const struct GUID *dsa_guid,
3962 const struct dom_sid *sid)
3965 - find DN of record with the DSA GUID in the
3966 configuration partition (objectGUID)
3967 - remove "NTDS Settings" component from DN
3968 - do a base search on that DN for serverReference with
3970 - extract objectSid from resulting serverReference
3972 - check this sid matches the sid argument
3974 struct ldb_dn *config_dn;
3975 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3976 struct ldb_message *msg;
3977 const char *attrs1[] = { NULL };
3978 const char *attrs2[] = { "serverReference", NULL };
3980 struct ldb_dn *dn, *account_dn;
3981 struct dom_sid sid2;
3984 config_dn = ldb_get_config_basedn(ldb);
3986 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3987 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3988 if (ret != LDB_SUCCESS) {
3989 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3990 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3991 talloc_free(tmp_ctx);
3992 return ldb_operr(ldb);
3996 if (!ldb_dn_remove_child_components(dn, 1)) {
3997 talloc_free(tmp_ctx);
3998 return ldb_operr(ldb);
4001 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4002 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4003 "(objectClass=server)");
4004 if (ret != LDB_SUCCESS) {
4005 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4006 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4007 talloc_free(tmp_ctx);
4008 return ldb_operr(ldb);
4011 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4012 if (account_dn == NULL) {
4013 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4014 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4015 talloc_free(tmp_ctx);
4016 return ldb_operr(ldb);
4019 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4020 if (!NT_STATUS_IS_OK(status)) {
4021 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4022 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4023 talloc_free(tmp_ctx);
4024 return ldb_operr(ldb);
4027 if (!dom_sid_equal(sid, &sid2)) {
4028 /* someone is trying to spoof another account */
4029 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4030 GUID_string(tmp_ctx, dsa_guid),
4031 dom_sid_string(tmp_ctx, sid),
4032 dom_sid_string(tmp_ctx, &sid2)));
4033 talloc_free(tmp_ctx);
4034 return ldb_operr(ldb);
4037 talloc_free(tmp_ctx);
4041 static const char *secret_attributes[] = {
4044 "initialAuthIncoming",
4045 "initialAuthOutgoing",
4049 "supplementalCredentials",
4050 "trustAuthIncoming",
4051 "trustAuthOutgoing",
4057 check if the attribute belongs to the RODC filtered attribute set
4058 Note that attributes that are in the filtered attribute set are the
4059 ones that _are_ always sent to a RODC
4061 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4063 /* they never get secret attributes */
4064 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4068 /* they do get non-secret critical attributes */
4069 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4073 /* they do get non-secret attributes marked as being in the FAS */
4074 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4078 /* other attributes are denied */
4082 /* return fsmo role dn and role owner dn for a particular role*/
4083 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4084 struct ldb_context *ldb,
4086 struct ldb_dn **fsmo_role_dn,
4087 struct ldb_dn **role_owner_dn)
4091 case DREPL_NAMING_MASTER:
4092 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4093 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4094 if (ret != LDB_SUCCESS) {
4095 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4096 ldb_errstring(ldb)));
4097 talloc_free(tmp_ctx);
4098 return WERR_DS_DRA_INTERNAL_ERROR;
4101 case DREPL_INFRASTRUCTURE_MASTER:
4102 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4103 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4104 if (ret != LDB_SUCCESS) {
4105 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4106 ldb_errstring(ldb)));
4107 talloc_free(tmp_ctx);
4108 return WERR_DS_DRA_INTERNAL_ERROR;
4111 case DREPL_RID_MASTER:
4112 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4113 if (ret != LDB_SUCCESS) {
4114 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4115 talloc_free(tmp_ctx);
4116 return WERR_DS_DRA_INTERNAL_ERROR;
4119 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4120 if (ret != LDB_SUCCESS) {
4121 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4122 ldb_errstring(ldb)));
4123 talloc_free(tmp_ctx);
4124 return WERR_DS_DRA_INTERNAL_ERROR;
4127 case DREPL_SCHEMA_MASTER:
4128 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4129 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4130 if (ret != LDB_SUCCESS) {
4131 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4132 ldb_errstring(ldb)));
4133 talloc_free(tmp_ctx);
4134 return WERR_DS_DRA_INTERNAL_ERROR;
4137 case DREPL_PDC_MASTER:
4138 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4139 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4140 if (ret != LDB_SUCCESS) {
4141 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4142 ldb_errstring(ldb)));
4143 talloc_free(tmp_ctx);
4144 return WERR_DS_DRA_INTERNAL_ERROR;
4148 return WERR_DS_DRA_INTERNAL_ERROR;
4153 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4154 TALLOC_CTX *mem_ctx,
4155 struct ldb_dn *server_dn)
4158 struct ldb_result *res = NULL;
4159 const char * const attrs[] = { "dNSHostName", NULL};
4161 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4165 if (ldb_ret != LDB_SUCCESS) {
4166 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4167 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4171 return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
4175 returns true if an attribute is in the filter,
4176 false otherwise, provided that attribute value is provided with the expression
4178 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4182 switch (tree->operation) {
4185 for (i=0;i<tree->u.list.num_elements;i++) {
4186 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4192 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4193 case LDB_OP_EQUALITY:
4194 case LDB_OP_GREATER:
4197 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4201 case LDB_OP_SUBSTRING:
4202 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4206 case LDB_OP_PRESENT:
4207 /* (attrname=*) is not filtered out */
4209 case LDB_OP_EXTENDED:
4210 if (tree->u.extended.attr &&
4211 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {