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);
929 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
933 add a unsigned int element to a message
935 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
936 const char *attr_name, unsigned int v)
938 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
942 add a (signed) int64_t element to a message
944 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
945 const char *attr_name, int64_t v)
947 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
948 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
952 add a uint64_t element to a message
954 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955 const char *attr_name, uint64_t v)
957 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
961 add a samr_Password element to a message
963 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
964 const char *attr_name, const struct samr_Password *hash)
967 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
969 return ldb_oom(sam_ldb);
972 return ldb_msg_add_value(msg, attr_name, &val, NULL);
976 add a samr_Password array to a message
978 int samdb_msg_add_hashes(struct ldb_context *ldb,
979 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
980 const char *attr_name, struct samr_Password *hashes,
985 val.data = talloc_array_size(mem_ctx, 16, count);
986 val.length = count*16;
990 for (i=0;i<count;i++) {
991 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
993 return ldb_msg_add_value(msg, attr_name, &val, NULL);
997 add a acct_flags element to a message
999 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1000 const char *attr_name, uint32_t v)
1002 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1006 add a logon_hours element to a message
1008 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1009 const char *attr_name, struct samr_LogonHours *hours)
1012 val.length = hours->units_per_week / 8;
1013 val.data = hours->bits;
1014 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1018 add a parameters element to a message
1020 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1021 const char *attr_name, struct lsa_BinaryString *parameters)
1024 val.length = parameters->length;
1025 val.data = (uint8_t *)parameters->array;
1026 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1030 sets a general value element to a message
1032 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1033 const char *attr_name, const struct ldb_val *val)
1035 struct ldb_message_element *el;
1037 el = ldb_msg_find_element(msg, attr_name);
1041 return ldb_msg_add_value(msg, attr_name, val, NULL);
1045 set a string element in a message
1047 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1048 const char *attr_name, const char *str)
1050 struct ldb_message_element *el;
1052 el = ldb_msg_find_element(msg, attr_name);
1056 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1060 * sets a signed integer in a message
1062 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1063 struct ldb_message *msg, const char *attr_name, int v)
1065 struct ldb_message_element *el;
1067 el = ldb_msg_find_element(msg, attr_name);
1071 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1075 * sets an unsigned integer in a message
1077 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1078 struct ldb_message *msg, const char *attr_name,
1081 struct ldb_message_element *el;
1083 el = ldb_msg_find_element(msg, attr_name);
1087 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1091 * Handle ldb_request in transaction
1093 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1094 struct ldb_request *req)
1098 ret = ldb_transaction_start(sam_ldb);
1099 if (ret != LDB_SUCCESS) {
1103 ret = ldb_request(sam_ldb, req);
1104 if (ret == LDB_SUCCESS) {
1105 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1108 if (ret == LDB_SUCCESS) {
1109 return ldb_transaction_commit(sam_ldb);
1111 ldb_transaction_cancel(sam_ldb);
1117 return a default security descriptor
1119 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1121 struct security_descriptor *sd;
1123 sd = security_descriptor_initialise(mem_ctx);
1128 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1130 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1131 struct ldb_dn *aggregate_dn;
1136 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1137 if (!aggregate_dn) {
1140 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1143 return aggregate_dn;
1146 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1148 struct ldb_dn *new_dn;
1150 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1151 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1152 talloc_free(new_dn);
1158 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1160 struct ldb_dn *new_dn;
1162 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1163 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1164 talloc_free(new_dn);
1170 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1172 struct ldb_dn *new_dn;
1174 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1175 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1176 talloc_free(new_dn);
1183 work out the domain sid for the current open ldb
1185 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1187 TALLOC_CTX *tmp_ctx;
1188 const struct dom_sid *domain_sid;
1189 const char *attrs[] = {
1193 struct ldb_result *res;
1196 /* see if we have a cached copy */
1197 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1202 tmp_ctx = talloc_new(ldb);
1203 if (tmp_ctx == NULL) {
1207 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1209 if (ret != LDB_SUCCESS) {
1213 if (res->count != 1) {
1217 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1218 if (domain_sid == NULL) {
1222 /* cache the domain_sid in the ldb */
1223 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1227 talloc_steal(ldb, domain_sid);
1228 talloc_free(tmp_ctx);
1233 talloc_free(tmp_ctx);
1238 get domain sid from cache
1240 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1242 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1245 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1247 TALLOC_CTX *tmp_ctx;
1248 struct dom_sid *dom_sid_new;
1249 struct dom_sid *dom_sid_old;
1251 /* see if we have a cached copy */
1252 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1253 "cache.domain_sid"), struct dom_sid);
1255 tmp_ctx = talloc_new(ldb);
1256 if (tmp_ctx == NULL) {
1260 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1265 /* cache the domain_sid in the ldb */
1266 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1270 talloc_steal(ldb, dom_sid_new);
1271 talloc_free(tmp_ctx);
1272 talloc_free(dom_sid_old);
1277 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1278 talloc_free(tmp_ctx);
1282 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1284 TALLOC_CTX *tmp_ctx;
1285 struct ldb_dn *ntds_settings_dn_new;
1286 struct ldb_dn *ntds_settings_dn_old;
1288 /* see if we have a cached copy */
1289 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1290 "cache.ntds_settings_dn"), struct ldb_dn);
1292 tmp_ctx = talloc_new(ldb);
1293 if (tmp_ctx == NULL) {
1297 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1298 if (!ntds_settings_dn_new) {
1302 /* cache the domain_sid in the ldb */
1303 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1307 talloc_steal(ldb, ntds_settings_dn_new);
1308 talloc_free(tmp_ctx);
1309 talloc_free(ntds_settings_dn_old);
1314 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1315 talloc_free(tmp_ctx);
1319 /* Obtain the short name of the flexible single master operator
1320 * (FSMO), such as the PDC Emulator */
1321 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1324 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1325 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1326 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1327 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1329 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1330 /* Ensure this matches the format. This gives us a
1331 * bit more confidence that a 'cn' value will be a
1336 return (char *)val->data;
1342 work out the ntds settings dn for the current open ldb
1344 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1346 TALLOC_CTX *tmp_ctx;
1347 const char *root_attrs[] = { "dsServiceName", NULL };
1349 struct ldb_result *root_res;
1350 struct ldb_dn *settings_dn;
1352 /* see if we have a cached copy */
1353 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1358 tmp_ctx = talloc_new(ldb);
1359 if (tmp_ctx == NULL) {
1363 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1365 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1366 ldb_errstring(ldb)));
1370 if (root_res->count != 1) {
1374 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1376 /* cache the domain_sid in the ldb */
1377 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1381 talloc_steal(ldb, settings_dn);
1382 talloc_free(tmp_ctx);
1387 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1388 talloc_free(tmp_ctx);
1393 work out the ntds settings invocationId for the current open ldb
1395 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1397 TALLOC_CTX *tmp_ctx;
1398 const char *attrs[] = { "invocationId", NULL };
1400 struct ldb_result *res;
1401 struct GUID *invocation_id;
1403 /* see if we have a cached copy */
1404 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1405 if (invocation_id) {
1406 return invocation_id;
1409 tmp_ctx = talloc_new(ldb);
1410 if (tmp_ctx == NULL) {
1414 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1419 if (res->count != 1) {
1423 invocation_id = talloc(tmp_ctx, struct GUID);
1424 if (!invocation_id) {
1428 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1430 /* cache the domain_sid in the ldb */
1431 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1435 talloc_steal(ldb, invocation_id);
1436 talloc_free(tmp_ctx);
1438 return invocation_id;
1441 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1442 talloc_free(tmp_ctx);
1446 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1448 TALLOC_CTX *tmp_ctx;
1449 struct GUID *invocation_id_new;
1450 struct GUID *invocation_id_old;
1452 /* see if we have a cached copy */
1453 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1454 "cache.invocation_id");
1456 tmp_ctx = talloc_new(ldb);
1457 if (tmp_ctx == NULL) {
1461 invocation_id_new = talloc(tmp_ctx, struct GUID);
1462 if (!invocation_id_new) {
1466 *invocation_id_new = *invocation_id_in;
1468 /* cache the domain_sid in the ldb */
1469 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1473 talloc_steal(ldb, invocation_id_new);
1474 talloc_free(tmp_ctx);
1475 talloc_free(invocation_id_old);
1480 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1481 talloc_free(tmp_ctx);
1486 work out the ntds settings objectGUID for the current open ldb
1488 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1490 TALLOC_CTX *tmp_ctx;
1491 const char *attrs[] = { "objectGUID", NULL };
1493 struct ldb_result *res;
1494 struct GUID *ntds_guid;
1496 /* see if we have a cached copy */
1497 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1502 tmp_ctx = talloc_new(ldb);
1503 if (tmp_ctx == NULL) {
1507 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1512 if (res->count != 1) {
1516 ntds_guid = talloc(tmp_ctx, struct GUID);
1521 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1523 /* cache the domain_sid in the ldb */
1524 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1528 talloc_steal(ldb, ntds_guid);
1529 talloc_free(tmp_ctx);
1534 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1535 talloc_free(tmp_ctx);
1539 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1541 TALLOC_CTX *tmp_ctx;
1542 struct GUID *ntds_guid_new;
1543 struct GUID *ntds_guid_old;
1545 /* see if we have a cached copy */
1546 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1548 tmp_ctx = talloc_new(ldb);
1549 if (tmp_ctx == NULL) {
1553 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1554 if (!ntds_guid_new) {
1558 *ntds_guid_new = *ntds_guid_in;
1560 /* cache the domain_sid in the ldb */
1561 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1565 talloc_steal(ldb, ntds_guid_new);
1566 talloc_free(tmp_ctx);
1567 talloc_free(ntds_guid_old);
1572 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1573 talloc_free(tmp_ctx);
1578 work out the server dn for the current open ldb
1580 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1582 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1586 work out the server dn for the current open ldb
1588 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1590 struct ldb_dn *server_dn;
1591 struct ldb_dn *servers_dn;
1592 struct ldb_dn *server_site_dn;
1594 /* TODO: there must be a saner way to do this!! */
1595 server_dn = samdb_server_dn(ldb, mem_ctx);
1596 if (!server_dn) return NULL;
1598 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1599 talloc_free(server_dn);
1600 if (!servers_dn) return NULL;
1602 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1603 talloc_free(servers_dn);
1605 return server_site_dn;
1609 find the site name from a computers DN record
1611 int samdb_find_site_for_computer(struct ldb_context *ldb,
1612 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1613 const char **site_name)
1617 const struct ldb_val *rdn_val;
1621 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1622 if (ret != LDB_SUCCESS) {
1626 if (!ldb_dn_remove_child_components(dn, 2)) {
1628 return LDB_ERR_INVALID_DN_SYNTAX;
1630 rdn_val = ldb_dn_get_rdn_val(dn);
1631 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1634 return LDB_ERR_OPERATIONS_ERROR;
1640 find the NTDS GUID from a computers DN record
1642 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1643 struct GUID *ntds_guid)
1648 *ntds_guid = GUID_zero();
1650 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1651 if (ret != LDB_SUCCESS) {
1655 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1657 return LDB_ERR_OPERATIONS_ERROR;
1660 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1666 find a 'reference' DN that points at another object
1667 (eg. serverReference, rIDManagerReference etc)
1669 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1670 const char *attribute, struct ldb_dn **dn)
1672 const char *attrs[2];
1673 struct ldb_result *res;
1676 attrs[0] = attribute;
1679 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1680 if (ret != LDB_SUCCESS) {
1684 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1686 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1687 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1688 ldb_dn_get_linearized(base));
1690 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1691 ldb_dn_get_linearized(base));
1694 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1702 find our machine account via the serverReference attribute in the
1705 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1707 struct ldb_dn *server_dn;
1710 server_dn = samdb_server_dn(ldb, mem_ctx);
1711 if (server_dn == NULL) {
1712 return LDB_ERR_NO_SUCH_OBJECT;
1715 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1716 talloc_free(server_dn);
1722 find the RID Manager$ DN via the rIDManagerReference attribute in the
1725 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1727 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1728 "rIDManagerReference", dn);
1732 find the RID Set DN via the rIDSetReferences attribute in our
1735 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1737 struct ldb_dn *server_ref_dn;
1740 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1741 if (ret != LDB_SUCCESS) {
1744 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1745 talloc_free(server_ref_dn);
1749 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1751 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1758 return (const char *) val->data;
1762 * Finds the client site by using the client's IP address.
1763 * The "subnet_name" returns the name of the subnet if parameter != NULL
1765 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1766 const char *ip_address, char **subnet_name)
1768 const char *attrs[] = { "cn", "siteObject", NULL };
1769 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1770 struct ldb_result *res;
1771 const struct ldb_val *val;
1772 const char *site_name = NULL, *l_subnet_name = NULL;
1773 const char *allow_list[2] = { NULL, NULL };
1774 unsigned int i, count;
1778 * if we don't have a client ip e.g. ncalrpc
1779 * the server site is the client site
1781 if (ip_address == NULL) {
1782 return samdb_server_site_name(ldb, mem_ctx);
1785 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1786 if (sites_container_dn == NULL) {
1790 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1791 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1792 talloc_free(sites_container_dn);
1793 talloc_free(subnets_dn);
1797 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1799 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1801 } else if (ret != LDB_SUCCESS) {
1802 talloc_free(sites_container_dn);
1803 talloc_free(subnets_dn);
1809 for (i = 0; i < count; i++) {
1810 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1813 allow_list[0] = l_subnet_name;
1815 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1816 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1819 if (sites_dn == NULL) {
1820 /* No reference, maybe another subnet matches */
1824 /* "val" cannot be NULL here since "sites_dn" != NULL */
1825 val = ldb_dn_get_rdn_val(sites_dn);
1826 site_name = talloc_strdup(mem_ctx,
1827 (const char *) val->data);
1829 talloc_free(sites_dn);
1835 if (site_name == NULL) {
1836 /* This is the Windows Server fallback rule: when no subnet
1837 * exists and we have only one site available then use it (it
1838 * is for sure the same as our server site). If more sites do
1839 * exist then we don't know which one to use and set the site
1841 cnt = samdb_search_count(ldb, sites_container_dn,
1842 "(objectClass=site)");
1844 site_name = samdb_server_site_name(ldb, mem_ctx);
1846 site_name = talloc_strdup(mem_ctx, "");
1848 l_subnet_name = NULL;
1851 if (subnet_name != NULL) {
1852 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1855 talloc_free(sites_container_dn);
1856 talloc_free(subnets_dn);
1863 work out if we are the PDC for the domain of the current open ldb
1865 bool samdb_is_pdc(struct ldb_context *ldb)
1867 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1869 struct ldb_result *dom_res;
1870 TALLOC_CTX *tmp_ctx;
1874 tmp_ctx = talloc_new(ldb);
1875 if (tmp_ctx == NULL) {
1876 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1880 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1881 if (ret != LDB_SUCCESS) {
1882 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1883 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1884 ldb_errstring(ldb)));
1887 if (dom_res->count != 1) {
1891 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1893 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1899 talloc_free(tmp_ctx);
1904 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1905 talloc_free(tmp_ctx);
1910 work out if we are a Global Catalog server for the domain of the current open ldb
1912 bool samdb_is_gc(struct ldb_context *ldb)
1914 const char *attrs[] = { "options", NULL };
1916 struct ldb_result *res;
1917 TALLOC_CTX *tmp_ctx;
1919 tmp_ctx = talloc_new(ldb);
1920 if (tmp_ctx == NULL) {
1921 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1925 /* Query cn=ntds settings,.... */
1926 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1927 if (ret != LDB_SUCCESS) {
1928 talloc_free(tmp_ctx);
1931 if (res->count != 1) {
1932 talloc_free(tmp_ctx);
1936 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1937 talloc_free(tmp_ctx);
1939 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1940 if (options & 0x000000001) {
1946 /* Find a domain object in the parents of a particular DN. */
1947 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1948 struct ldb_dn **parent_dn, const char **errstring)
1950 TALLOC_CTX *local_ctx;
1951 struct ldb_dn *sdn = dn;
1952 struct ldb_result *res = NULL;
1953 int ret = LDB_SUCCESS;
1954 const char *attrs[] = { NULL };
1956 local_ctx = talloc_new(mem_ctx);
1957 if (local_ctx == NULL) return ldb_oom(ldb);
1959 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1960 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1961 "(|(objectClass=domain)(objectClass=builtinDomain))");
1962 if (ret == LDB_SUCCESS) {
1963 if (res->count == 1) {
1971 if (ret != LDB_SUCCESS) {
1972 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1973 ldb_dn_get_linearized(dn),
1974 ldb_dn_get_linearized(sdn),
1975 ldb_errstring(ldb));
1976 talloc_free(local_ctx);
1979 if (res->count != 1) {
1980 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1981 ldb_dn_get_linearized(dn));
1982 DEBUG(0,(__location__ ": %s\n", *errstring));
1983 talloc_free(local_ctx);
1984 return LDB_ERR_CONSTRAINT_VIOLATION;
1987 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1988 talloc_free(local_ctx);
1994 * Performs checks on a user password (plaintext UNIX format - attribute
1995 * "password"). The remaining parameters have to be extracted from the domain
1998 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2000 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2001 const uint32_t pwdProperties,
2002 const uint32_t minPwdLength)
2004 /* checks if the "minPwdLength" property is satisfied */
2005 if (minPwdLength > password->length)
2006 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2008 /* checks the password complexity */
2009 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2010 && (password->data != NULL)
2011 && (!check_password_quality((const char *) password->data)))
2012 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2014 return SAMR_VALIDATION_STATUS_SUCCESS;
2018 * Callback for "samdb_set_password" password change
2020 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2025 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2028 if (ares->error != LDB_SUCCESS) {
2030 req->context = talloc_steal(req,
2031 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2033 return ldb_request_done(req, ret);
2036 if (ares->type != LDB_REPLY_DONE) {
2038 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2041 req->context = talloc_steal(req,
2042 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2044 return ldb_request_done(req, LDB_SUCCESS);
2048 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2049 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2050 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2051 * user change or not. The "rejectReason" gives some more informations if the
2054 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2055 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2057 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2058 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2059 const DATA_BLOB *new_password,
2060 const struct samr_Password *lmNewHash,
2061 const struct samr_Password *ntNewHash,
2062 const struct samr_Password *lmOldHash,
2063 const struct samr_Password *ntOldHash,
2064 enum samPwdChangeReason *reject_reason,
2065 struct samr_DomInfo1 **_dominfo)
2067 struct ldb_message *msg;
2068 struct ldb_message_element *el;
2069 struct ldb_request *req;
2070 struct dsdb_control_password_change_status *pwd_stat = NULL;
2072 NTSTATUS status = NT_STATUS_OK;
2074 #define CHECK_RET(x) \
2075 if (x != LDB_SUCCESS) { \
2077 return NT_STATUS_NO_MEMORY; \
2080 msg = ldb_msg_new(mem_ctx);
2082 return NT_STATUS_NO_MEMORY;
2085 if ((new_password != NULL)
2086 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2087 /* we have the password as plaintext UTF16 */
2088 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2089 new_password, NULL));
2090 el = ldb_msg_find_element(msg, "clearTextPassword");
2091 el->flags = LDB_FLAG_MOD_REPLACE;
2092 } else if ((new_password == NULL)
2093 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2094 /* we have a password as LM and/or NT hash */
2095 if (lmNewHash != NULL) {
2096 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2097 "dBCSPwd", lmNewHash));
2098 el = ldb_msg_find_element(msg, "dBCSPwd");
2099 el->flags = LDB_FLAG_MOD_REPLACE;
2101 if (ntNewHash != NULL) {
2102 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2103 "unicodePwd", ntNewHash));
2104 el = ldb_msg_find_element(msg, "unicodePwd");
2105 el->flags = LDB_FLAG_MOD_REPLACE;
2108 /* the password wasn't specified correctly */
2110 return NT_STATUS_INVALID_PARAMETER;
2113 /* build modify request */
2114 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2115 samdb_set_password_callback, NULL);
2116 if (ret != LDB_SUCCESS) {
2118 return NT_STATUS_NO_MEMORY;
2121 /* A password change operation */
2122 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2123 struct dsdb_control_password_change *change;
2125 change = talloc(req, struct dsdb_control_password_change);
2126 if (change == NULL) {
2129 return NT_STATUS_NO_MEMORY;
2132 change->old_nt_pwd_hash = ntOldHash;
2133 change->old_lm_pwd_hash = lmOldHash;
2135 ret = ldb_request_add_control(req,
2136 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2138 if (ret != LDB_SUCCESS) {
2141 return NT_STATUS_NO_MEMORY;
2144 ret = ldb_request_add_control(req,
2145 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2147 if (ret != LDB_SUCCESS) {
2150 return NT_STATUS_NO_MEMORY;
2152 ret = ldb_request_add_control(req,
2153 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2155 if (ret != LDB_SUCCESS) {
2158 return NT_STATUS_NO_MEMORY;
2161 ret = dsdb_autotransaction_request(ldb, req);
2163 if (req->context != NULL) {
2164 pwd_stat = talloc_steal(mem_ctx,
2165 ((struct ldb_control *)req->context)->data);
2171 /* Sets the domain info (if requested) */
2172 if (_dominfo != NULL) {
2173 struct samr_DomInfo1 *dominfo;
2175 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2176 if (dominfo == NULL) {
2177 return NT_STATUS_NO_MEMORY;
2180 if (pwd_stat != NULL) {
2181 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2182 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2183 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2184 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2185 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2188 *_dominfo = dominfo;
2191 if (reject_reason != NULL) {
2192 if (pwd_stat != NULL) {
2193 *reject_reason = pwd_stat->reject_reason;
2195 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2199 if (pwd_stat != NULL) {
2200 talloc_free(pwd_stat);
2203 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2204 const char *errmsg = ldb_errstring(ldb);
2205 char *endptr = NULL;
2206 WERROR werr = WERR_GENERAL_FAILURE;
2207 status = NT_STATUS_UNSUCCESSFUL;
2208 if (errmsg != NULL) {
2209 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2211 if (endptr != errmsg) {
2212 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2213 status = NT_STATUS_WRONG_PASSWORD;
2215 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2216 status = NT_STATUS_PASSWORD_RESTRICTION;
2219 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2220 /* don't let the caller know if an account doesn't exist */
2221 status = NT_STATUS_WRONG_PASSWORD;
2222 } else if (ret != LDB_SUCCESS) {
2223 status = NT_STATUS_UNSUCCESSFUL;
2230 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2231 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2232 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2233 * user change or not. The "rejectReason" gives some more informations if the
2236 * This wrapper function for "samdb_set_password" takes a SID as input rather
2239 * This call encapsulates a new LDB transaction for changing the password;
2240 * therefore the user hasn't to start a new one.
2242 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2243 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2244 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2245 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2247 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2248 const struct dom_sid *user_sid,
2249 const DATA_BLOB *new_password,
2250 const struct samr_Password *lmNewHash,
2251 const struct samr_Password *ntNewHash,
2252 const struct samr_Password *lmOldHash,
2253 const struct samr_Password *ntOldHash,
2254 enum samPwdChangeReason *reject_reason,
2255 struct samr_DomInfo1 **_dominfo)
2258 struct ldb_dn *user_dn;
2261 ret = ldb_transaction_start(ldb);
2262 if (ret != LDB_SUCCESS) {
2263 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2264 return NT_STATUS_TRANSACTION_ABORTED;
2267 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2268 "(&(objectSid=%s)(objectClass=user))",
2269 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2271 ldb_transaction_cancel(ldb);
2272 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2273 dom_sid_string(mem_ctx, user_sid)));
2274 return NT_STATUS_NO_SUCH_USER;
2277 nt_status = samdb_set_password(ldb, mem_ctx,
2280 lmNewHash, ntNewHash,
2281 lmOldHash, ntOldHash,
2282 reject_reason, _dominfo);
2283 if (!NT_STATUS_IS_OK(nt_status)) {
2284 ldb_transaction_cancel(ldb);
2285 talloc_free(user_dn);
2289 ret = ldb_transaction_commit(ldb);
2290 if (ret != LDB_SUCCESS) {
2291 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2292 ldb_dn_get_linearized(user_dn),
2293 ldb_errstring(ldb)));
2294 talloc_free(user_dn);
2295 return NT_STATUS_TRANSACTION_ABORTED;
2298 talloc_free(user_dn);
2299 return NT_STATUS_OK;
2303 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2304 struct dom_sid *sid, struct ldb_dn **ret_dn)
2306 struct ldb_message *msg;
2307 struct ldb_dn *basedn;
2311 sidstr = dom_sid_string(mem_ctx, sid);
2312 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2314 /* We might have to create a ForeignSecurityPrincipal, even if this user
2315 * is in our own domain */
2317 msg = ldb_msg_new(sidstr);
2319 talloc_free(sidstr);
2320 return NT_STATUS_NO_MEMORY;
2323 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2324 ldb_get_default_basedn(sam_ctx),
2325 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2327 if (ret != LDB_SUCCESS) {
2328 DEBUG(0, ("Failed to find DN for "
2329 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2330 talloc_free(sidstr);
2331 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2334 /* add core elements to the ldb_message for the alias */
2336 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2337 talloc_free(sidstr);
2338 return NT_STATUS_NO_MEMORY;
2341 samdb_msg_add_string(sam_ctx, msg, msg,
2343 "foreignSecurityPrincipal");
2345 /* create the alias */
2346 ret = ldb_add(sam_ctx, msg);
2347 if (ret != LDB_SUCCESS) {
2348 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2350 ldb_dn_get_linearized(msg->dn),
2351 ldb_errstring(sam_ctx)));
2352 talloc_free(sidstr);
2353 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2356 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2357 talloc_free(sidstr);
2359 return NT_STATUS_OK;
2364 Find the DN of a domain, assuming it to be a dotted.dns name
2367 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2370 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2371 const char *binary_encoded;
2372 const char **split_realm;
2379 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2381 talloc_free(tmp_ctx);
2384 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2385 for (i=0; split_realm[i]; i++) {
2386 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2387 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2388 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2389 binary_encoded, ldb_dn_get_linearized(dn)));
2390 talloc_free(tmp_ctx);
2394 if (!ldb_dn_validate(dn)) {
2395 DEBUG(2, ("Failed to validated DN %s\n",
2396 ldb_dn_get_linearized(dn)));
2397 talloc_free(tmp_ctx);
2400 talloc_free(tmp_ctx);
2405 Find the DN of a domain, be it the netbios or DNS name
2407 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2408 const char *domain_name)
2410 const char * const domain_ref_attrs[] = {
2413 const char * const domain_ref2_attrs[] = {
2416 struct ldb_result *res_domain_ref;
2417 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2418 /* find the domain's DN */
2419 int ret_domain = ldb_search(ldb, mem_ctx,
2421 samdb_partitions_dn(ldb, mem_ctx),
2424 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2426 if (ret_domain != LDB_SUCCESS) {
2430 if (res_domain_ref->count == 0) {
2431 ret_domain = ldb_search(ldb, mem_ctx,
2433 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2436 "(objectclass=domain)");
2437 if (ret_domain != LDB_SUCCESS) {
2441 if (res_domain_ref->count == 1) {
2442 return res_domain_ref->msgs[0]->dn;
2447 if (res_domain_ref->count > 1) {
2448 DEBUG(0,("Found %d records matching domain [%s]\n",
2449 ret_domain, domain_name));
2453 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2459 use a GUID to find a DN
2461 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2462 TALLOC_CTX *mem_ctx,
2463 const struct GUID *guid, struct ldb_dn **dn)
2466 struct ldb_result *res;
2467 const char *attrs[] = { NULL };
2468 char *guid_str = GUID_string(mem_ctx, guid);
2471 return ldb_operr(ldb);
2474 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2475 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2476 DSDB_SEARCH_SHOW_EXTENDED_DN |
2477 DSDB_SEARCH_ONE_ONLY,
2478 "objectGUID=%s", guid_str);
2479 talloc_free(guid_str);
2480 if (ret != LDB_SUCCESS) {
2484 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2491 use a DN to find a GUID with a given attribute name
2493 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2494 struct ldb_dn *dn, const char *attribute,
2498 struct ldb_result *res;
2499 const char *attrs[2];
2500 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2502 attrs[0] = attribute;
2505 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2506 DSDB_SEARCH_SHOW_DELETED |
2507 DSDB_SEARCH_SHOW_RECYCLED);
2508 if (ret != LDB_SUCCESS) {
2509 talloc_free(tmp_ctx);
2512 if (res->count < 1) {
2513 talloc_free(tmp_ctx);
2514 return LDB_ERR_NO_SUCH_OBJECT;
2516 *guid = samdb_result_guid(res->msgs[0], attribute);
2517 talloc_free(tmp_ctx);
2522 use a DN to find a GUID
2524 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2525 struct ldb_dn *dn, struct GUID *guid)
2527 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2533 adds the given GUID to the given ldb_message. This value is added
2534 for the given attr_name (may be either "objectGUID" or "parentGUID").
2536 int dsdb_msg_add_guid(struct ldb_message *msg,
2538 const char *attr_name)
2543 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2545 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2546 if (!NT_STATUS_IS_OK(status)) {
2547 ret = LDB_ERR_OPERATIONS_ERROR;
2551 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2552 if (ret != LDB_SUCCESS) {
2553 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2561 talloc_free(tmp_ctx);
2568 use a DN to find a SID
2570 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2571 struct ldb_dn *dn, struct dom_sid *sid)
2574 struct ldb_result *res;
2575 const char *attrs[] = { "objectSid", NULL };
2576 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2581 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2582 DSDB_SEARCH_SHOW_DELETED |
2583 DSDB_SEARCH_SHOW_RECYCLED);
2584 if (ret != LDB_SUCCESS) {
2585 talloc_free(tmp_ctx);
2588 if (res->count < 1) {
2589 talloc_free(tmp_ctx);
2590 return LDB_ERR_NO_SUCH_OBJECT;
2592 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2594 talloc_free(tmp_ctx);
2595 return LDB_ERR_NO_SUCH_OBJECT;
2598 talloc_free(tmp_ctx);
2603 use a SID to find a DN
2605 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2606 TALLOC_CTX *mem_ctx,
2607 struct dom_sid *sid, struct ldb_dn **dn)
2610 struct ldb_result *res;
2611 const char *attrs[] = { NULL };
2612 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2615 return ldb_operr(ldb);
2618 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2619 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2620 DSDB_SEARCH_SHOW_EXTENDED_DN |
2621 DSDB_SEARCH_ONE_ONLY,
2622 "objectSid=%s", sid_str);
2623 talloc_free(sid_str);
2624 if (ret != LDB_SUCCESS) {
2628 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2635 load a repsFromTo blob list for a given partition GUID
2636 attr must be "repsFrom" or "repsTo"
2638 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2639 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2641 const char *attrs[] = { attr, NULL };
2642 struct ldb_result *res = NULL;
2643 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2645 struct ldb_message_element *el;
2650 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2652 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2653 talloc_free(tmp_ctx);
2654 return WERR_DS_DRA_INTERNAL_ERROR;
2657 el = ldb_msg_find_element(res->msgs[0], attr);
2659 /* it's OK to be empty */
2660 talloc_free(tmp_ctx);
2664 *count = el->num_values;
2665 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2667 talloc_free(tmp_ctx);
2668 return WERR_DS_DRA_INTERNAL_ERROR;
2671 for (i=0; i<(*count); i++) {
2672 enum ndr_err_code ndr_err;
2673 ndr_err = ndr_pull_struct_blob(&el->values[i],
2676 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2677 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2678 talloc_free(tmp_ctx);
2679 return WERR_DS_DRA_INTERNAL_ERROR;
2683 talloc_free(tmp_ctx);
2689 save the repsFromTo blob list for a given partition GUID
2690 attr must be "repsFrom" or "repsTo"
2692 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2693 const char *attr, struct repsFromToBlob *r, uint32_t count)
2695 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2696 struct ldb_message *msg;
2697 struct ldb_message_element *el;
2700 msg = ldb_msg_new(tmp_ctx);
2702 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2706 el->values = talloc_array(msg, struct ldb_val, count);
2711 for (i=0; i<count; i++) {
2713 enum ndr_err_code ndr_err;
2715 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2717 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2718 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2726 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2727 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2731 talloc_free(tmp_ctx);
2736 talloc_free(tmp_ctx);
2737 return WERR_DS_DRA_INTERNAL_ERROR;
2742 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2743 object for a partition
2745 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2746 uint64_t *uSN, uint64_t *urgent_uSN)
2748 struct ldb_request *req;
2750 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2751 struct dsdb_control_current_partition *p_ctrl;
2752 struct ldb_result *res;
2754 res = talloc_zero(tmp_ctx, struct ldb_result);
2756 talloc_free(tmp_ctx);
2757 return ldb_oom(ldb);
2760 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2761 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2765 res, ldb_search_default_callback,
2767 if (ret != LDB_SUCCESS) {
2768 talloc_free(tmp_ctx);
2772 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2773 if (p_ctrl == NULL) {
2774 talloc_free(tmp_ctx);
2775 return ldb_oom(ldb);
2777 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2780 ret = ldb_request_add_control(req,
2781 DSDB_CONTROL_CURRENT_PARTITION_OID,
2783 if (ret != LDB_SUCCESS) {
2784 talloc_free(tmp_ctx);
2788 /* Run the new request */
2789 ret = ldb_request(ldb, req);
2791 if (ret == LDB_SUCCESS) {
2792 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2795 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2796 /* it hasn't been created yet, which means
2797 an implicit value of zero */
2799 talloc_free(tmp_ctx);
2803 if (ret != LDB_SUCCESS) {
2804 talloc_free(tmp_ctx);
2808 if (res->count < 1) {
2814 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2816 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2820 talloc_free(tmp_ctx);
2825 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2826 const struct drsuapi_DsReplicaCursor2 *c2)
2828 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2831 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2832 const struct drsuapi_DsReplicaCursor *c2)
2834 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2839 see if a computer identified by its invocationId is a RODC
2841 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2843 /* 1) find the DN for this servers NTDSDSA object
2844 2) search for the msDS-isRODC attribute
2845 3) if not present then not a RODC
2846 4) if present and TRUE then is a RODC
2848 struct ldb_dn *config_dn;
2849 const char *attrs[] = { "msDS-isRODC", NULL };
2851 struct ldb_result *res;
2852 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2854 config_dn = ldb_get_config_basedn(sam_ctx);
2856 talloc_free(tmp_ctx);
2857 return ldb_operr(sam_ctx);
2860 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2861 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2863 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2865 talloc_free(tmp_ctx);
2869 if (ret != LDB_SUCCESS) {
2870 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2871 GUID_string(tmp_ctx, objectGUID)));
2873 talloc_free(tmp_ctx);
2877 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2878 *is_rodc = (ret == 1);
2880 talloc_free(tmp_ctx);
2886 see if we are a RODC
2888 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2890 const struct GUID *objectGUID;
2894 /* see if we have a cached copy */
2895 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2901 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2903 return ldb_operr(sam_ctx);
2906 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2907 if (ret != LDB_SUCCESS) {
2911 cached = talloc(sam_ctx, bool);
2912 if (cached == NULL) {
2913 return ldb_oom(sam_ctx);
2917 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2918 if (ret != LDB_SUCCESS) {
2919 talloc_free(cached);
2920 return ldb_operr(sam_ctx);
2926 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2928 TALLOC_CTX *tmp_ctx;
2931 tmp_ctx = talloc_new(ldb);
2932 if (tmp_ctx == NULL) {
2936 cached = talloc(tmp_ctx, bool);
2942 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2946 talloc_steal(ldb, cached);
2947 talloc_free(tmp_ctx);
2951 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2952 talloc_free(tmp_ctx);
2958 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2960 flags are DS_NTDS_OPTION_*
2962 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2964 TALLOC_CTX *tmp_ctx;
2965 const char *attrs[] = { "options", NULL };
2967 struct ldb_result *res;
2969 tmp_ctx = talloc_new(ldb);
2970 if (tmp_ctx == NULL) {
2974 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2975 if (ret != LDB_SUCCESS) {
2979 if (res->count != 1) {
2983 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
2985 talloc_free(tmp_ctx);
2990 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2991 talloc_free(tmp_ctx);
2992 return LDB_ERR_NO_SUCH_OBJECT;
2995 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
2997 const char *attrs[] = { "objectCategory", NULL };
2999 struct ldb_result *res;
3001 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3002 if (ret != LDB_SUCCESS) {
3006 if (res->count != 1) {
3010 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3013 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3018 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3019 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3021 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3023 char **tokens, *ret;
3026 tokens = str_list_make(mem_ctx, cn, " -_");
3030 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3031 tokens[0][0] = tolower(tokens[0][0]);
3032 for (i = 1; i < str_list_length((const char **)tokens); i++)
3033 tokens[i][0] = toupper(tokens[i][0]);
3035 ret = talloc_strdup(mem_ctx, tokens[0]);
3036 for (i = 1; i < str_list_length((const char **)tokens); i++)
3037 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3039 talloc_free(tokens);
3045 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3047 int dsdb_functional_level(struct ldb_context *ldb)
3049 int *domainFunctionality =
3050 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3051 if (!domainFunctionality) {
3052 /* this is expected during initial provision */
3053 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3054 return DS_DOMAIN_FUNCTION_2000;
3056 return *domainFunctionality;
3060 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3062 int dsdb_forest_functional_level(struct ldb_context *ldb)
3064 int *forestFunctionality =
3065 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3066 if (!forestFunctionality) {
3067 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3068 return DS_DOMAIN_FUNCTION_2000;
3070 return *forestFunctionality;
3074 set a GUID in an extended DN structure
3076 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3082 status = GUID_to_ndr_blob(guid, dn, &v);
3083 if (!NT_STATUS_IS_OK(status)) {
3084 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3087 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3093 return a GUID from a extended DN structure
3095 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3097 const struct ldb_val *v;
3099 v = ldb_dn_get_extended_component(dn, component_name);
3101 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3104 return GUID_from_ndr_blob(v, guid);
3108 return a uint64_t from a extended DN structure
3110 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3112 const struct ldb_val *v;
3115 v = ldb_dn_get_extended_component(dn, component_name);
3117 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3119 s = talloc_strndup(dn, (const char *)v->data, v->length);
3120 NT_STATUS_HAVE_NO_MEMORY(s);
3122 *val = strtoull(s, NULL, 0);
3125 return NT_STATUS_OK;
3129 return a NTTIME from a extended DN structure
3131 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3133 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3137 return a uint32_t from a extended DN structure
3139 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3141 const struct ldb_val *v;
3144 v = ldb_dn_get_extended_component(dn, component_name);
3146 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3149 s = talloc_strndup(dn, (const char *)v->data, v->length);
3150 NT_STATUS_HAVE_NO_MEMORY(s);
3152 *val = strtoul(s, NULL, 0);
3155 return NT_STATUS_OK;
3159 return a dom_sid from a extended DN structure
3161 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3163 const struct ldb_val *sid_blob;
3164 struct TALLOC_CTX *tmp_ctx;
3165 enum ndr_err_code ndr_err;
3167 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3169 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3172 tmp_ctx = talloc_new(NULL);
3174 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3175 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3176 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3177 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3178 talloc_free(tmp_ctx);
3182 talloc_free(tmp_ctx);
3183 return NT_STATUS_OK;
3188 return RMD_FLAGS directly from a ldb_dn
3189 returns 0 if not found
3191 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3193 const struct ldb_val *v;
3195 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3196 if (!v || v->length > sizeof(buf)-1) return 0;
3197 strncpy(buf, (const char *)v->data, v->length);
3199 return strtoul(buf, NULL, 10);
3203 return RMD_FLAGS directly from a ldb_val for a DN
3204 returns 0 if RMD_FLAGS is not found
3206 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3212 if (val->length < 13) {
3215 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3219 flags = strtoul(p+11, &end, 10);
3220 if (!end || *end != '>') {
3221 /* it must end in a > */
3228 return true if a ldb_val containing a DN in storage form is deleted
3230 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3232 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3236 return true if a ldb_val containing a DN in storage form is
3237 in the upgraded w2k3 linked attribute format
3239 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3241 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3245 return a DN for a wellknown GUID
3247 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3248 struct ldb_dn *nc_root, const char *wk_guid,
3249 struct ldb_dn **wkguid_dn)
3251 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3252 const char *attrs[] = { NULL };
3255 struct ldb_result *res;
3257 /* construct the magic WKGUID DN */
3258 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3259 wk_guid, ldb_dn_get_linearized(nc_root));
3261 talloc_free(tmp_ctx);
3262 return ldb_operr(samdb);
3265 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3266 DSDB_SEARCH_SHOW_DELETED |
3267 DSDB_SEARCH_SHOW_RECYCLED);
3268 if (ret != LDB_SUCCESS) {
3269 talloc_free(tmp_ctx);
3273 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3274 talloc_free(tmp_ctx);
3279 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3281 return ldb_dn_compare(*dn1, *dn2);
3285 find a NC root given a DN within the NC
3287 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3288 struct ldb_dn **nc_root)
3290 const char *root_attrs[] = { "namingContexts", NULL };
3291 TALLOC_CTX *tmp_ctx;
3293 struct ldb_message_element *el;
3294 struct ldb_result *root_res;
3296 struct ldb_dn **nc_dns;
3298 tmp_ctx = talloc_new(samdb);
3299 if (tmp_ctx == NULL) {
3300 return ldb_oom(samdb);
3303 ret = ldb_search(samdb, tmp_ctx, &root_res,
3304 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3305 if (ret != LDB_SUCCESS) {
3306 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3307 talloc_free(tmp_ctx);
3311 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3313 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3314 ldb_errstring(samdb)));
3315 talloc_free(tmp_ctx);
3316 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3319 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3321 talloc_free(tmp_ctx);
3322 return ldb_oom(samdb);
3325 for (i=0; i<el->num_values; i++) {
3326 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3327 if (nc_dns[i] == NULL) {
3328 talloc_free(tmp_ctx);
3329 return ldb_operr(samdb);
3333 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3335 for (i=0; i<el->num_values; i++) {
3336 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3337 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3338 talloc_free(tmp_ctx);
3343 talloc_free(tmp_ctx);
3344 return LDB_ERR_NO_SUCH_OBJECT;
3349 find the deleted objects DN for any object, by looking for the NC
3350 root, then looking up the wellknown GUID
3352 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3353 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3354 struct ldb_dn **do_dn)
3356 struct ldb_dn *nc_root;
3359 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3360 if (ret != LDB_SUCCESS) {
3364 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3365 talloc_free(nc_root);
3370 return the tombstoneLifetime, in days
3372 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3375 dn = ldb_get_config_basedn(ldb);
3377 return LDB_ERR_NO_SUCH_OBJECT;
3379 dn = ldb_dn_copy(ldb, dn);
3381 return ldb_operr(ldb);
3383 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3384 be a wellknown GUID for this */
3385 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3387 return ldb_operr(ldb);
3390 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3396 compare a ldb_val to a string case insensitively
3398 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3400 size_t len = strlen(s);
3402 if (len > v->length) return 1;
3403 ret = strncasecmp(s, (const char *)v->data, v->length);
3404 if (ret != 0) return ret;
3405 if (v->length > len && v->data[len] != 0) {
3413 load the UDV for a partition in v2 format
3414 The list is returned sorted, and with our local cursor added
3416 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3417 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3419 static const char *attrs[] = { "replUpToDateVector", NULL };
3420 struct ldb_result *r;
3421 const struct ldb_val *ouv_value;
3424 uint64_t highest_usn;
3425 const struct GUID *our_invocation_id;
3426 struct timeval now = timeval_current();
3428 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3429 if (ret != LDB_SUCCESS) {
3433 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3435 enum ndr_err_code ndr_err;
3436 struct replUpToDateVectorBlob ouv;
3438 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3439 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3440 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3442 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3444 if (ouv.version != 2) {
3445 /* we always store as version 2, and
3446 * replUpToDateVector is not replicated
3448 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3451 *count = ouv.ctr.ctr2.count;
3452 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3460 our_invocation_id = samdb_ntds_invocation_id(samdb);
3461 if (!our_invocation_id) {
3462 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3463 talloc_free(*cursors);
3464 return ldb_operr(samdb);
3467 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3468 if (ret != LDB_SUCCESS) {
3469 /* nothing to add - this can happen after a vampire */
3470 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3474 for (i=0; i<*count; i++) {
3475 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3476 (*cursors)[i].highest_usn = highest_usn;
3477 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3478 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3483 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3485 return ldb_oom(samdb);
3488 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3489 (*cursors)[*count].highest_usn = highest_usn;
3490 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3493 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3499 load the UDV for a partition in version 1 format
3500 The list is returned sorted, and with our local cursor added
3502 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3503 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3505 struct drsuapi_DsReplicaCursor2 *v2;
3509 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3510 if (ret != LDB_SUCCESS) {
3520 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3521 if (*cursors == NULL) {
3523 return ldb_oom(samdb);
3526 for (i=0; i<*count; i++) {
3527 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3528 (*cursors)[i].highest_usn = v2[i].highest_usn;
3535 add a set of controls to a ldb_request structure based on a set of
3536 flags. See util.h for a list of available flags
3538 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3541 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3542 struct ldb_search_options_control *options;
3543 /* Using the phantom root control allows us to search all partitions */
3544 options = talloc(req, struct ldb_search_options_control);
3545 if (options == NULL) {
3546 return LDB_ERR_OPERATIONS_ERROR;
3548 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3550 ret = ldb_request_add_control(req,
3551 LDB_CONTROL_SEARCH_OPTIONS_OID,
3553 if (ret != LDB_SUCCESS) {
3558 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3559 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3560 if (ret != LDB_SUCCESS) {
3565 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3566 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3567 if (ret != LDB_SUCCESS) {
3572 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3573 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3574 if (ret != LDB_SUCCESS) {
3579 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3580 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3581 if (!extended_ctrl) {
3582 return LDB_ERR_OPERATIONS_ERROR;
3584 extended_ctrl->type = 1;
3586 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3587 if (ret != LDB_SUCCESS) {
3592 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3593 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3594 if (ret != LDB_SUCCESS) {
3599 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3600 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3601 if (ret != LDB_SUCCESS) {
3606 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3607 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3608 if (ret != LDB_SUCCESS) {
3613 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3614 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3615 if (ret != LDB_SUCCESS) {
3620 if (dsdb_flags & DSDB_TREE_DELETE) {
3621 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3622 if (ret != LDB_SUCCESS) {
3631 an add with a set of controls
3633 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3634 uint32_t dsdb_flags)
3636 struct ldb_request *req;
3639 ret = ldb_build_add_req(&req, ldb, ldb,
3643 ldb_op_default_callback,
3646 if (ret != LDB_SUCCESS) return ret;
3648 ret = dsdb_request_add_controls(req, dsdb_flags);
3649 if (ret != LDB_SUCCESS) {
3654 ret = dsdb_autotransaction_request(ldb, req);
3661 a modify with a set of controls
3663 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3664 uint32_t dsdb_flags)
3666 struct ldb_request *req;
3669 ret = ldb_build_mod_req(&req, ldb, ldb,
3673 ldb_op_default_callback,
3676 if (ret != LDB_SUCCESS) return ret;
3678 ret = dsdb_request_add_controls(req, dsdb_flags);
3679 if (ret != LDB_SUCCESS) {
3684 ret = dsdb_autotransaction_request(ldb, req);
3691 like dsdb_modify() but set all the element flags to
3692 LDB_FLAG_MOD_REPLACE
3694 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3698 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3699 for (i=0;i<msg->num_elements;i++) {
3700 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3703 return dsdb_modify(ldb, msg, dsdb_flags);
3708 search for attrs on one DN, allowing for dsdb_flags controls
3710 int dsdb_search_dn(struct ldb_context *ldb,
3711 TALLOC_CTX *mem_ctx,
3712 struct ldb_result **_res,
3713 struct ldb_dn *basedn,
3714 const char * const *attrs,
3715 uint32_t dsdb_flags)
3718 struct ldb_request *req;
3719 struct ldb_result *res;
3721 res = talloc_zero(mem_ctx, struct ldb_result);
3723 return ldb_oom(ldb);
3726 ret = ldb_build_search_req(&req, ldb, res,
3733 ldb_search_default_callback,
3735 if (ret != LDB_SUCCESS) {
3740 ret = dsdb_request_add_controls(req, dsdb_flags);
3741 if (ret != LDB_SUCCESS) {
3746 ret = ldb_request(ldb, req);
3747 if (ret == LDB_SUCCESS) {
3748 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3752 if (ret != LDB_SUCCESS) {
3762 search for attrs on one DN, by the GUID of the DN, allowing for
3765 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3766 TALLOC_CTX *mem_ctx,
3767 struct ldb_result **_res,
3768 const struct GUID *guid,
3769 const char * const *attrs,
3770 uint32_t dsdb_flags)
3772 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3776 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3777 if (!ldb_dn_validate(dn)) {
3778 talloc_free(tmp_ctx);
3779 return LDB_ERR_INVALID_DN_SYNTAX;
3782 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3783 talloc_free(tmp_ctx);
3788 general search with dsdb_flags for controls
3790 int dsdb_search(struct ldb_context *ldb,
3791 TALLOC_CTX *mem_ctx,
3792 struct ldb_result **_res,
3793 struct ldb_dn *basedn,
3794 enum ldb_scope scope,
3795 const char * const *attrs,
3796 uint32_t dsdb_flags,
3797 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3800 struct ldb_request *req;
3801 struct ldb_result *res;
3803 char *expression = NULL;
3804 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3806 res = talloc_zero(tmp_ctx, struct ldb_result);
3808 talloc_free(tmp_ctx);
3809 return ldb_oom(ldb);
3813 va_start(ap, exp_fmt);
3814 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3818 talloc_free(tmp_ctx);
3819 return ldb_oom(ldb);
3823 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3830 ldb_search_default_callback,
3832 if (ret != LDB_SUCCESS) {
3833 talloc_free(tmp_ctx);
3837 ret = dsdb_request_add_controls(req, dsdb_flags);
3838 if (ret != LDB_SUCCESS) {
3839 talloc_free(tmp_ctx);
3840 ldb_reset_err_string(ldb);
3844 ret = ldb_request(ldb, req);
3845 if (ret == LDB_SUCCESS) {
3846 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3849 if (ret != LDB_SUCCESS) {
3850 talloc_free(tmp_ctx);
3854 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3855 if (res->count == 0) {
3856 talloc_free(tmp_ctx);
3857 ldb_reset_err_string(ldb);
3858 return LDB_ERR_NO_SUCH_OBJECT;
3860 if (res->count != 1) {
3861 talloc_free(tmp_ctx);
3862 ldb_reset_err_string(ldb);
3863 return LDB_ERR_CONSTRAINT_VIOLATION;
3867 *_res = talloc_steal(mem_ctx, res);
3868 talloc_free(tmp_ctx);
3875 general search with dsdb_flags for controls
3876 returns exactly 1 record or an error
3878 int dsdb_search_one(struct ldb_context *ldb,
3879 TALLOC_CTX *mem_ctx,
3880 struct ldb_message **msg,
3881 struct ldb_dn *basedn,
3882 enum ldb_scope scope,
3883 const char * const *attrs,
3884 uint32_t dsdb_flags,
3885 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3888 struct ldb_result *res;
3890 char *expression = NULL;
3891 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3893 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3895 res = talloc_zero(tmp_ctx, struct ldb_result);
3897 talloc_free(tmp_ctx);
3898 return ldb_oom(ldb);
3902 va_start(ap, exp_fmt);
3903 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3907 talloc_free(tmp_ctx);
3908 return ldb_oom(ldb);
3910 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3911 dsdb_flags, "%s", expression);
3913 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3917 if (ret != LDB_SUCCESS) {
3918 talloc_free(tmp_ctx);
3922 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3923 talloc_free(tmp_ctx);
3928 /* returns back the forest DNS name */
3929 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3931 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3932 ldb_get_root_basedn(ldb));
3935 if (forest_name == NULL) {
3939 p = strchr(forest_name, '/');
3948 validate that an DSA GUID belongs to the specified user sid.
3949 The user SID must be a domain controller account (either RODC or
3952 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3953 const struct GUID *dsa_guid,
3954 const struct dom_sid *sid)
3957 - find DN of record with the DSA GUID in the
3958 configuration partition (objectGUID)
3959 - remove "NTDS Settings" component from DN
3960 - do a base search on that DN for serverReference with
3962 - extract objectSid from resulting serverReference
3964 - check this sid matches the sid argument
3966 struct ldb_dn *config_dn;
3967 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3968 struct ldb_message *msg;
3969 const char *attrs1[] = { NULL };
3970 const char *attrs2[] = { "serverReference", NULL };
3972 struct ldb_dn *dn, *account_dn;
3973 struct dom_sid sid2;
3976 config_dn = ldb_get_config_basedn(ldb);
3978 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3979 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3980 if (ret != LDB_SUCCESS) {
3981 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3982 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3983 talloc_free(tmp_ctx);
3984 return ldb_operr(ldb);
3988 if (!ldb_dn_remove_child_components(dn, 1)) {
3989 talloc_free(tmp_ctx);
3990 return ldb_operr(ldb);
3993 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3994 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3995 "(objectClass=server)");
3996 if (ret != LDB_SUCCESS) {
3997 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3998 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3999 talloc_free(tmp_ctx);
4000 return ldb_operr(ldb);
4003 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4004 if (account_dn == NULL) {
4005 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4006 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4007 talloc_free(tmp_ctx);
4008 return ldb_operr(ldb);
4011 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4012 if (!NT_STATUS_IS_OK(status)) {
4013 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4014 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4015 talloc_free(tmp_ctx);
4016 return ldb_operr(ldb);
4019 if (!dom_sid_equal(sid, &sid2)) {
4020 /* someone is trying to spoof another account */
4021 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4022 GUID_string(tmp_ctx, dsa_guid),
4023 dom_sid_string(tmp_ctx, sid),
4024 dom_sid_string(tmp_ctx, &sid2)));
4025 talloc_free(tmp_ctx);
4026 return ldb_operr(ldb);
4029 talloc_free(tmp_ctx);
4033 static const char *secret_attributes[] = {
4036 "initialAuthIncoming",
4037 "initialAuthOutgoing",
4041 "supplementalCredentials",
4042 "trustAuthIncoming",
4043 "trustAuthOutgoing",
4049 check if the attribute belongs to the RODC filtered attribute set
4050 Note that attributes that are in the filtered attribute set are the
4051 ones that _are_ always sent to a RODC
4053 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4055 /* they never get secret attributes */
4056 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4060 /* they do get non-secret critical attributes */
4061 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4065 /* they do get non-secret attributes marked as being in the FAS */
4066 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4070 /* other attributes are denied */
4074 /* return fsmo role dn and role owner dn for a particular role*/
4075 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4076 struct ldb_context *ldb,
4078 struct ldb_dn **fsmo_role_dn,
4079 struct ldb_dn **role_owner_dn)
4083 case DREPL_NAMING_MASTER:
4084 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4085 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4086 if (ret != LDB_SUCCESS) {
4087 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4088 ldb_errstring(ldb)));
4089 talloc_free(tmp_ctx);
4090 return WERR_DS_DRA_INTERNAL_ERROR;
4093 case DREPL_INFRASTRUCTURE_MASTER:
4094 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4095 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4096 if (ret != LDB_SUCCESS) {
4097 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4098 ldb_errstring(ldb)));
4099 talloc_free(tmp_ctx);
4100 return WERR_DS_DRA_INTERNAL_ERROR;
4103 case DREPL_RID_MASTER:
4104 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4105 if (ret != LDB_SUCCESS) {
4106 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4107 talloc_free(tmp_ctx);
4108 return WERR_DS_DRA_INTERNAL_ERROR;
4111 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4112 if (ret != LDB_SUCCESS) {
4113 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4114 ldb_errstring(ldb)));
4115 talloc_free(tmp_ctx);
4116 return WERR_DS_DRA_INTERNAL_ERROR;
4119 case DREPL_SCHEMA_MASTER:
4120 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4121 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4122 if (ret != LDB_SUCCESS) {
4123 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4124 ldb_errstring(ldb)));
4125 talloc_free(tmp_ctx);
4126 return WERR_DS_DRA_INTERNAL_ERROR;
4129 case DREPL_PDC_MASTER:
4130 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4131 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4132 if (ret != LDB_SUCCESS) {
4133 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4134 ldb_errstring(ldb)));
4135 talloc_free(tmp_ctx);
4136 return WERR_DS_DRA_INTERNAL_ERROR;
4140 return WERR_DS_DRA_INTERNAL_ERROR;
4145 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4146 TALLOC_CTX *mem_ctx,
4147 struct ldb_dn *server_dn)
4150 struct ldb_result *res = NULL;
4151 const char * const attrs[] = { "dNSHostName", NULL};
4153 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4157 if (ldb_ret != LDB_SUCCESS) {
4158 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4159 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4163 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4167 returns true if an attribute is in the filter,
4168 false otherwise, provided that attribute value is provided with the expression
4170 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4174 switch (tree->operation) {
4177 for (i=0;i<tree->u.list.num_elements;i++) {
4178 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4184 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4185 case LDB_OP_EQUALITY:
4186 case LDB_OP_GREATER:
4189 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4193 case LDB_OP_SUBSTRING:
4194 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4198 case LDB_OP_PRESENT:
4199 /* (attrname=*) is not filtered out */
4201 case LDB_OP_EXTENDED:
4202 if (tree->u.extended.attr &&
4203 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4211 bool is_attr_in_list(const char * const * attrs, const char *attr)
4215 for (i = 0; attrs[i]; i++) {
4216 if (ldb_attr_cmp(attrs[i], attr) == 0)