2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "librpc/gen_ndr/irpc.h"
48 search the sam for the specified attributes in a specific domain, filter on
49 objectSid being in domain_sid.
51 int samdb_search_domain(struct ldb_context *sam_ldb,
53 struct ldb_dn *basedn,
54 struct ldb_message ***res,
55 const char * const *attrs,
56 const struct dom_sid *domain_sid,
57 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
63 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
64 res, attrs, format, ap);
70 struct dom_sid *entry_sid;
72 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
74 if ((entry_sid == NULL) ||
75 (!dom_sid_in_domain(domain_sid, entry_sid))) {
76 /* Delete that entry from the result set */
77 (*res)[i] = (*res)[count-1];
79 talloc_free(entry_sid);
82 talloc_free(entry_sid);
90 search the sam for a single string attribute in exactly 1 record
92 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
94 struct ldb_dn *basedn,
95 const char *attr_name,
96 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
99 const char *attrs[2] = { NULL, NULL };
100 struct ldb_message **res = NULL;
102 attrs[0] = attr_name;
104 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
106 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
107 attr_name, format, count));
114 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
118 search the sam for a single string attribute in exactly 1 record
120 const char *samdb_search_string(struct ldb_context *sam_ldb,
122 struct ldb_dn *basedn,
123 const char *attr_name,
124 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
129 va_start(ap, format);
130 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
136 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
138 struct ldb_dn *basedn,
139 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
143 struct ldb_message **res = NULL;
146 va_start(ap, format);
147 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
150 if (count != 1) return NULL;
152 ret = talloc_steal(mem_ctx, res[0]->dn);
159 search the sam for a dom_sid attribute in exactly 1 record
161 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
163 struct ldb_dn *basedn,
164 const char *attr_name,
165 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
169 struct ldb_message **res;
170 const char *attrs[2] = { NULL, NULL };
173 attrs[0] = attr_name;
175 va_start(ap, format);
176 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
179 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
180 attr_name, format, count));
186 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
192 return the count of the number of records in the sam matching the query
194 int samdb_search_count(struct ldb_context *sam_ldb,
195 struct ldb_dn *basedn,
196 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
199 struct ldb_message **res;
200 const char *attrs[] = { NULL };
202 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
204 va_start(ap, format);
205 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
207 talloc_free(tmp_ctx);
214 search the sam for a single integer attribute in exactly 1 record
216 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
218 unsigned int default_value,
219 struct ldb_dn *basedn,
220 const char *attr_name,
221 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
225 struct ldb_message **res;
226 const char *attrs[2] = { NULL, NULL };
228 attrs[0] = attr_name;
230 va_start(ap, format);
231 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
235 return default_value;
238 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
242 search the sam for a single signed 64 bit integer attribute in exactly 1 record
244 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
246 int64_t default_value,
247 struct ldb_dn *basedn,
248 const char *attr_name,
249 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
253 struct ldb_message **res;
254 const char *attrs[2] = { NULL, NULL };
256 attrs[0] = attr_name;
258 va_start(ap, format);
259 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
263 return default_value;
266 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
270 search the sam for multipe records each giving a single string attribute
271 return the number of matches, or -1 on error
273 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
275 struct ldb_dn *basedn,
277 const char *attr_name,
278 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
282 const char *attrs[2] = { NULL, NULL };
283 struct ldb_message **res = NULL;
285 attrs[0] = attr_name;
287 va_start(ap, format);
288 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
295 /* make sure its single valued */
296 for (i=0;i<count;i++) {
297 if (res[i]->num_elements != 1) {
298 DEBUG(1,("samdb: search for %s %s not single valued\n",
305 *strs = talloc_array(mem_ctx, const char *, count+1);
311 for (i=0;i<count;i++) {
312 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
314 (*strs)[count] = NULL;
319 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
320 const char *attr, struct ldb_dn *default_value)
322 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
324 return default_value;
330 pull a rid from a objectSid in a result set.
332 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
333 const char *attr, uint32_t default_value)
338 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
340 return default_value;
342 rid = sid->sub_auths[sid->num_auths-1];
348 pull a dom_sid structure from a objectSid in a result set.
350 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
353 const struct ldb_val *v;
355 enum ndr_err_code ndr_err;
356 v = ldb_msg_find_ldb_val(msg, attr);
360 sid = talloc(mem_ctx, struct dom_sid);
364 ndr_err = ndr_pull_struct_blob(v, sid, sid,
365 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 pull a guid structure from a objectGUID in a result set.
376 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
378 const struct ldb_val *v;
382 v = ldb_msg_find_ldb_val(msg, attr);
383 if (!v) return GUID_zero();
385 status = GUID_from_ndr_blob(v, &guid);
386 if (!NT_STATUS_IS_OK(status)) {
394 pull a sid prefix from a objectSid in a result set.
395 this is used to find the domain sid for a user
397 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
400 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
401 if (!sid || sid->num_auths < 1) return NULL;
407 pull a NTTIME in a result set.
409 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
410 NTTIME default_value)
412 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
416 * Windows stores 0 for lastLogoff.
417 * But when a MS DC return the lastLogoff (as Logoff Time)
418 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
419 * cause windows 2008 and newer version to fail for SMB requests
421 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
423 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
426 ret = 0x7FFFFFFFFFFFFFFFULL;
432 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
433 * indicate an account doesn't expire.
435 * When Windows initially creates an account, it sets
436 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
437 * when changing from an account having a specific expiration date to
438 * that account never expiring, it sets accountExpires = 0.
440 * Consolidate that logic here to allow clearer logic for account expiry in
441 * the rest of the code.
443 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
445 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
449 ret = 0x7FFFFFFFFFFFFFFFULL;
455 construct the allow_password_change field from the PwdLastSet attribute and the
456 domain password settings
458 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
460 struct ldb_dn *domain_dn,
461 struct ldb_message *msg,
464 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
467 if (attr_time == 0) {
471 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
473 /* yes, this is a -= not a += as minPwdAge is stored as the negative
474 of the number of 100-nano-seconds */
475 attr_time -= minPwdAge;
481 construct the force_password_change field from the PwdLastSet
482 attribute, the userAccountControl and the domain password settings
484 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
486 struct ldb_dn *domain_dn,
487 struct ldb_message *msg)
489 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
490 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
491 "userAccountControl",
495 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
496 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
497 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
498 return 0x7FFFFFFFFFFFFFFFULL;
501 if (attr_time == 0) {
504 if (attr_time == -1) {
505 return 0x7FFFFFFFFFFFFFFFULL;
508 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
510 if (maxPwdAge == 0) {
511 return 0x7FFFFFFFFFFFFFFFULL;
513 attr_time -= maxPwdAge;
520 pull a samr_Password structutre from a result set.
522 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
524 struct samr_Password *hash = NULL;
525 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
526 if (val && (val->length >= sizeof(hash->hash))) {
527 hash = talloc(mem_ctx, struct samr_Password);
528 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
534 pull an array of samr_Password structures from a result set.
536 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
537 const char *attr, struct samr_Password **hashes)
539 unsigned int count, i;
540 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
546 count = val->length / 16;
551 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
556 for (i=0;i<count;i++) {
557 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
563 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
564 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
566 struct samr_Password *lmPwdHash, *ntPwdHash;
569 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
572 } else if (num_nt > 1) {
573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
575 *nt_pwd = &ntPwdHash[0];
579 /* Ensure that if we have turned off LM
580 * authentication, that we never use the LM hash, even
582 if (lpcfg_lanman_auth(lp_ctx)) {
584 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
587 } else if (num_lm > 1) {
588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590 *lm_pwd = &lmPwdHash[0];
600 pull a samr_LogonHours structutre from a result set.
602 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
604 struct samr_LogonHours hours;
605 size_t units_per_week = 168;
606 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
611 units_per_week = val->length * 8;
614 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
618 hours.units_per_week = units_per_week;
619 memset(hours.bits, 0xFF, units_per_week/8);
621 memcpy(hours.bits, val->data, val->length);
628 pull a set of account_flags from a result set.
630 This requires that the attributes:
635 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
636 struct ldb_message *msg, struct ldb_dn *domain_dn)
638 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
639 uint32_t acct_flags = ds_uf2acb(userAccountControl);
640 NTTIME must_change_time;
643 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
646 /* Test account expire time */
647 unix_to_nt_time(&now, time(NULL));
648 /* check for expired password */
649 if (must_change_time < now) {
650 acct_flags |= ACB_PW_EXPIRED;
655 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
656 struct ldb_message *msg,
659 struct lsa_BinaryString s;
660 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
668 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
672 s.length = s.size = val->length;
673 memcpy(s.array, val->data, val->length);
678 /* Find an attribute, with a particular value */
680 /* The current callers of this function expect a very specific
681 * behaviour: In particular, objectClass subclass equivilance is not
682 * wanted. This means that we should not lookup the schema for the
683 * comparison function */
684 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
685 const struct ldb_message *msg,
686 const char *name, const char *value)
689 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
695 for (i=0;i<el->num_values;i++) {
696 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
705 * This is intended for use by the "password hash" module since there
706 * password changes can be specified through one message element with the
707 * new password (to set) and another one with the old password (to unset).
709 * The first which sets a password (new value) can have flags
710 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
711 * for entries). The latter (old value) has always specified
712 * LDB_FLAG_MOD_DELETE.
714 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
715 * doesn't contain only one value (this is the Windows Server behaviour)
716 * otherwise LDB_SUCCESS.
718 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
720 const struct ldb_val **new_val,
721 const struct ldb_val **old_val)
732 for (i = 0; i < msg->num_elements; i++) {
733 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
734 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
735 *old_val = &msg->elements[i].values[0];
737 *new_val = &msg->elements[i].values[0];
745 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
747 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
748 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
753 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
755 struct ldb_message_element *el;
757 el = ldb_msg_find_element(msg, name);
762 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
768 add a string element to a message
770 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
771 const char *attr_name, const char *str)
773 const char *s = talloc_strdup(mem_ctx, str);
775 return ldb_oom(sam_ldb);
777 return ldb_msg_add_string(msg, attr_name, s);
781 add a dom_sid element to a message
783 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, struct dom_sid *sid)
787 enum ndr_err_code ndr_err;
789 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
791 (ndr_push_flags_fn_t)ndr_push_dom_sid);
792 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
793 return ldb_operr(sam_ldb);
795 return ldb_msg_add_value(msg, attr_name, &v, NULL);
800 add a delete element operation to a message
802 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
803 const char *attr_name)
805 /* we use an empty replace rather than a delete, as it allows for
806 dsdb_replace() to be used everywhere */
807 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
811 add an add attribute value to a message or enhance an existing attribute
812 which has the same name and the add flag set.
814 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
815 struct ldb_message *msg, const char *attr_name,
818 struct ldb_message_element *el;
819 struct ldb_val val, *vals;
825 v = talloc_strdup(mem_ctx, value);
827 return ldb_oom(sam_ldb);
830 val.data = (uint8_t *) v;
831 val.length = strlen(v);
833 if (val.length == 0) {
834 /* allow empty strings as non-existent attributes */
838 for (i = 0; i < msg->num_elements; i++) {
839 el = &msg->elements[i];
840 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
841 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
847 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
849 if (ret != LDB_SUCCESS) {
854 vals = talloc_realloc(msg, el->values, struct ldb_val,
857 return ldb_oom(sam_ldb);
860 el->values[el->num_values] = val;
867 add a delete attribute value to a message or enhance an existing attribute
868 which has the same name and the delete flag set.
870 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
871 struct ldb_message *msg, const char *attr_name,
874 struct ldb_message_element *el;
875 struct ldb_val val, *vals;
881 v = talloc_strdup(mem_ctx, value);
883 return ldb_oom(sam_ldb);
886 val.data = (uint8_t *) v;
887 val.length = strlen(v);
889 if (val.length == 0) {
890 /* allow empty strings as non-existent attributes */
894 for (i = 0; i < msg->num_elements; i++) {
895 el = &msg->elements[i];
896 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
897 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
903 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
905 if (ret != LDB_SUCCESS) {
910 vals = talloc_realloc(msg, el->values, struct ldb_val,
913 return ldb_oom(sam_ldb);
916 el->values[el->num_values] = val;
923 add a int element to a message
925 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
926 const char *attr_name, int v)
928 const char *s = talloc_asprintf(mem_ctx, "%d", v);
930 return ldb_oom(sam_ldb);
932 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
936 add a unsigned int element to a message
938 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939 const char *attr_name, unsigned int v)
941 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
945 add a (signed) int64_t element to a message
947 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948 const char *attr_name, int64_t v)
950 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
952 return ldb_oom(sam_ldb);
954 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
958 add a uint64_t element to a message
960 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961 const char *attr_name, uint64_t v)
963 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
967 add a samr_Password element to a message
969 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970 const char *attr_name, const struct samr_Password *hash)
973 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
975 return ldb_oom(sam_ldb);
978 return ldb_msg_add_value(msg, attr_name, &val, NULL);
982 add a samr_Password array to a message
984 int samdb_msg_add_hashes(struct ldb_context *ldb,
985 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
986 const char *attr_name, struct samr_Password *hashes,
991 val.data = talloc_array_size(mem_ctx, 16, count);
992 val.length = count*16;
996 for (i=0;i<count;i++) {
997 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
999 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1003 add a acct_flags element to a message
1005 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1006 const char *attr_name, uint32_t v)
1008 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1012 add a logon_hours element to a message
1014 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1015 const char *attr_name, struct samr_LogonHours *hours)
1018 val.length = hours->units_per_week / 8;
1019 val.data = hours->bits;
1020 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1024 add a parameters element to a message
1026 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1027 const char *attr_name, struct lsa_BinaryString *parameters)
1030 val.length = parameters->length;
1031 val.data = (uint8_t *)parameters->array;
1032 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1036 sets a general value element to a message
1038 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1039 const char *attr_name, const struct ldb_val *val)
1041 struct ldb_message_element *el;
1043 el = ldb_msg_find_element(msg, attr_name);
1047 return ldb_msg_add_value(msg, attr_name, val, NULL);
1051 set a string element in a message
1053 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1054 const char *attr_name, const char *str)
1056 struct ldb_message_element *el;
1058 el = ldb_msg_find_element(msg, attr_name);
1062 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1066 * sets a signed integer in a message
1068 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1069 struct ldb_message *msg, const char *attr_name, int v)
1071 struct ldb_message_element *el;
1073 el = ldb_msg_find_element(msg, attr_name);
1077 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1081 * sets an unsigned integer in a message
1083 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1084 struct ldb_message *msg, const char *attr_name,
1087 struct ldb_message_element *el;
1089 el = ldb_msg_find_element(msg, attr_name);
1093 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1097 * Handle ldb_request in transaction
1099 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1100 struct ldb_request *req)
1104 ret = ldb_transaction_start(sam_ldb);
1105 if (ret != LDB_SUCCESS) {
1109 ret = ldb_request(sam_ldb, req);
1110 if (ret == LDB_SUCCESS) {
1111 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1114 if (ret == LDB_SUCCESS) {
1115 return ldb_transaction_commit(sam_ldb);
1117 ldb_transaction_cancel(sam_ldb);
1123 return a default security descriptor
1125 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1127 struct security_descriptor *sd;
1129 sd = security_descriptor_initialise(mem_ctx);
1134 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1136 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1137 struct ldb_dn *aggregate_dn;
1142 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1143 if (!aggregate_dn) {
1146 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1149 return aggregate_dn;
1152 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1154 struct ldb_dn *new_dn;
1156 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1157 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1158 talloc_free(new_dn);
1164 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1166 struct ldb_dn *new_dn;
1168 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1169 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1170 talloc_free(new_dn);
1176 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1178 struct ldb_dn *new_dn;
1180 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1181 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1182 talloc_free(new_dn);
1189 work out the domain sid for the current open ldb
1191 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1193 TALLOC_CTX *tmp_ctx;
1194 const struct dom_sid *domain_sid;
1195 const char *attrs[] = {
1199 struct ldb_result *res;
1202 /* see if we have a cached copy */
1203 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1208 tmp_ctx = talloc_new(ldb);
1209 if (tmp_ctx == NULL) {
1213 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1215 if (ret != LDB_SUCCESS) {
1219 if (res->count != 1) {
1223 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1224 if (domain_sid == NULL) {
1228 /* cache the domain_sid in the ldb */
1229 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1233 talloc_steal(ldb, domain_sid);
1234 talloc_free(tmp_ctx);
1239 talloc_free(tmp_ctx);
1244 get domain sid from cache
1246 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1248 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1251 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1253 TALLOC_CTX *tmp_ctx;
1254 struct dom_sid *dom_sid_new;
1255 struct dom_sid *dom_sid_old;
1257 /* see if we have a cached copy */
1258 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1259 "cache.domain_sid"), struct dom_sid);
1261 tmp_ctx = talloc_new(ldb);
1262 if (tmp_ctx == NULL) {
1266 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1271 /* cache the domain_sid in the ldb */
1272 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1276 talloc_steal(ldb, dom_sid_new);
1277 talloc_free(tmp_ctx);
1278 talloc_free(dom_sid_old);
1283 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1284 talloc_free(tmp_ctx);
1288 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1290 TALLOC_CTX *tmp_ctx;
1291 struct ldb_dn *ntds_settings_dn_new;
1292 struct ldb_dn *ntds_settings_dn_old;
1294 /* see if we have a cached copy */
1295 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1296 "cache.ntds_settings_dn"), struct ldb_dn);
1298 tmp_ctx = talloc_new(ldb);
1299 if (tmp_ctx == NULL) {
1303 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1304 if (!ntds_settings_dn_new) {
1308 /* cache the domain_sid in the ldb */
1309 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1313 talloc_steal(ldb, ntds_settings_dn_new);
1314 talloc_free(tmp_ctx);
1315 talloc_free(ntds_settings_dn_old);
1320 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1321 talloc_free(tmp_ctx);
1325 /* Obtain the short name of the flexible single master operator
1326 * (FSMO), such as the PDC Emulator */
1327 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1330 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1331 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1332 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1333 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1335 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1336 /* Ensure this matches the format. This gives us a
1337 * bit more confidence that a 'cn' value will be a
1342 return (char *)val->data;
1348 work out the ntds settings dn for the current open ldb
1350 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1352 TALLOC_CTX *tmp_ctx;
1353 const char *root_attrs[] = { "dsServiceName", NULL };
1355 struct ldb_result *root_res;
1356 struct ldb_dn *settings_dn;
1358 /* see if we have a cached copy */
1359 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1364 tmp_ctx = talloc_new(ldb);
1365 if (tmp_ctx == NULL) {
1369 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1371 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1372 ldb_errstring(ldb)));
1376 if (root_res->count != 1) {
1380 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1382 /* cache the domain_sid in the ldb */
1383 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1387 talloc_steal(ldb, settings_dn);
1388 talloc_free(tmp_ctx);
1393 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1394 talloc_free(tmp_ctx);
1399 work out the ntds settings invocationId for the current open ldb
1401 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1403 TALLOC_CTX *tmp_ctx;
1404 const char *attrs[] = { "invocationId", NULL };
1406 struct ldb_result *res;
1407 struct GUID *invocation_id;
1409 /* see if we have a cached copy */
1410 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1411 if (invocation_id) {
1412 return invocation_id;
1415 tmp_ctx = talloc_new(ldb);
1416 if (tmp_ctx == NULL) {
1420 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1425 if (res->count != 1) {
1429 invocation_id = talloc(tmp_ctx, struct GUID);
1430 if (!invocation_id) {
1434 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1436 /* cache the domain_sid in the ldb */
1437 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1441 talloc_steal(ldb, invocation_id);
1442 talloc_free(tmp_ctx);
1444 return invocation_id;
1447 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1448 talloc_free(tmp_ctx);
1452 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1454 TALLOC_CTX *tmp_ctx;
1455 struct GUID *invocation_id_new;
1456 struct GUID *invocation_id_old;
1458 /* see if we have a cached copy */
1459 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1460 "cache.invocation_id");
1462 tmp_ctx = talloc_new(ldb);
1463 if (tmp_ctx == NULL) {
1467 invocation_id_new = talloc(tmp_ctx, struct GUID);
1468 if (!invocation_id_new) {
1472 *invocation_id_new = *invocation_id_in;
1474 /* cache the domain_sid in the ldb */
1475 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1479 talloc_steal(ldb, invocation_id_new);
1480 talloc_free(tmp_ctx);
1481 talloc_free(invocation_id_old);
1486 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1487 talloc_free(tmp_ctx);
1492 work out the ntds settings objectGUID for the current open ldb
1494 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1496 TALLOC_CTX *tmp_ctx;
1497 const char *attrs[] = { "objectGUID", NULL };
1499 struct ldb_result *res;
1500 struct GUID *ntds_guid;
1502 /* see if we have a cached copy */
1503 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1508 tmp_ctx = talloc_new(ldb);
1509 if (tmp_ctx == NULL) {
1513 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1518 if (res->count != 1) {
1522 ntds_guid = talloc(tmp_ctx, struct GUID);
1527 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1529 /* cache the domain_sid in the ldb */
1530 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1534 talloc_steal(ldb, ntds_guid);
1535 talloc_free(tmp_ctx);
1540 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1541 talloc_free(tmp_ctx);
1545 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1547 TALLOC_CTX *tmp_ctx;
1548 struct GUID *ntds_guid_new;
1549 struct GUID *ntds_guid_old;
1551 /* see if we have a cached copy */
1552 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1554 tmp_ctx = talloc_new(ldb);
1555 if (tmp_ctx == NULL) {
1559 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1560 if (!ntds_guid_new) {
1564 *ntds_guid_new = *ntds_guid_in;
1566 /* cache the domain_sid in the ldb */
1567 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1571 talloc_steal(ldb, ntds_guid_new);
1572 talloc_free(tmp_ctx);
1573 talloc_free(ntds_guid_old);
1578 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1579 talloc_free(tmp_ctx);
1584 work out the server dn for the current open ldb
1586 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1588 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 struct ldb_dn *server_dn;
1597 struct ldb_dn *servers_dn;
1598 struct ldb_dn *server_site_dn;
1600 /* TODO: there must be a saner way to do this!! */
1601 server_dn = samdb_server_dn(ldb, mem_ctx);
1602 if (!server_dn) return NULL;
1604 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1605 talloc_free(server_dn);
1606 if (!servers_dn) return NULL;
1608 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1609 talloc_free(servers_dn);
1611 return server_site_dn;
1615 find the site name from a computers DN record
1617 int samdb_find_site_for_computer(struct ldb_context *ldb,
1618 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1619 const char **site_name)
1623 const struct ldb_val *rdn_val;
1627 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1628 if (ret != LDB_SUCCESS) {
1632 if (!ldb_dn_remove_child_components(dn, 2)) {
1634 return LDB_ERR_INVALID_DN_SYNTAX;
1636 rdn_val = ldb_dn_get_rdn_val(dn);
1637 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1640 return LDB_ERR_OPERATIONS_ERROR;
1646 find the NTDS GUID from a computers DN record
1648 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1649 struct GUID *ntds_guid)
1654 *ntds_guid = GUID_zero();
1656 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1657 if (ret != LDB_SUCCESS) {
1661 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1663 return LDB_ERR_OPERATIONS_ERROR;
1666 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1672 find a 'reference' DN that points at another object
1673 (eg. serverReference, rIDManagerReference etc)
1675 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1676 const char *attribute, struct ldb_dn **dn)
1678 const char *attrs[2];
1679 struct ldb_result *res;
1682 attrs[0] = attribute;
1685 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1686 if (ret != LDB_SUCCESS) {
1690 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1692 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1693 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1694 ldb_dn_get_linearized(base));
1696 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1697 ldb_dn_get_linearized(base));
1700 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1708 find our machine account via the serverReference attribute in the
1711 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1713 struct ldb_dn *server_dn;
1716 server_dn = samdb_server_dn(ldb, mem_ctx);
1717 if (server_dn == NULL) {
1718 return LDB_ERR_NO_SUCH_OBJECT;
1721 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1722 talloc_free(server_dn);
1728 find the RID Manager$ DN via the rIDManagerReference attribute in the
1731 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1733 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1734 "rIDManagerReference", dn);
1738 find the RID Set DN via the rIDSetReferences attribute in our
1741 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1743 struct ldb_dn *server_ref_dn;
1746 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1747 if (ret != LDB_SUCCESS) {
1750 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1751 talloc_free(server_ref_dn);
1755 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1757 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1764 return (const char *) val->data;
1768 * Finds the client site by using the client's IP address.
1769 * The "subnet_name" returns the name of the subnet if parameter != NULL
1771 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1772 const char *ip_address, char **subnet_name)
1774 const char *attrs[] = { "cn", "siteObject", NULL };
1775 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1776 struct ldb_result *res;
1777 const struct ldb_val *val;
1778 const char *site_name = NULL, *l_subnet_name = NULL;
1779 const char *allow_list[2] = { NULL, NULL };
1780 unsigned int i, count;
1784 * if we don't have a client ip e.g. ncalrpc
1785 * the server site is the client site
1787 if (ip_address == NULL) {
1788 return samdb_server_site_name(ldb, mem_ctx);
1791 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1792 if (sites_container_dn == NULL) {
1796 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1797 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1798 talloc_free(sites_container_dn);
1799 talloc_free(subnets_dn);
1803 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1805 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1807 } else if (ret != LDB_SUCCESS) {
1808 talloc_free(sites_container_dn);
1809 talloc_free(subnets_dn);
1815 for (i = 0; i < count; i++) {
1816 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1819 allow_list[0] = l_subnet_name;
1821 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1822 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1825 if (sites_dn == NULL) {
1826 /* No reference, maybe another subnet matches */
1830 /* "val" cannot be NULL here since "sites_dn" != NULL */
1831 val = ldb_dn_get_rdn_val(sites_dn);
1832 site_name = talloc_strdup(mem_ctx,
1833 (const char *) val->data);
1835 talloc_free(sites_dn);
1841 if (site_name == NULL) {
1842 /* This is the Windows Server fallback rule: when no subnet
1843 * exists and we have only one site available then use it (it
1844 * is for sure the same as our server site). If more sites do
1845 * exist then we don't know which one to use and set the site
1847 cnt = samdb_search_count(ldb, sites_container_dn,
1848 "(objectClass=site)");
1850 site_name = samdb_server_site_name(ldb, mem_ctx);
1852 site_name = talloc_strdup(mem_ctx, "");
1854 l_subnet_name = NULL;
1857 if (subnet_name != NULL) {
1858 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1861 talloc_free(sites_container_dn);
1862 talloc_free(subnets_dn);
1869 work out if we are the PDC for the domain of the current open ldb
1871 bool samdb_is_pdc(struct ldb_context *ldb)
1873 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1875 struct ldb_result *dom_res;
1876 TALLOC_CTX *tmp_ctx;
1880 tmp_ctx = talloc_new(ldb);
1881 if (tmp_ctx == NULL) {
1882 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1886 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1887 if (ret != LDB_SUCCESS) {
1888 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1889 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1890 ldb_errstring(ldb)));
1893 if (dom_res->count != 1) {
1897 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1899 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1905 talloc_free(tmp_ctx);
1910 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1911 talloc_free(tmp_ctx);
1916 work out if we are a Global Catalog server for the domain of the current open ldb
1918 bool samdb_is_gc(struct ldb_context *ldb)
1920 const char *attrs[] = { "options", NULL };
1922 struct ldb_result *res;
1923 TALLOC_CTX *tmp_ctx;
1925 tmp_ctx = talloc_new(ldb);
1926 if (tmp_ctx == NULL) {
1927 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1931 /* Query cn=ntds settings,.... */
1932 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1933 if (ret != LDB_SUCCESS) {
1934 talloc_free(tmp_ctx);
1937 if (res->count != 1) {
1938 talloc_free(tmp_ctx);
1942 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1943 talloc_free(tmp_ctx);
1945 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1946 if (options & 0x000000001) {
1952 /* Find a domain object in the parents of a particular DN. */
1953 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1954 struct ldb_dn **parent_dn, const char **errstring)
1956 TALLOC_CTX *local_ctx;
1957 struct ldb_dn *sdn = dn;
1958 struct ldb_result *res = NULL;
1959 int ret = LDB_SUCCESS;
1960 const char *attrs[] = { NULL };
1962 local_ctx = talloc_new(mem_ctx);
1963 if (local_ctx == NULL) return ldb_oom(ldb);
1965 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1966 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1967 "(|(objectClass=domain)(objectClass=builtinDomain))");
1968 if (ret == LDB_SUCCESS) {
1969 if (res->count == 1) {
1977 if (ret != LDB_SUCCESS) {
1978 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1979 ldb_dn_get_linearized(dn),
1980 ldb_dn_get_linearized(sdn),
1981 ldb_errstring(ldb));
1982 talloc_free(local_ctx);
1985 if (res->count != 1) {
1986 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1987 ldb_dn_get_linearized(dn));
1988 DEBUG(0,(__location__ ": %s\n", *errstring));
1989 talloc_free(local_ctx);
1990 return LDB_ERR_CONSTRAINT_VIOLATION;
1993 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1994 talloc_free(local_ctx);
2000 * Performs checks on a user password (plaintext UNIX format - attribute
2001 * "password"). The remaining parameters have to be extracted from the domain
2004 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2006 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2007 const uint32_t pwdProperties,
2008 const uint32_t minPwdLength)
2010 /* checks if the "minPwdLength" property is satisfied */
2011 if (minPwdLength > password->length)
2012 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2014 /* checks the password complexity */
2015 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2016 && (password->data != NULL)
2017 && (!check_password_quality((const char *) password->data)))
2018 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2020 return SAMR_VALIDATION_STATUS_SUCCESS;
2024 * Callback for "samdb_set_password" password change
2026 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2031 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2034 if (ares->error != LDB_SUCCESS) {
2036 req->context = talloc_steal(req,
2037 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2039 return ldb_request_done(req, ret);
2042 if (ares->type != LDB_REPLY_DONE) {
2044 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2047 req->context = talloc_steal(req,
2048 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2050 return ldb_request_done(req, LDB_SUCCESS);
2054 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2055 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2056 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2057 * user change or not. The "rejectReason" gives some more informations if the
2060 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2061 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2063 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2064 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2065 const DATA_BLOB *new_password,
2066 const struct samr_Password *lmNewHash,
2067 const struct samr_Password *ntNewHash,
2068 const struct samr_Password *lmOldHash,
2069 const struct samr_Password *ntOldHash,
2070 enum samPwdChangeReason *reject_reason,
2071 struct samr_DomInfo1 **_dominfo)
2073 struct ldb_message *msg;
2074 struct ldb_message_element *el;
2075 struct ldb_request *req;
2076 struct dsdb_control_password_change_status *pwd_stat = NULL;
2078 NTSTATUS status = NT_STATUS_OK;
2080 #define CHECK_RET(x) \
2081 if (x != LDB_SUCCESS) { \
2083 return NT_STATUS_NO_MEMORY; \
2086 msg = ldb_msg_new(mem_ctx);
2088 return NT_STATUS_NO_MEMORY;
2091 if ((new_password != NULL)
2092 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2093 /* we have the password as plaintext UTF16 */
2094 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2095 new_password, NULL));
2096 el = ldb_msg_find_element(msg, "clearTextPassword");
2097 el->flags = LDB_FLAG_MOD_REPLACE;
2098 } else if ((new_password == NULL)
2099 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2100 /* we have a password as LM and/or NT hash */
2101 if (lmNewHash != NULL) {
2102 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2103 "dBCSPwd", lmNewHash));
2104 el = ldb_msg_find_element(msg, "dBCSPwd");
2105 el->flags = LDB_FLAG_MOD_REPLACE;
2107 if (ntNewHash != NULL) {
2108 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2109 "unicodePwd", ntNewHash));
2110 el = ldb_msg_find_element(msg, "unicodePwd");
2111 el->flags = LDB_FLAG_MOD_REPLACE;
2114 /* the password wasn't specified correctly */
2116 return NT_STATUS_INVALID_PARAMETER;
2119 /* build modify request */
2120 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2121 samdb_set_password_callback, NULL);
2122 if (ret != LDB_SUCCESS) {
2124 return NT_STATUS_NO_MEMORY;
2127 /* A password change operation */
2128 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2129 struct dsdb_control_password_change *change;
2131 change = talloc(req, struct dsdb_control_password_change);
2132 if (change == NULL) {
2135 return NT_STATUS_NO_MEMORY;
2138 change->old_nt_pwd_hash = ntOldHash;
2139 change->old_lm_pwd_hash = lmOldHash;
2141 ret = ldb_request_add_control(req,
2142 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2144 if (ret != LDB_SUCCESS) {
2147 return NT_STATUS_NO_MEMORY;
2150 ret = ldb_request_add_control(req,
2151 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2153 if (ret != LDB_SUCCESS) {
2156 return NT_STATUS_NO_MEMORY;
2158 ret = ldb_request_add_control(req,
2159 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2161 if (ret != LDB_SUCCESS) {
2164 return NT_STATUS_NO_MEMORY;
2167 ret = dsdb_autotransaction_request(ldb, req);
2169 if (req->context != NULL) {
2170 pwd_stat = talloc_steal(mem_ctx,
2171 ((struct ldb_control *)req->context)->data);
2177 /* Sets the domain info (if requested) */
2178 if (_dominfo != NULL) {
2179 struct samr_DomInfo1 *dominfo;
2181 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2182 if (dominfo == NULL) {
2183 return NT_STATUS_NO_MEMORY;
2186 if (pwd_stat != NULL) {
2187 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2188 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2189 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2190 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2191 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2194 *_dominfo = dominfo;
2197 if (reject_reason != NULL) {
2198 if (pwd_stat != NULL) {
2199 *reject_reason = pwd_stat->reject_reason;
2201 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2205 if (pwd_stat != NULL) {
2206 talloc_free(pwd_stat);
2209 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2210 const char *errmsg = ldb_errstring(ldb);
2211 char *endptr = NULL;
2212 WERROR werr = WERR_GENERAL_FAILURE;
2213 status = NT_STATUS_UNSUCCESSFUL;
2214 if (errmsg != NULL) {
2215 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2217 if (endptr != errmsg) {
2218 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2219 status = NT_STATUS_WRONG_PASSWORD;
2221 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2222 status = NT_STATUS_PASSWORD_RESTRICTION;
2225 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2226 /* don't let the caller know if an account doesn't exist */
2227 status = NT_STATUS_WRONG_PASSWORD;
2228 } else if (ret != LDB_SUCCESS) {
2229 status = NT_STATUS_UNSUCCESSFUL;
2236 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2237 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2238 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2239 * user change or not. The "rejectReason" gives some more informations if the
2242 * This wrapper function for "samdb_set_password" takes a SID as input rather
2245 * This call encapsulates a new LDB transaction for changing the password;
2246 * therefore the user hasn't to start a new one.
2248 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2249 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2250 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2251 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2253 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2254 const struct dom_sid *user_sid,
2255 const DATA_BLOB *new_password,
2256 const struct samr_Password *lmNewHash,
2257 const struct samr_Password *ntNewHash,
2258 const struct samr_Password *lmOldHash,
2259 const struct samr_Password *ntOldHash,
2260 enum samPwdChangeReason *reject_reason,
2261 struct samr_DomInfo1 **_dominfo)
2264 struct ldb_dn *user_dn;
2267 ret = ldb_transaction_start(ldb);
2268 if (ret != LDB_SUCCESS) {
2269 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2270 return NT_STATUS_TRANSACTION_ABORTED;
2273 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2274 "(&(objectSid=%s)(objectClass=user))",
2275 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2277 ldb_transaction_cancel(ldb);
2278 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2279 dom_sid_string(mem_ctx, user_sid)));
2280 return NT_STATUS_NO_SUCH_USER;
2283 nt_status = samdb_set_password(ldb, mem_ctx,
2286 lmNewHash, ntNewHash,
2287 lmOldHash, ntOldHash,
2288 reject_reason, _dominfo);
2289 if (!NT_STATUS_IS_OK(nt_status)) {
2290 ldb_transaction_cancel(ldb);
2291 talloc_free(user_dn);
2295 ret = ldb_transaction_commit(ldb);
2296 if (ret != LDB_SUCCESS) {
2297 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2298 ldb_dn_get_linearized(user_dn),
2299 ldb_errstring(ldb)));
2300 talloc_free(user_dn);
2301 return NT_STATUS_TRANSACTION_ABORTED;
2304 talloc_free(user_dn);
2305 return NT_STATUS_OK;
2309 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2310 struct dom_sid *sid, struct ldb_dn **ret_dn)
2312 struct ldb_message *msg;
2313 struct ldb_dn *basedn;
2317 sidstr = dom_sid_string(mem_ctx, sid);
2318 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2320 /* We might have to create a ForeignSecurityPrincipal, even if this user
2321 * is in our own domain */
2323 msg = ldb_msg_new(sidstr);
2325 talloc_free(sidstr);
2326 return NT_STATUS_NO_MEMORY;
2329 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2330 ldb_get_default_basedn(sam_ctx),
2331 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2333 if (ret != LDB_SUCCESS) {
2334 DEBUG(0, ("Failed to find DN for "
2335 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2336 talloc_free(sidstr);
2337 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2340 /* add core elements to the ldb_message for the alias */
2342 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2343 talloc_free(sidstr);
2344 return NT_STATUS_NO_MEMORY;
2347 ret = samdb_msg_add_string(sam_ctx, msg, msg,
2348 "objectClass", "foreignSecurityPrincipal");
2349 if (ret != LDB_SUCCESS) {
2350 talloc_free(sidstr);
2351 return NT_STATUS_NO_MEMORY;
2354 /* create the alias */
2355 ret = ldb_add(sam_ctx, msg);
2356 if (ret != LDB_SUCCESS) {
2357 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2359 ldb_dn_get_linearized(msg->dn),
2360 ldb_errstring(sam_ctx)));
2361 talloc_free(sidstr);
2362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2365 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2366 talloc_free(sidstr);
2368 return NT_STATUS_OK;
2373 Find the DN of a domain, assuming it to be a dotted.dns name
2376 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2379 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2380 const char *binary_encoded;
2381 const char **split_realm;
2388 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2390 talloc_free(tmp_ctx);
2393 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2394 for (i=0; split_realm[i]; i++) {
2395 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2396 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2397 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2398 binary_encoded, ldb_dn_get_linearized(dn)));
2399 talloc_free(tmp_ctx);
2403 if (!ldb_dn_validate(dn)) {
2404 DEBUG(2, ("Failed to validated DN %s\n",
2405 ldb_dn_get_linearized(dn)));
2406 talloc_free(tmp_ctx);
2409 talloc_free(tmp_ctx);
2414 Find the DN of a domain, be it the netbios or DNS name
2416 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2417 const char *domain_name)
2419 const char * const domain_ref_attrs[] = {
2422 const char * const domain_ref2_attrs[] = {
2425 struct ldb_result *res_domain_ref;
2426 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2427 /* find the domain's DN */
2428 int ret_domain = ldb_search(ldb, mem_ctx,
2430 samdb_partitions_dn(ldb, mem_ctx),
2433 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2435 if (ret_domain != LDB_SUCCESS) {
2439 if (res_domain_ref->count == 0) {
2440 ret_domain = ldb_search(ldb, mem_ctx,
2442 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2445 "(objectclass=domain)");
2446 if (ret_domain != LDB_SUCCESS) {
2450 if (res_domain_ref->count == 1) {
2451 return res_domain_ref->msgs[0]->dn;
2456 if (res_domain_ref->count > 1) {
2457 DEBUG(0,("Found %d records matching domain [%s]\n",
2458 ret_domain, domain_name));
2462 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2468 use a GUID to find a DN
2470 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2471 TALLOC_CTX *mem_ctx,
2472 const struct GUID *guid, struct ldb_dn **dn)
2475 struct ldb_result *res;
2476 const char *attrs[] = { NULL };
2477 char *guid_str = GUID_string(mem_ctx, guid);
2480 return ldb_operr(ldb);
2483 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2484 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2485 DSDB_SEARCH_SHOW_EXTENDED_DN |
2486 DSDB_SEARCH_ONE_ONLY,
2487 "objectGUID=%s", guid_str);
2488 talloc_free(guid_str);
2489 if (ret != LDB_SUCCESS) {
2493 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2500 use a DN to find a GUID with a given attribute name
2502 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2503 struct ldb_dn *dn, const char *attribute,
2507 struct ldb_result *res;
2508 const char *attrs[2];
2509 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2511 attrs[0] = attribute;
2514 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2515 DSDB_SEARCH_SHOW_DELETED |
2516 DSDB_SEARCH_SHOW_RECYCLED);
2517 if (ret != LDB_SUCCESS) {
2518 talloc_free(tmp_ctx);
2521 if (res->count < 1) {
2522 talloc_free(tmp_ctx);
2523 return LDB_ERR_NO_SUCH_OBJECT;
2525 *guid = samdb_result_guid(res->msgs[0], attribute);
2526 talloc_free(tmp_ctx);
2531 use a DN to find a GUID
2533 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2534 struct ldb_dn *dn, struct GUID *guid)
2536 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2542 adds the given GUID to the given ldb_message. This value is added
2543 for the given attr_name (may be either "objectGUID" or "parentGUID").
2545 int dsdb_msg_add_guid(struct ldb_message *msg,
2547 const char *attr_name)
2552 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2554 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 ret = LDB_ERR_OPERATIONS_ERROR;
2560 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2561 if (ret != LDB_SUCCESS) {
2562 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2570 talloc_free(tmp_ctx);
2577 use a DN to find a SID
2579 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2580 struct ldb_dn *dn, struct dom_sid *sid)
2583 struct ldb_result *res;
2584 const char *attrs[] = { "objectSid", NULL };
2585 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2590 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2591 DSDB_SEARCH_SHOW_DELETED |
2592 DSDB_SEARCH_SHOW_RECYCLED);
2593 if (ret != LDB_SUCCESS) {
2594 talloc_free(tmp_ctx);
2597 if (res->count < 1) {
2598 talloc_free(tmp_ctx);
2599 return LDB_ERR_NO_SUCH_OBJECT;
2601 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2603 talloc_free(tmp_ctx);
2604 return LDB_ERR_NO_SUCH_OBJECT;
2607 talloc_free(tmp_ctx);
2612 use a SID to find a DN
2614 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2615 TALLOC_CTX *mem_ctx,
2616 struct dom_sid *sid, struct ldb_dn **dn)
2619 struct ldb_result *res;
2620 const char *attrs[] = { NULL };
2621 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2624 return ldb_operr(ldb);
2627 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2628 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2629 DSDB_SEARCH_SHOW_EXTENDED_DN |
2630 DSDB_SEARCH_ONE_ONLY,
2631 "objectSid=%s", sid_str);
2632 talloc_free(sid_str);
2633 if (ret != LDB_SUCCESS) {
2637 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2644 load a repsFromTo blob list for a given partition GUID
2645 attr must be "repsFrom" or "repsTo"
2647 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2648 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2650 const char *attrs[] = { attr, NULL };
2651 struct ldb_result *res = NULL;
2652 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2654 struct ldb_message_element *el;
2659 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2661 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2662 talloc_free(tmp_ctx);
2663 return WERR_DS_DRA_INTERNAL_ERROR;
2666 el = ldb_msg_find_element(res->msgs[0], attr);
2668 /* it's OK to be empty */
2669 talloc_free(tmp_ctx);
2673 *count = el->num_values;
2674 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2676 talloc_free(tmp_ctx);
2677 return WERR_DS_DRA_INTERNAL_ERROR;
2680 for (i=0; i<(*count); i++) {
2681 enum ndr_err_code ndr_err;
2682 ndr_err = ndr_pull_struct_blob(&el->values[i],
2685 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2686 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2687 talloc_free(tmp_ctx);
2688 return WERR_DS_DRA_INTERNAL_ERROR;
2692 talloc_free(tmp_ctx);
2698 save the repsFromTo blob list for a given partition GUID
2699 attr must be "repsFrom" or "repsTo"
2701 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2702 const char *attr, struct repsFromToBlob *r, uint32_t count)
2704 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2705 struct ldb_message *msg;
2706 struct ldb_message_element *el;
2709 msg = ldb_msg_new(tmp_ctx);
2711 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2715 el->values = talloc_array(msg, struct ldb_val, count);
2720 for (i=0; i<count; i++) {
2722 enum ndr_err_code ndr_err;
2724 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2726 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2735 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2736 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2740 talloc_free(tmp_ctx);
2745 talloc_free(tmp_ctx);
2746 return WERR_DS_DRA_INTERNAL_ERROR;
2751 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2752 object for a partition
2754 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2755 uint64_t *uSN, uint64_t *urgent_uSN)
2757 struct ldb_request *req;
2759 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2760 struct dsdb_control_current_partition *p_ctrl;
2761 struct ldb_result *res;
2763 res = talloc_zero(tmp_ctx, struct ldb_result);
2765 talloc_free(tmp_ctx);
2766 return ldb_oom(ldb);
2769 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2770 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2774 res, ldb_search_default_callback,
2776 if (ret != LDB_SUCCESS) {
2777 talloc_free(tmp_ctx);
2781 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2782 if (p_ctrl == NULL) {
2783 talloc_free(tmp_ctx);
2784 return ldb_oom(ldb);
2786 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2789 ret = ldb_request_add_control(req,
2790 DSDB_CONTROL_CURRENT_PARTITION_OID,
2792 if (ret != LDB_SUCCESS) {
2793 talloc_free(tmp_ctx);
2797 /* Run the new request */
2798 ret = ldb_request(ldb, req);
2800 if (ret == LDB_SUCCESS) {
2801 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2804 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2805 /* it hasn't been created yet, which means
2806 an implicit value of zero */
2808 talloc_free(tmp_ctx);
2812 if (ret != LDB_SUCCESS) {
2813 talloc_free(tmp_ctx);
2817 if (res->count < 1) {
2823 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2825 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2829 talloc_free(tmp_ctx);
2834 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2835 const struct drsuapi_DsReplicaCursor2 *c2)
2837 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2840 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2841 const struct drsuapi_DsReplicaCursor *c2)
2843 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2848 see if a computer identified by its invocationId is a RODC
2850 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2852 /* 1) find the DN for this servers NTDSDSA object
2853 2) search for the msDS-isRODC attribute
2854 3) if not present then not a RODC
2855 4) if present and TRUE then is a RODC
2857 struct ldb_dn *config_dn;
2858 const char *attrs[] = { "msDS-isRODC", NULL };
2860 struct ldb_result *res;
2861 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2863 config_dn = ldb_get_config_basedn(sam_ctx);
2865 talloc_free(tmp_ctx);
2866 return ldb_operr(sam_ctx);
2869 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2870 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2872 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2874 talloc_free(tmp_ctx);
2878 if (ret != LDB_SUCCESS) {
2879 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2880 GUID_string(tmp_ctx, objectGUID)));
2882 talloc_free(tmp_ctx);
2886 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2887 *is_rodc = (ret == 1);
2889 talloc_free(tmp_ctx);
2895 see if we are a RODC
2897 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2899 const struct GUID *objectGUID;
2903 /* see if we have a cached copy */
2904 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2910 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2912 return ldb_operr(sam_ctx);
2915 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2916 if (ret != LDB_SUCCESS) {
2920 cached = talloc(sam_ctx, bool);
2921 if (cached == NULL) {
2922 return ldb_oom(sam_ctx);
2926 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2927 if (ret != LDB_SUCCESS) {
2928 talloc_free(cached);
2929 return ldb_operr(sam_ctx);
2935 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2937 TALLOC_CTX *tmp_ctx;
2940 tmp_ctx = talloc_new(ldb);
2941 if (tmp_ctx == NULL) {
2945 cached = talloc(tmp_ctx, bool);
2951 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2955 talloc_steal(ldb, cached);
2956 talloc_free(tmp_ctx);
2960 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2961 talloc_free(tmp_ctx);
2967 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2969 flags are DS_NTDS_OPTION_*
2971 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2973 TALLOC_CTX *tmp_ctx;
2974 const char *attrs[] = { "options", NULL };
2976 struct ldb_result *res;
2978 tmp_ctx = talloc_new(ldb);
2979 if (tmp_ctx == NULL) {
2983 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2984 if (ret != LDB_SUCCESS) {
2988 if (res->count != 1) {
2992 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
2994 talloc_free(tmp_ctx);
2999 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3000 talloc_free(tmp_ctx);
3001 return LDB_ERR_NO_SUCH_OBJECT;
3004 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3006 const char *attrs[] = { "objectCategory", NULL };
3008 struct ldb_result *res;
3010 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3011 if (ret != LDB_SUCCESS) {
3015 if (res->count != 1) {
3019 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3022 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3027 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3028 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3030 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3032 char **tokens, *ret;
3035 tokens = str_list_make(mem_ctx, cn, " -_");
3039 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3040 tokens[0][0] = tolower(tokens[0][0]);
3041 for (i = 1; i < str_list_length((const char **)tokens); i++)
3042 tokens[i][0] = toupper(tokens[i][0]);
3044 ret = talloc_strdup(mem_ctx, tokens[0]);
3045 for (i = 1; i < str_list_length((const char **)tokens); i++)
3046 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3048 talloc_free(tokens);
3054 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3056 int dsdb_functional_level(struct ldb_context *ldb)
3058 int *domainFunctionality =
3059 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3060 if (!domainFunctionality) {
3061 /* this is expected during initial provision */
3062 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3063 return DS_DOMAIN_FUNCTION_2000;
3065 return *domainFunctionality;
3069 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3071 int dsdb_forest_functional_level(struct ldb_context *ldb)
3073 int *forestFunctionality =
3074 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3075 if (!forestFunctionality) {
3076 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3077 return DS_DOMAIN_FUNCTION_2000;
3079 return *forestFunctionality;
3083 set a GUID in an extended DN structure
3085 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3091 status = GUID_to_ndr_blob(guid, dn, &v);
3092 if (!NT_STATUS_IS_OK(status)) {
3093 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3096 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3102 return a GUID from a extended DN structure
3104 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3106 const struct ldb_val *v;
3108 v = ldb_dn_get_extended_component(dn, component_name);
3110 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3113 return GUID_from_ndr_blob(v, guid);
3117 return a uint64_t from a extended DN structure
3119 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3121 const struct ldb_val *v;
3124 v = ldb_dn_get_extended_component(dn, component_name);
3126 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3128 s = talloc_strndup(dn, (const char *)v->data, v->length);
3129 NT_STATUS_HAVE_NO_MEMORY(s);
3131 *val = strtoull(s, NULL, 0);
3134 return NT_STATUS_OK;
3138 return a NTTIME from a extended DN structure
3140 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3142 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3146 return a uint32_t from a extended DN structure
3148 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3150 const struct ldb_val *v;
3153 v = ldb_dn_get_extended_component(dn, component_name);
3155 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3158 s = talloc_strndup(dn, (const char *)v->data, v->length);
3159 NT_STATUS_HAVE_NO_MEMORY(s);
3161 *val = strtoul(s, NULL, 0);
3164 return NT_STATUS_OK;
3168 return a dom_sid from a extended DN structure
3170 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3172 const struct ldb_val *sid_blob;
3173 struct TALLOC_CTX *tmp_ctx;
3174 enum ndr_err_code ndr_err;
3176 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3178 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3181 tmp_ctx = talloc_new(NULL);
3183 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3184 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3186 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3187 talloc_free(tmp_ctx);
3191 talloc_free(tmp_ctx);
3192 return NT_STATUS_OK;
3197 return RMD_FLAGS directly from a ldb_dn
3198 returns 0 if not found
3200 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3202 const struct ldb_val *v;
3204 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3205 if (!v || v->length > sizeof(buf)-1) return 0;
3206 strncpy(buf, (const char *)v->data, v->length);
3208 return strtoul(buf, NULL, 10);
3212 return RMD_FLAGS directly from a ldb_val for a DN
3213 returns 0 if RMD_FLAGS is not found
3215 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3221 if (val->length < 13) {
3224 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3228 flags = strtoul(p+11, &end, 10);
3229 if (!end || *end != '>') {
3230 /* it must end in a > */
3237 return true if a ldb_val containing a DN in storage form is deleted
3239 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3241 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3245 return true if a ldb_val containing a DN in storage form is
3246 in the upgraded w2k3 linked attribute format
3248 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3250 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3254 return a DN for a wellknown GUID
3256 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3257 struct ldb_dn *nc_root, const char *wk_guid,
3258 struct ldb_dn **wkguid_dn)
3260 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3261 const char *attrs[] = { NULL };
3264 struct ldb_result *res;
3266 /* construct the magic WKGUID DN */
3267 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3268 wk_guid, ldb_dn_get_linearized(nc_root));
3270 talloc_free(tmp_ctx);
3271 return ldb_operr(samdb);
3274 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3275 DSDB_SEARCH_SHOW_DELETED |
3276 DSDB_SEARCH_SHOW_RECYCLED);
3277 if (ret != LDB_SUCCESS) {
3278 talloc_free(tmp_ctx);
3282 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3283 talloc_free(tmp_ctx);
3288 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3290 return ldb_dn_compare(*dn1, *dn2);
3294 find a NC root given a DN within the NC
3296 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3297 struct ldb_dn **nc_root)
3299 const char *root_attrs[] = { "namingContexts", NULL };
3300 TALLOC_CTX *tmp_ctx;
3302 struct ldb_message_element *el;
3303 struct ldb_result *root_res;
3305 struct ldb_dn **nc_dns;
3307 tmp_ctx = talloc_new(samdb);
3308 if (tmp_ctx == NULL) {
3309 return ldb_oom(samdb);
3312 ret = ldb_search(samdb, tmp_ctx, &root_res,
3313 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3314 if (ret != LDB_SUCCESS) {
3315 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3316 talloc_free(tmp_ctx);
3320 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3322 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3323 ldb_errstring(samdb)));
3324 talloc_free(tmp_ctx);
3325 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3328 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3330 talloc_free(tmp_ctx);
3331 return ldb_oom(samdb);
3334 for (i=0; i<el->num_values; i++) {
3335 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3336 if (nc_dns[i] == NULL) {
3337 talloc_free(tmp_ctx);
3338 return ldb_operr(samdb);
3342 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3344 for (i=0; i<el->num_values; i++) {
3345 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3346 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3347 talloc_free(tmp_ctx);
3352 talloc_free(tmp_ctx);
3353 return LDB_ERR_NO_SUCH_OBJECT;
3358 find the deleted objects DN for any object, by looking for the NC
3359 root, then looking up the wellknown GUID
3361 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3362 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3363 struct ldb_dn **do_dn)
3365 struct ldb_dn *nc_root;
3368 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3369 if (ret != LDB_SUCCESS) {
3373 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3374 talloc_free(nc_root);
3379 return the tombstoneLifetime, in days
3381 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3384 dn = ldb_get_config_basedn(ldb);
3386 return LDB_ERR_NO_SUCH_OBJECT;
3388 dn = ldb_dn_copy(ldb, dn);
3390 return ldb_operr(ldb);
3392 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3393 be a wellknown GUID for this */
3394 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3396 return ldb_operr(ldb);
3399 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3405 compare a ldb_val to a string case insensitively
3407 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3409 size_t len = strlen(s);
3411 if (len > v->length) return 1;
3412 ret = strncasecmp(s, (const char *)v->data, v->length);
3413 if (ret != 0) return ret;
3414 if (v->length > len && v->data[len] != 0) {
3422 load the UDV for a partition in v2 format
3423 The list is returned sorted, and with our local cursor added
3425 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3426 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3428 static const char *attrs[] = { "replUpToDateVector", NULL };
3429 struct ldb_result *r;
3430 const struct ldb_val *ouv_value;
3433 uint64_t highest_usn;
3434 const struct GUID *our_invocation_id;
3435 struct timeval now = timeval_current();
3437 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3438 if (ret != LDB_SUCCESS) {
3442 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3444 enum ndr_err_code ndr_err;
3445 struct replUpToDateVectorBlob ouv;
3447 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3448 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3449 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3451 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3453 if (ouv.version != 2) {
3454 /* we always store as version 2, and
3455 * replUpToDateVector is not replicated
3457 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3460 *count = ouv.ctr.ctr2.count;
3461 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3469 our_invocation_id = samdb_ntds_invocation_id(samdb);
3470 if (!our_invocation_id) {
3471 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3472 talloc_free(*cursors);
3473 return ldb_operr(samdb);
3476 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3477 if (ret != LDB_SUCCESS) {
3478 /* nothing to add - this can happen after a vampire */
3479 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3483 for (i=0; i<*count; i++) {
3484 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3485 (*cursors)[i].highest_usn = highest_usn;
3486 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3487 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3492 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3494 return ldb_oom(samdb);
3497 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3498 (*cursors)[*count].highest_usn = highest_usn;
3499 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3502 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3508 load the UDV for a partition in version 1 format
3509 The list is returned sorted, and with our local cursor added
3511 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3512 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3514 struct drsuapi_DsReplicaCursor2 *v2;
3518 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3519 if (ret != LDB_SUCCESS) {
3529 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3530 if (*cursors == NULL) {
3532 return ldb_oom(samdb);
3535 for (i=0; i<*count; i++) {
3536 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3537 (*cursors)[i].highest_usn = v2[i].highest_usn;
3544 add a set of controls to a ldb_request structure based on a set of
3545 flags. See util.h for a list of available flags
3547 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3550 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3551 struct ldb_search_options_control *options;
3552 /* Using the phantom root control allows us to search all partitions */
3553 options = talloc(req, struct ldb_search_options_control);
3554 if (options == NULL) {
3555 return LDB_ERR_OPERATIONS_ERROR;
3557 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3559 ret = ldb_request_add_control(req,
3560 LDB_CONTROL_SEARCH_OPTIONS_OID,
3562 if (ret != LDB_SUCCESS) {
3567 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3568 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3569 if (ret != LDB_SUCCESS) {
3574 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3575 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3576 if (ret != LDB_SUCCESS) {
3581 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3582 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3583 if (ret != LDB_SUCCESS) {
3588 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3589 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3590 if (!extended_ctrl) {
3591 return LDB_ERR_OPERATIONS_ERROR;
3593 extended_ctrl->type = 1;
3595 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3596 if (ret != LDB_SUCCESS) {
3601 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3602 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3603 if (ret != LDB_SUCCESS) {
3608 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3609 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3610 if (ret != LDB_SUCCESS) {
3615 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3616 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3617 if (ret != LDB_SUCCESS) {
3622 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3623 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3624 if (ret != LDB_SUCCESS) {
3629 if (dsdb_flags & DSDB_TREE_DELETE) {
3630 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3631 if (ret != LDB_SUCCESS) {
3640 an add with a set of controls
3642 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3643 uint32_t dsdb_flags)
3645 struct ldb_request *req;
3648 ret = ldb_build_add_req(&req, ldb, ldb,
3652 ldb_op_default_callback,
3655 if (ret != LDB_SUCCESS) return ret;
3657 ret = dsdb_request_add_controls(req, dsdb_flags);
3658 if (ret != LDB_SUCCESS) {
3663 ret = dsdb_autotransaction_request(ldb, req);
3670 a modify with a set of controls
3672 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3673 uint32_t dsdb_flags)
3675 struct ldb_request *req;
3678 ret = ldb_build_mod_req(&req, ldb, ldb,
3682 ldb_op_default_callback,
3685 if (ret != LDB_SUCCESS) return ret;
3687 ret = dsdb_request_add_controls(req, dsdb_flags);
3688 if (ret != LDB_SUCCESS) {
3693 ret = dsdb_autotransaction_request(ldb, req);
3700 like dsdb_modify() but set all the element flags to
3701 LDB_FLAG_MOD_REPLACE
3703 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3707 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3708 for (i=0;i<msg->num_elements;i++) {
3709 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3712 return dsdb_modify(ldb, msg, dsdb_flags);
3717 search for attrs on one DN, allowing for dsdb_flags controls
3719 int dsdb_search_dn(struct ldb_context *ldb,
3720 TALLOC_CTX *mem_ctx,
3721 struct ldb_result **_res,
3722 struct ldb_dn *basedn,
3723 const char * const *attrs,
3724 uint32_t dsdb_flags)
3727 struct ldb_request *req;
3728 struct ldb_result *res;
3730 res = talloc_zero(mem_ctx, struct ldb_result);
3732 return ldb_oom(ldb);
3735 ret = ldb_build_search_req(&req, ldb, res,
3742 ldb_search_default_callback,
3744 if (ret != LDB_SUCCESS) {
3749 ret = dsdb_request_add_controls(req, dsdb_flags);
3750 if (ret != LDB_SUCCESS) {
3755 ret = ldb_request(ldb, req);
3756 if (ret == LDB_SUCCESS) {
3757 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3761 if (ret != LDB_SUCCESS) {
3771 search for attrs on one DN, by the GUID of the DN, allowing for
3774 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3775 TALLOC_CTX *mem_ctx,
3776 struct ldb_result **_res,
3777 const struct GUID *guid,
3778 const char * const *attrs,
3779 uint32_t dsdb_flags)
3781 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3785 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3786 if (!ldb_dn_validate(dn)) {
3787 talloc_free(tmp_ctx);
3788 return LDB_ERR_INVALID_DN_SYNTAX;
3791 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3792 talloc_free(tmp_ctx);
3797 general search with dsdb_flags for controls
3799 int dsdb_search(struct ldb_context *ldb,
3800 TALLOC_CTX *mem_ctx,
3801 struct ldb_result **_res,
3802 struct ldb_dn *basedn,
3803 enum ldb_scope scope,
3804 const char * const *attrs,
3805 uint32_t dsdb_flags,
3806 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3809 struct ldb_request *req;
3810 struct ldb_result *res;
3812 char *expression = NULL;
3813 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3815 res = talloc_zero(tmp_ctx, struct ldb_result);
3817 talloc_free(tmp_ctx);
3818 return ldb_oom(ldb);
3822 va_start(ap, exp_fmt);
3823 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3827 talloc_free(tmp_ctx);
3828 return ldb_oom(ldb);
3832 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3839 ldb_search_default_callback,
3841 if (ret != LDB_SUCCESS) {
3842 talloc_free(tmp_ctx);
3846 ret = dsdb_request_add_controls(req, dsdb_flags);
3847 if (ret != LDB_SUCCESS) {
3848 talloc_free(tmp_ctx);
3849 ldb_reset_err_string(ldb);
3853 ret = ldb_request(ldb, req);
3854 if (ret == LDB_SUCCESS) {
3855 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3858 if (ret != LDB_SUCCESS) {
3859 talloc_free(tmp_ctx);
3863 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3864 if (res->count == 0) {
3865 talloc_free(tmp_ctx);
3866 ldb_reset_err_string(ldb);
3867 return LDB_ERR_NO_SUCH_OBJECT;
3869 if (res->count != 1) {
3870 talloc_free(tmp_ctx);
3871 ldb_reset_err_string(ldb);
3872 return LDB_ERR_CONSTRAINT_VIOLATION;
3876 *_res = talloc_steal(mem_ctx, res);
3877 talloc_free(tmp_ctx);
3884 general search with dsdb_flags for controls
3885 returns exactly 1 record or an error
3887 int dsdb_search_one(struct ldb_context *ldb,
3888 TALLOC_CTX *mem_ctx,
3889 struct ldb_message **msg,
3890 struct ldb_dn *basedn,
3891 enum ldb_scope scope,
3892 const char * const *attrs,
3893 uint32_t dsdb_flags,
3894 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3897 struct ldb_result *res;
3899 char *expression = NULL;
3900 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3902 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3904 res = talloc_zero(tmp_ctx, struct ldb_result);
3906 talloc_free(tmp_ctx);
3907 return ldb_oom(ldb);
3911 va_start(ap, exp_fmt);
3912 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3916 talloc_free(tmp_ctx);
3917 return ldb_oom(ldb);
3919 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3920 dsdb_flags, "%s", expression);
3922 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3926 if (ret != LDB_SUCCESS) {
3927 talloc_free(tmp_ctx);
3931 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3932 talloc_free(tmp_ctx);
3937 /* returns back the forest DNS name */
3938 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3940 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3941 ldb_get_root_basedn(ldb));
3944 if (forest_name == NULL) {
3948 p = strchr(forest_name, '/');
3957 validate that an DSA GUID belongs to the specified user sid.
3958 The user SID must be a domain controller account (either RODC or
3961 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3962 const struct GUID *dsa_guid,
3963 const struct dom_sid *sid)
3966 - find DN of record with the DSA GUID in the
3967 configuration partition (objectGUID)
3968 - remove "NTDS Settings" component from DN
3969 - do a base search on that DN for serverReference with
3971 - extract objectSid from resulting serverReference
3973 - check this sid matches the sid argument
3975 struct ldb_dn *config_dn;
3976 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3977 struct ldb_message *msg;
3978 const char *attrs1[] = { NULL };
3979 const char *attrs2[] = { "serverReference", NULL };
3981 struct ldb_dn *dn, *account_dn;
3982 struct dom_sid sid2;
3985 config_dn = ldb_get_config_basedn(ldb);
3987 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3988 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3989 if (ret != LDB_SUCCESS) {
3990 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3991 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3992 talloc_free(tmp_ctx);
3993 return ldb_operr(ldb);
3997 if (!ldb_dn_remove_child_components(dn, 1)) {
3998 talloc_free(tmp_ctx);
3999 return ldb_operr(ldb);
4002 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4003 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4004 "(objectClass=server)");
4005 if (ret != LDB_SUCCESS) {
4006 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4007 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4008 talloc_free(tmp_ctx);
4009 return ldb_operr(ldb);
4012 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4013 if (account_dn == NULL) {
4014 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4015 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4016 talloc_free(tmp_ctx);
4017 return ldb_operr(ldb);
4020 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4021 if (!NT_STATUS_IS_OK(status)) {
4022 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4023 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4024 talloc_free(tmp_ctx);
4025 return ldb_operr(ldb);
4028 if (!dom_sid_equal(sid, &sid2)) {
4029 /* someone is trying to spoof another account */
4030 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4031 GUID_string(tmp_ctx, dsa_guid),
4032 dom_sid_string(tmp_ctx, sid),
4033 dom_sid_string(tmp_ctx, &sid2)));
4034 talloc_free(tmp_ctx);
4035 return ldb_operr(ldb);
4038 talloc_free(tmp_ctx);
4042 static const char *secret_attributes[] = {
4045 "initialAuthIncoming",
4046 "initialAuthOutgoing",
4050 "supplementalCredentials",
4051 "trustAuthIncoming",
4052 "trustAuthOutgoing",
4058 check if the attribute belongs to the RODC filtered attribute set
4059 Note that attributes that are in the filtered attribute set are the
4060 ones that _are_ always sent to a RODC
4062 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4064 /* they never get secret attributes */
4065 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4069 /* they do get non-secret critical attributes */
4070 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4074 /* they do get non-secret attributes marked as being in the FAS */
4075 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4079 /* other attributes are denied */
4083 /* return fsmo role dn and role owner dn for a particular role*/
4084 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4085 struct ldb_context *ldb,
4087 struct ldb_dn **fsmo_role_dn,
4088 struct ldb_dn **role_owner_dn)
4092 case DREPL_NAMING_MASTER:
4093 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4094 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4095 if (ret != LDB_SUCCESS) {
4096 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4097 ldb_errstring(ldb)));
4098 talloc_free(tmp_ctx);
4099 return WERR_DS_DRA_INTERNAL_ERROR;
4102 case DREPL_INFRASTRUCTURE_MASTER:
4103 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4104 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4105 if (ret != LDB_SUCCESS) {
4106 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4107 ldb_errstring(ldb)));
4108 talloc_free(tmp_ctx);
4109 return WERR_DS_DRA_INTERNAL_ERROR;
4112 case DREPL_RID_MASTER:
4113 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4114 if (ret != LDB_SUCCESS) {
4115 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4116 talloc_free(tmp_ctx);
4117 return WERR_DS_DRA_INTERNAL_ERROR;
4120 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4121 if (ret != LDB_SUCCESS) {
4122 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4123 ldb_errstring(ldb)));
4124 talloc_free(tmp_ctx);
4125 return WERR_DS_DRA_INTERNAL_ERROR;
4128 case DREPL_SCHEMA_MASTER:
4129 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4130 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4131 if (ret != LDB_SUCCESS) {
4132 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4133 ldb_errstring(ldb)));
4134 talloc_free(tmp_ctx);
4135 return WERR_DS_DRA_INTERNAL_ERROR;
4138 case DREPL_PDC_MASTER:
4139 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4140 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4141 if (ret != LDB_SUCCESS) {
4142 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4143 ldb_errstring(ldb)));
4144 talloc_free(tmp_ctx);
4145 return WERR_DS_DRA_INTERNAL_ERROR;
4149 return WERR_DS_DRA_INTERNAL_ERROR;
4154 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4155 TALLOC_CTX *mem_ctx,
4156 struct ldb_dn *server_dn)
4159 struct ldb_result *res = NULL;
4160 const char * const attrs[] = { "dNSHostName", NULL};
4162 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4166 if (ldb_ret != LDB_SUCCESS) {
4167 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4168 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4172 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4176 returns true if an attribute is in the filter,
4177 false otherwise, provided that attribute value is provided with the expression
4179 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4183 switch (tree->operation) {
4186 for (i=0;i<tree->u.list.num_elements;i++) {
4187 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4193 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4194 case LDB_OP_EQUALITY:
4195 case LDB_OP_GREATER:
4198 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4202 case LDB_OP_SUBSTRING:
4203 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4207 case LDB_OP_PRESENT:
4208 /* (attrname=*) is not filtered out */
4210 case LDB_OP_EXTENDED:
4211 if (tree->u.extended.attr &&
4212 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4220 bool is_attr_in_list(const char * const * attrs, const char *attr)
4224 for (i = 0; attrs[i]; i++) {
4225 if (ldb_attr_cmp(attrs[i], attr) == 0)