2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "librpc/gen_ndr/irpc.h"
48 search the sam for the specified attributes in a specific domain, filter on
49 objectSid being in domain_sid.
51 int samdb_search_domain(struct ldb_context *sam_ldb,
53 struct ldb_dn *basedn,
54 struct ldb_message ***res,
55 const char * const *attrs,
56 const struct dom_sid *domain_sid,
57 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
63 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
64 res, attrs, format, ap);
70 struct dom_sid *entry_sid;
72 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
74 if ((entry_sid == NULL) ||
75 (!dom_sid_in_domain(domain_sid, entry_sid))) {
76 /* Delete that entry from the result set */
77 (*res)[i] = (*res)[count-1];
79 talloc_free(entry_sid);
82 talloc_free(entry_sid);
90 search the sam for a single string attribute in exactly 1 record
92 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
94 struct ldb_dn *basedn,
95 const char *attr_name,
96 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
99 const char *attrs[2] = { NULL, NULL };
100 struct ldb_message **res = NULL;
102 attrs[0] = attr_name;
104 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
106 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
107 attr_name, format, count));
114 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
118 search the sam for a single string attribute in exactly 1 record
120 const char *samdb_search_string(struct ldb_context *sam_ldb,
122 struct ldb_dn *basedn,
123 const char *attr_name,
124 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
129 va_start(ap, format);
130 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
136 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
138 struct ldb_dn *basedn,
139 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
143 struct ldb_message **res = NULL;
146 va_start(ap, format);
147 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
150 if (count != 1) return NULL;
152 ret = talloc_steal(mem_ctx, res[0]->dn);
159 search the sam for a dom_sid attribute in exactly 1 record
161 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
163 struct ldb_dn *basedn,
164 const char *attr_name,
165 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
169 struct ldb_message **res;
170 const char *attrs[2] = { NULL, NULL };
173 attrs[0] = attr_name;
175 va_start(ap, format);
176 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
179 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
180 attr_name, format, count));
186 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
192 return the count of the number of records in the sam matching the query
194 int samdb_search_count(struct ldb_context *sam_ldb,
195 struct ldb_dn *basedn,
196 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
199 struct ldb_message **res;
200 const char *attrs[] = { NULL };
202 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
204 va_start(ap, format);
205 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
207 talloc_free(tmp_ctx);
214 search the sam for a single integer attribute in exactly 1 record
216 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
218 unsigned int default_value,
219 struct ldb_dn *basedn,
220 const char *attr_name,
221 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
225 struct ldb_message **res;
226 const char *attrs[2] = { NULL, NULL };
228 attrs[0] = attr_name;
230 va_start(ap, format);
231 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
235 return default_value;
238 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
242 search the sam for a single signed 64 bit integer attribute in exactly 1 record
244 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
246 int64_t default_value,
247 struct ldb_dn *basedn,
248 const char *attr_name,
249 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
253 struct ldb_message **res;
254 const char *attrs[2] = { NULL, NULL };
256 attrs[0] = attr_name;
258 va_start(ap, format);
259 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
263 return default_value;
266 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
270 search the sam for multipe records each giving a single string attribute
271 return the number of matches, or -1 on error
273 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
275 struct ldb_dn *basedn,
277 const char *attr_name,
278 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
282 const char *attrs[2] = { NULL, NULL };
283 struct ldb_message **res = NULL;
285 attrs[0] = attr_name;
287 va_start(ap, format);
288 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
295 /* make sure its single valued */
296 for (i=0;i<count;i++) {
297 if (res[i]->num_elements != 1) {
298 DEBUG(1,("samdb: search for %s %s not single valued\n",
305 *strs = talloc_array(mem_ctx, const char *, count+1);
311 for (i=0;i<count;i++) {
312 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
314 (*strs)[count] = NULL;
319 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
320 const char *attr, struct ldb_dn *default_value)
322 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
324 return default_value;
330 pull a rid from a objectSid in a result set.
332 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
333 const char *attr, uint32_t default_value)
338 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
340 return default_value;
342 rid = sid->sub_auths[sid->num_auths-1];
348 pull a dom_sid structure from a objectSid in a result set.
350 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
353 const struct ldb_val *v;
355 enum ndr_err_code ndr_err;
356 v = ldb_msg_find_ldb_val(msg, attr);
360 sid = talloc(mem_ctx, struct dom_sid);
364 ndr_err = ndr_pull_struct_blob(v, sid, sid,
365 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 pull a guid structure from a objectGUID in a result set.
376 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
378 const struct ldb_val *v;
382 v = ldb_msg_find_ldb_val(msg, attr);
383 if (!v) return GUID_zero();
385 status = GUID_from_ndr_blob(v, &guid);
386 if (!NT_STATUS_IS_OK(status)) {
394 pull a sid prefix from a objectSid in a result set.
395 this is used to find the domain sid for a user
397 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
400 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
401 if (!sid || sid->num_auths < 1) return NULL;
407 pull a NTTIME in a result set.
409 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
410 NTTIME default_value)
412 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
416 * Windows stores 0 for lastLogoff.
417 * But when a MS DC return the lastLogoff (as Logoff Time)
418 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
419 * cause windows 2008 and newer version to fail for SMB requests
421 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
423 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
426 ret = 0x7FFFFFFFFFFFFFFFULL;
432 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
433 * indicate an account doesn't expire.
435 * When Windows initially creates an account, it sets
436 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
437 * when changing from an account having a specific expiration date to
438 * that account never expiring, it sets accountExpires = 0.
440 * Consolidate that logic here to allow clearer logic for account expiry in
441 * the rest of the code.
443 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
445 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
449 ret = 0x7FFFFFFFFFFFFFFFULL;
455 construct the allow_password_change field from the PwdLastSet attribute and the
456 domain password settings
458 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
460 struct ldb_dn *domain_dn,
461 struct ldb_message *msg,
464 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
467 if (attr_time == 0) {
471 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
473 /* yes, this is a -= not a += as minPwdAge is stored as the negative
474 of the number of 100-nano-seconds */
475 attr_time -= minPwdAge;
481 construct the force_password_change field from the PwdLastSet
482 attribute, the userAccountControl and the domain password settings
484 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
486 struct ldb_dn *domain_dn,
487 struct ldb_message *msg)
489 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
490 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
491 "userAccountControl",
495 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
496 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
497 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
498 return 0x7FFFFFFFFFFFFFFFULL;
501 if (attr_time == 0) {
504 if (attr_time == -1) {
505 return 0x7FFFFFFFFFFFFFFFULL;
508 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
510 if (maxPwdAge == 0) {
511 return 0x7FFFFFFFFFFFFFFFULL;
513 attr_time -= maxPwdAge;
520 pull a samr_Password structutre from a result set.
522 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
524 struct samr_Password *hash = NULL;
525 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
526 if (val && (val->length >= sizeof(hash->hash))) {
527 hash = talloc(mem_ctx, struct samr_Password);
528 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
534 pull an array of samr_Password structures from a result set.
536 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
537 const char *attr, struct samr_Password **hashes)
539 unsigned int count, i;
540 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
546 count = val->length / 16;
551 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
556 for (i=0;i<count;i++) {
557 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
563 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
564 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
566 struct samr_Password *lmPwdHash, *ntPwdHash;
569 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
572 } else if (num_nt > 1) {
573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
575 *nt_pwd = &ntPwdHash[0];
579 /* Ensure that if we have turned off LM
580 * authentication, that we never use the LM hash, even
582 if (lpcfg_lanman_auth(lp_ctx)) {
584 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
587 } else if (num_lm > 1) {
588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590 *lm_pwd = &lmPwdHash[0];
600 pull a samr_LogonHours structutre from a result set.
602 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
604 struct samr_LogonHours hours;
605 size_t units_per_week = 168;
606 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
611 units_per_week = val->length * 8;
614 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
618 hours.units_per_week = units_per_week;
619 memset(hours.bits, 0xFF, units_per_week/8);
621 memcpy(hours.bits, val->data, val->length);
628 pull a set of account_flags from a result set.
630 This requires that the attributes:
635 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
636 struct ldb_message *msg, struct ldb_dn *domain_dn)
638 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
639 uint32_t acct_flags = ds_uf2acb(userAccountControl);
640 NTTIME must_change_time;
643 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
646 /* Test account expire time */
647 unix_to_nt_time(&now, time(NULL));
648 /* check for expired password */
649 if (must_change_time < now) {
650 acct_flags |= ACB_PW_EXPIRED;
655 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
656 struct ldb_message *msg,
659 struct lsa_BinaryString s;
660 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
668 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
672 s.length = s.size = val->length;
673 memcpy(s.array, val->data, val->length);
678 /* Find an attribute, with a particular value */
680 /* The current callers of this function expect a very specific
681 * behaviour: In particular, objectClass subclass equivilance is not
682 * wanted. This means that we should not lookup the schema for the
683 * comparison function */
684 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
685 const struct ldb_message *msg,
686 const char *name, const char *value)
689 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
695 for (i=0;i<el->num_values;i++) {
696 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
705 * This is intended for use by the "password hash" module since there
706 * password changes can be specified through one message element with the
707 * new password (to set) and another one with the old password (to unset).
709 * The first which sets a password (new value) can have flags
710 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
711 * for entries). The latter (old value) has always specified
712 * LDB_FLAG_MOD_DELETE.
714 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
715 * doesn't contain only one value (this is the Windows Server behaviour)
716 * otherwise LDB_SUCCESS.
718 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
720 const struct ldb_val **new_val,
721 const struct ldb_val **old_val)
732 for (i = 0; i < msg->num_elements; i++) {
733 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
734 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
735 *old_val = &msg->elements[i].values[0];
737 *new_val = &msg->elements[i].values[0];
745 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
747 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
748 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
753 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
755 struct ldb_message_element *el;
757 el = ldb_msg_find_element(msg, name);
762 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
768 add a string element to a message
770 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
771 const char *attr_name, const char *str)
773 const char *s = talloc_strdup(mem_ctx, str);
775 return ldb_oom(sam_ldb);
777 return ldb_msg_add_string(msg, attr_name, s);
781 add a dom_sid element to a message
783 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, struct dom_sid *sid)
787 enum ndr_err_code ndr_err;
789 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
791 (ndr_push_flags_fn_t)ndr_push_dom_sid);
792 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
793 return ldb_operr(sam_ldb);
795 return ldb_msg_add_value(msg, attr_name, &v, NULL);
800 add a delete element operation to a message
802 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
803 const char *attr_name)
805 /* we use an empty replace rather than a delete, as it allows for
806 dsdb_replace() to be used everywhere */
807 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
811 add an add attribute value to a message or enhance an existing attribute
812 which has the same name and the add flag set.
814 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
815 struct ldb_message *msg, const char *attr_name,
818 struct ldb_message_element *el;
819 struct ldb_val val, *vals;
825 v = talloc_strdup(mem_ctx, value);
827 return ldb_oom(sam_ldb);
830 val.data = (uint8_t *) v;
831 val.length = strlen(v);
833 if (val.length == 0) {
834 /* allow empty strings as non-existent attributes */
838 for (i = 0; i < msg->num_elements; i++) {
839 el = &msg->elements[i];
840 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
841 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
847 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
849 if (ret != LDB_SUCCESS) {
854 vals = talloc_realloc(msg, el->values, struct ldb_val,
857 return ldb_oom(sam_ldb);
860 el->values[el->num_values] = val;
867 add a delete attribute value to a message or enhance an existing attribute
868 which has the same name and the delete flag set.
870 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
871 struct ldb_message *msg, const char *attr_name,
874 struct ldb_message_element *el;
875 struct ldb_val val, *vals;
881 v = talloc_strdup(mem_ctx, value);
883 return ldb_oom(sam_ldb);
886 val.data = (uint8_t *) v;
887 val.length = strlen(v);
889 if (val.length == 0) {
890 /* allow empty strings as non-existent attributes */
894 for (i = 0; i < msg->num_elements; i++) {
895 el = &msg->elements[i];
896 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
897 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
903 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
905 if (ret != LDB_SUCCESS) {
910 vals = talloc_realloc(msg, el->values, struct ldb_val,
913 return ldb_oom(sam_ldb);
916 el->values[el->num_values] = val;
923 add a int element to a message
925 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
926 const char *attr_name, int v)
928 const char *s = talloc_asprintf(mem_ctx, "%d", v);
930 return ldb_oom(sam_ldb);
932 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
936 add a unsigned int element to a message
938 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939 const char *attr_name, unsigned int v)
941 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
945 add a (signed) int64_t element to a message
947 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948 const char *attr_name, int64_t v)
950 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
952 return ldb_oom(sam_ldb);
954 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
958 add a uint64_t element to a message
960 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961 const char *attr_name, uint64_t v)
963 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
967 add a samr_Password element to a message
969 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970 const char *attr_name, const struct samr_Password *hash)
973 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
975 return ldb_oom(sam_ldb);
978 return ldb_msg_add_value(msg, attr_name, &val, NULL);
982 add a samr_Password array to a message
984 int samdb_msg_add_hashes(struct ldb_context *ldb,
985 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
986 const char *attr_name, struct samr_Password *hashes,
991 val.data = talloc_array_size(mem_ctx, 16, count);
992 val.length = count*16;
996 for (i=0;i<count;i++) {
997 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
999 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1003 add a acct_flags element to a message
1005 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1006 const char *attr_name, uint32_t v)
1008 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1012 add a logon_hours element to a message
1014 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1015 const char *attr_name, struct samr_LogonHours *hours)
1018 val.length = hours->units_per_week / 8;
1019 val.data = hours->bits;
1020 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1024 add a parameters element to a message
1026 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1027 const char *attr_name, struct lsa_BinaryString *parameters)
1030 val.length = parameters->length;
1031 val.data = (uint8_t *)parameters->array;
1032 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1036 sets a general value element to a message
1038 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1039 const char *attr_name, const struct ldb_val *val)
1041 struct ldb_message_element *el;
1043 el = ldb_msg_find_element(msg, attr_name);
1047 return ldb_msg_add_value(msg, attr_name, val, NULL);
1051 set a string element in a message
1053 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1054 const char *attr_name, const char *str)
1056 struct ldb_message_element *el;
1058 el = ldb_msg_find_element(msg, attr_name);
1062 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1066 * sets a signed integer in a message
1068 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1069 struct ldb_message *msg, const char *attr_name, int v)
1071 struct ldb_message_element *el;
1073 el = ldb_msg_find_element(msg, attr_name);
1077 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1081 * sets an unsigned integer in a message
1083 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1084 struct ldb_message *msg, const char *attr_name,
1087 struct ldb_message_element *el;
1089 el = ldb_msg_find_element(msg, attr_name);
1093 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1097 * Handle ldb_request in transaction
1099 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1100 struct ldb_request *req)
1104 ret = ldb_transaction_start(sam_ldb);
1105 if (ret != LDB_SUCCESS) {
1109 ret = ldb_request(sam_ldb, req);
1110 if (ret == LDB_SUCCESS) {
1111 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1114 if (ret == LDB_SUCCESS) {
1115 return ldb_transaction_commit(sam_ldb);
1117 ldb_transaction_cancel(sam_ldb);
1123 return a default security descriptor
1125 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1127 struct security_descriptor *sd;
1129 sd = security_descriptor_initialise(mem_ctx);
1134 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1136 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1137 struct ldb_dn *aggregate_dn;
1142 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1143 if (!aggregate_dn) {
1146 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1149 return aggregate_dn;
1152 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1154 struct ldb_dn *new_dn;
1156 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1157 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1158 talloc_free(new_dn);
1164 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1166 struct ldb_dn *new_dn;
1168 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1169 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1170 talloc_free(new_dn);
1176 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1178 struct ldb_dn *new_dn;
1180 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1181 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1182 talloc_free(new_dn);
1189 work out the domain sid for the current open ldb
1191 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1193 TALLOC_CTX *tmp_ctx;
1194 const struct dom_sid *domain_sid;
1195 const char *attrs[] = {
1199 struct ldb_result *res;
1202 /* see if we have a cached copy */
1203 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1208 tmp_ctx = talloc_new(ldb);
1209 if (tmp_ctx == NULL) {
1213 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1215 if (ret != LDB_SUCCESS) {
1219 if (res->count != 1) {
1223 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1224 if (domain_sid == NULL) {
1228 /* cache the domain_sid in the ldb */
1229 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1233 talloc_steal(ldb, domain_sid);
1234 talloc_free(tmp_ctx);
1239 talloc_free(tmp_ctx);
1244 get domain sid from cache
1246 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1248 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1251 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1253 TALLOC_CTX *tmp_ctx;
1254 struct dom_sid *dom_sid_new;
1255 struct dom_sid *dom_sid_old;
1257 /* see if we have a cached copy */
1258 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1259 "cache.domain_sid"), struct dom_sid);
1261 tmp_ctx = talloc_new(ldb);
1262 if (tmp_ctx == NULL) {
1266 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1271 /* cache the domain_sid in the ldb */
1272 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1276 talloc_steal(ldb, dom_sid_new);
1277 talloc_free(tmp_ctx);
1278 talloc_free(dom_sid_old);
1283 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1284 talloc_free(tmp_ctx);
1288 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1290 TALLOC_CTX *tmp_ctx;
1291 struct ldb_dn *ntds_settings_dn_new;
1292 struct ldb_dn *ntds_settings_dn_old;
1294 /* see if we have a cached copy */
1295 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1296 "cache.ntds_settings_dn"), struct ldb_dn);
1298 tmp_ctx = talloc_new(ldb);
1299 if (tmp_ctx == NULL) {
1303 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1304 if (!ntds_settings_dn_new) {
1308 /* cache the domain_sid in the ldb */
1309 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1313 talloc_steal(ldb, ntds_settings_dn_new);
1314 talloc_free(tmp_ctx);
1315 talloc_free(ntds_settings_dn_old);
1320 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1321 talloc_free(tmp_ctx);
1325 /* Obtain the short name of the flexible single master operator
1326 * (FSMO), such as the PDC Emulator */
1327 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1330 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1331 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1332 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1333 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1335 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1336 /* Ensure this matches the format. This gives us a
1337 * bit more confidence that a 'cn' value will be a
1342 return (char *)val->data;
1348 work out the ntds settings dn for the current open ldb
1350 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1352 TALLOC_CTX *tmp_ctx;
1353 const char *root_attrs[] = { "dsServiceName", NULL };
1355 struct ldb_result *root_res;
1356 struct ldb_dn *settings_dn;
1358 /* see if we have a cached copy */
1359 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1364 tmp_ctx = talloc_new(ldb);
1365 if (tmp_ctx == NULL) {
1369 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1371 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1372 ldb_errstring(ldb)));
1376 if (root_res->count != 1) {
1380 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1382 /* cache the domain_sid in the ldb */
1383 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1387 talloc_steal(ldb, settings_dn);
1388 talloc_free(tmp_ctx);
1393 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1394 talloc_free(tmp_ctx);
1399 work out the ntds settings invocationId for the current open ldb
1401 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1403 TALLOC_CTX *tmp_ctx;
1404 const char *attrs[] = { "invocationId", NULL };
1406 struct ldb_result *res;
1407 struct GUID *invocation_id;
1409 /* see if we have a cached copy */
1410 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1411 if (invocation_id) {
1412 return invocation_id;
1415 tmp_ctx = talloc_new(ldb);
1416 if (tmp_ctx == NULL) {
1420 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1425 if (res->count != 1) {
1429 invocation_id = talloc(tmp_ctx, struct GUID);
1430 if (!invocation_id) {
1434 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1436 /* cache the domain_sid in the ldb */
1437 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1441 talloc_steal(ldb, invocation_id);
1442 talloc_free(tmp_ctx);
1444 return invocation_id;
1447 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1448 talloc_free(tmp_ctx);
1452 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1454 TALLOC_CTX *tmp_ctx;
1455 struct GUID *invocation_id_new;
1456 struct GUID *invocation_id_old;
1458 /* see if we have a cached copy */
1459 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1460 "cache.invocation_id");
1462 tmp_ctx = talloc_new(ldb);
1463 if (tmp_ctx == NULL) {
1467 invocation_id_new = talloc(tmp_ctx, struct GUID);
1468 if (!invocation_id_new) {
1472 *invocation_id_new = *invocation_id_in;
1474 /* cache the domain_sid in the ldb */
1475 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1479 talloc_steal(ldb, invocation_id_new);
1480 talloc_free(tmp_ctx);
1481 talloc_free(invocation_id_old);
1486 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1487 talloc_free(tmp_ctx);
1492 work out the ntds settings objectGUID for the current open ldb
1494 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1496 TALLOC_CTX *tmp_ctx;
1497 const char *attrs[] = { "objectGUID", NULL };
1499 struct ldb_result *res;
1500 struct GUID *ntds_guid;
1502 /* see if we have a cached copy */
1503 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1508 tmp_ctx = talloc_new(ldb);
1509 if (tmp_ctx == NULL) {
1513 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1518 if (res->count != 1) {
1522 ntds_guid = talloc(tmp_ctx, struct GUID);
1527 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1529 /* cache the domain_sid in the ldb */
1530 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1534 talloc_steal(ldb, ntds_guid);
1535 talloc_free(tmp_ctx);
1540 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1541 talloc_free(tmp_ctx);
1545 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1547 TALLOC_CTX *tmp_ctx;
1548 struct GUID *ntds_guid_new;
1549 struct GUID *ntds_guid_old;
1551 /* see if we have a cached copy */
1552 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1554 tmp_ctx = talloc_new(ldb);
1555 if (tmp_ctx == NULL) {
1559 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1560 if (!ntds_guid_new) {
1564 *ntds_guid_new = *ntds_guid_in;
1566 /* cache the domain_sid in the ldb */
1567 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1571 talloc_steal(ldb, ntds_guid_new);
1572 talloc_free(tmp_ctx);
1573 talloc_free(ntds_guid_old);
1578 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1579 talloc_free(tmp_ctx);
1584 work out the server dn for the current open ldb
1586 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1588 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 struct ldb_dn *server_dn;
1597 struct ldb_dn *servers_dn;
1598 struct ldb_dn *server_site_dn;
1600 /* TODO: there must be a saner way to do this!! */
1601 server_dn = samdb_server_dn(ldb, mem_ctx);
1602 if (!server_dn) return NULL;
1604 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1605 talloc_free(server_dn);
1606 if (!servers_dn) return NULL;
1608 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1609 talloc_free(servers_dn);
1611 return server_site_dn;
1615 find the site name from a computers DN record
1617 int samdb_find_site_for_computer(struct ldb_context *ldb,
1618 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1619 const char **site_name)
1623 const struct ldb_val *rdn_val;
1627 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1628 if (ret != LDB_SUCCESS) {
1632 if (!ldb_dn_remove_child_components(dn, 2)) {
1634 return LDB_ERR_INVALID_DN_SYNTAX;
1636 rdn_val = ldb_dn_get_rdn_val(dn);
1637 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1640 return LDB_ERR_OPERATIONS_ERROR;
1646 find the NTDS GUID from a computers DN record
1648 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1649 struct GUID *ntds_guid)
1654 *ntds_guid = GUID_zero();
1656 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1657 if (ret != LDB_SUCCESS) {
1661 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1663 return LDB_ERR_OPERATIONS_ERROR;
1666 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1672 find a 'reference' DN that points at another object
1673 (eg. serverReference, rIDManagerReference etc)
1675 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1676 const char *attribute, struct ldb_dn **dn)
1678 const char *attrs[2];
1679 struct ldb_result *res;
1682 attrs[0] = attribute;
1685 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1686 if (ret != LDB_SUCCESS) {
1690 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1692 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1693 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1694 ldb_dn_get_linearized(base));
1696 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1697 ldb_dn_get_linearized(base));
1700 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1708 find our machine account via the serverReference attribute in the
1711 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1713 struct ldb_dn *server_dn;
1716 server_dn = samdb_server_dn(ldb, mem_ctx);
1717 if (server_dn == NULL) {
1718 return LDB_ERR_NO_SUCH_OBJECT;
1721 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1722 talloc_free(server_dn);
1728 find the RID Manager$ DN via the rIDManagerReference attribute in the
1731 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1733 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1734 "rIDManagerReference", dn);
1738 find the RID Set DN via the rIDSetReferences attribute in our
1741 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1743 struct ldb_dn *server_ref_dn;
1746 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1747 if (ret != LDB_SUCCESS) {
1750 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1751 talloc_free(server_ref_dn);
1755 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1757 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1764 return (const char *) val->data;
1768 * Finds the client site by using the client's IP address.
1769 * The "subnet_name" returns the name of the subnet if parameter != NULL
1771 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1772 const char *ip_address, char **subnet_name)
1774 const char *attrs[] = { "cn", "siteObject", NULL };
1775 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1776 struct ldb_result *res;
1777 const struct ldb_val *val;
1778 const char *site_name = NULL, *l_subnet_name = NULL;
1779 const char *allow_list[2] = { NULL, NULL };
1780 unsigned int i, count;
1784 * if we don't have a client ip e.g. ncalrpc
1785 * the server site is the client site
1787 if (ip_address == NULL) {
1788 return samdb_server_site_name(ldb, mem_ctx);
1791 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1792 if (sites_container_dn == NULL) {
1796 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1797 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1798 talloc_free(sites_container_dn);
1799 talloc_free(subnets_dn);
1803 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1805 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1807 } else if (ret != LDB_SUCCESS) {
1808 talloc_free(sites_container_dn);
1809 talloc_free(subnets_dn);
1815 for (i = 0; i < count; i++) {
1816 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1819 allow_list[0] = l_subnet_name;
1821 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1822 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1825 if (sites_dn == NULL) {
1826 /* No reference, maybe another subnet matches */
1830 /* "val" cannot be NULL here since "sites_dn" != NULL */
1831 val = ldb_dn_get_rdn_val(sites_dn);
1832 site_name = talloc_strdup(mem_ctx,
1833 (const char *) val->data);
1835 talloc_free(sites_dn);
1841 if (site_name == NULL) {
1842 /* This is the Windows Server fallback rule: when no subnet
1843 * exists and we have only one site available then use it (it
1844 * is for sure the same as our server site). If more sites do
1845 * exist then we don't know which one to use and set the site
1847 cnt = samdb_search_count(ldb, sites_container_dn,
1848 "(objectClass=site)");
1850 site_name = samdb_server_site_name(ldb, mem_ctx);
1852 site_name = talloc_strdup(mem_ctx, "");
1854 l_subnet_name = NULL;
1857 if (subnet_name != NULL) {
1858 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1861 talloc_free(sites_container_dn);
1862 talloc_free(subnets_dn);
1869 work out if we are the PDC for the domain of the current open ldb
1871 bool samdb_is_pdc(struct ldb_context *ldb)
1873 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1875 struct ldb_result *dom_res;
1876 TALLOC_CTX *tmp_ctx;
1880 tmp_ctx = talloc_new(ldb);
1881 if (tmp_ctx == NULL) {
1882 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1886 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1887 if (ret != LDB_SUCCESS) {
1888 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1889 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1890 ldb_errstring(ldb)));
1893 if (dom_res->count != 1) {
1897 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1899 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1905 talloc_free(tmp_ctx);
1910 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1911 talloc_free(tmp_ctx);
1916 work out if we are a Global Catalog server for the domain of the current open ldb
1918 bool samdb_is_gc(struct ldb_context *ldb)
1920 const char *attrs[] = { "options", NULL };
1922 struct ldb_result *res;
1923 TALLOC_CTX *tmp_ctx;
1925 tmp_ctx = talloc_new(ldb);
1926 if (tmp_ctx == NULL) {
1927 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1931 /* Query cn=ntds settings,.... */
1932 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1933 if (ret != LDB_SUCCESS) {
1934 talloc_free(tmp_ctx);
1937 if (res->count != 1) {
1938 talloc_free(tmp_ctx);
1942 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1943 talloc_free(tmp_ctx);
1945 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1946 if (options & 0x000000001) {
1952 /* Find a domain object in the parents of a particular DN. */
1953 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1954 struct ldb_dn **parent_dn, const char **errstring)
1956 TALLOC_CTX *local_ctx;
1957 struct ldb_dn *sdn = dn;
1958 struct ldb_result *res = NULL;
1959 int ret = LDB_SUCCESS;
1960 const char *attrs[] = { NULL };
1962 local_ctx = talloc_new(mem_ctx);
1963 if (local_ctx == NULL) return ldb_oom(ldb);
1965 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1966 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1967 "(|(objectClass=domain)(objectClass=builtinDomain))");
1968 if (ret == LDB_SUCCESS) {
1969 if (res->count == 1) {
1977 if (ret != LDB_SUCCESS) {
1978 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1979 ldb_dn_get_linearized(dn),
1980 ldb_dn_get_linearized(sdn),
1981 ldb_errstring(ldb));
1982 talloc_free(local_ctx);
1985 if (res->count != 1) {
1986 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1987 ldb_dn_get_linearized(dn));
1988 DEBUG(0,(__location__ ": %s\n", *errstring));
1989 talloc_free(local_ctx);
1990 return LDB_ERR_CONSTRAINT_VIOLATION;
1993 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1994 talloc_free(local_ctx);
2000 * Performs checks on a user password (plaintext UNIX format - attribute
2001 * "password"). The remaining parameters have to be extracted from the domain
2004 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2006 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2007 const uint32_t pwdProperties,
2008 const uint32_t minPwdLength)
2010 /* checks if the "minPwdLength" property is satisfied */
2011 if (minPwdLength > password->length)
2012 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2014 /* checks the password complexity */
2015 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2016 && (password->data != NULL)
2017 && (!check_password_quality((const char *) password->data)))
2018 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2020 return SAMR_VALIDATION_STATUS_SUCCESS;
2024 * Callback for "samdb_set_password" password change
2026 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2031 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2034 if (ares->error != LDB_SUCCESS) {
2036 req->context = talloc_steal(req,
2037 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2039 return ldb_request_done(req, ret);
2042 if (ares->type != LDB_REPLY_DONE) {
2044 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2047 req->context = talloc_steal(req,
2048 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2050 return ldb_request_done(req, LDB_SUCCESS);
2054 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2055 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2056 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2057 * user change or not. The "rejectReason" gives some more informations if the
2060 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2061 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2063 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2064 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2065 const DATA_BLOB *new_password,
2066 const struct samr_Password *lmNewHash,
2067 const struct samr_Password *ntNewHash,
2068 const struct samr_Password *lmOldHash,
2069 const struct samr_Password *ntOldHash,
2070 enum samPwdChangeReason *reject_reason,
2071 struct samr_DomInfo1 **_dominfo)
2073 struct ldb_message *msg;
2074 struct ldb_message_element *el;
2075 struct ldb_request *req;
2076 struct dsdb_control_password_change_status *pwd_stat = NULL;
2078 NTSTATUS status = NT_STATUS_OK;
2080 #define CHECK_RET(x) \
2081 if (x != LDB_SUCCESS) { \
2083 return NT_STATUS_NO_MEMORY; \
2086 msg = ldb_msg_new(mem_ctx);
2088 return NT_STATUS_NO_MEMORY;
2091 if ((new_password != NULL)
2092 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2093 /* we have the password as plaintext UTF16 */
2094 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2095 new_password, NULL));
2096 el = ldb_msg_find_element(msg, "clearTextPassword");
2097 el->flags = LDB_FLAG_MOD_REPLACE;
2098 } else if ((new_password == NULL)
2099 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2100 /* we have a password as LM and/or NT hash */
2101 if (lmNewHash != NULL) {
2102 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2103 "dBCSPwd", lmNewHash));
2104 el = ldb_msg_find_element(msg, "dBCSPwd");
2105 el->flags = LDB_FLAG_MOD_REPLACE;
2107 if (ntNewHash != NULL) {
2108 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2109 "unicodePwd", ntNewHash));
2110 el = ldb_msg_find_element(msg, "unicodePwd");
2111 el->flags = LDB_FLAG_MOD_REPLACE;
2114 /* the password wasn't specified correctly */
2116 return NT_STATUS_INVALID_PARAMETER;
2119 /* build modify request */
2120 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2121 samdb_set_password_callback, NULL);
2122 if (ret != LDB_SUCCESS) {
2124 return NT_STATUS_NO_MEMORY;
2127 /* A password change operation */
2128 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2129 struct dsdb_control_password_change *change;
2131 change = talloc(req, struct dsdb_control_password_change);
2132 if (change == NULL) {
2135 return NT_STATUS_NO_MEMORY;
2138 change->old_nt_pwd_hash = ntOldHash;
2139 change->old_lm_pwd_hash = lmOldHash;
2141 ret = ldb_request_add_control(req,
2142 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2144 if (ret != LDB_SUCCESS) {
2147 return NT_STATUS_NO_MEMORY;
2150 ret = ldb_request_add_control(req,
2151 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2153 if (ret != LDB_SUCCESS) {
2156 return NT_STATUS_NO_MEMORY;
2158 ret = ldb_request_add_control(req,
2159 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2161 if (ret != LDB_SUCCESS) {
2164 return NT_STATUS_NO_MEMORY;
2167 ret = dsdb_autotransaction_request(ldb, req);
2169 if (req->context != NULL) {
2170 pwd_stat = talloc_steal(mem_ctx,
2171 ((struct ldb_control *)req->context)->data);
2177 /* Sets the domain info (if requested) */
2178 if (_dominfo != NULL) {
2179 struct samr_DomInfo1 *dominfo;
2181 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2182 if (dominfo == NULL) {
2183 return NT_STATUS_NO_MEMORY;
2186 if (pwd_stat != NULL) {
2187 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2188 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2189 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2190 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2191 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2194 *_dominfo = dominfo;
2197 if (reject_reason != NULL) {
2198 if (pwd_stat != NULL) {
2199 *reject_reason = pwd_stat->reject_reason;
2201 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2205 if (pwd_stat != NULL) {
2206 talloc_free(pwd_stat);
2209 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2210 const char *errmsg = ldb_errstring(ldb);
2211 char *endptr = NULL;
2212 WERROR werr = WERR_GENERAL_FAILURE;
2213 status = NT_STATUS_UNSUCCESSFUL;
2214 if (errmsg != NULL) {
2215 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2217 if (endptr != errmsg) {
2218 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2219 status = NT_STATUS_WRONG_PASSWORD;
2221 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2222 status = NT_STATUS_PASSWORD_RESTRICTION;
2225 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2226 /* don't let the caller know if an account doesn't exist */
2227 status = NT_STATUS_WRONG_PASSWORD;
2228 } else if (ret != LDB_SUCCESS) {
2229 status = NT_STATUS_UNSUCCESSFUL;
2236 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2237 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2238 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2239 * user change or not. The "rejectReason" gives some more informations if the
2242 * This wrapper function for "samdb_set_password" takes a SID as input rather
2245 * This call encapsulates a new LDB transaction for changing the password;
2246 * therefore the user hasn't to start a new one.
2248 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2249 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2250 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2251 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2253 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2254 const struct dom_sid *user_sid,
2255 const DATA_BLOB *new_password,
2256 const struct samr_Password *lmNewHash,
2257 const struct samr_Password *ntNewHash,
2258 const struct samr_Password *lmOldHash,
2259 const struct samr_Password *ntOldHash,
2260 enum samPwdChangeReason *reject_reason,
2261 struct samr_DomInfo1 **_dominfo)
2264 struct ldb_dn *user_dn;
2267 ret = ldb_transaction_start(ldb);
2268 if (ret != LDB_SUCCESS) {
2269 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2270 return NT_STATUS_TRANSACTION_ABORTED;
2273 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2274 "(&(objectSid=%s)(objectClass=user))",
2275 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2277 ldb_transaction_cancel(ldb);
2278 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2279 dom_sid_string(mem_ctx, user_sid)));
2280 return NT_STATUS_NO_SUCH_USER;
2283 nt_status = samdb_set_password(ldb, mem_ctx,
2286 lmNewHash, ntNewHash,
2287 lmOldHash, ntOldHash,
2288 reject_reason, _dominfo);
2289 if (!NT_STATUS_IS_OK(nt_status)) {
2290 ldb_transaction_cancel(ldb);
2291 talloc_free(user_dn);
2295 ret = ldb_transaction_commit(ldb);
2296 if (ret != LDB_SUCCESS) {
2297 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2298 ldb_dn_get_linearized(user_dn),
2299 ldb_errstring(ldb)));
2300 talloc_free(user_dn);
2301 return NT_STATUS_TRANSACTION_ABORTED;
2304 talloc_free(user_dn);
2305 return NT_STATUS_OK;
2309 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2310 struct dom_sid *sid, struct ldb_dn **ret_dn)
2312 struct ldb_message *msg;
2313 struct ldb_dn *basedn;
2317 sidstr = dom_sid_string(mem_ctx, sid);
2318 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2320 /* We might have to create a ForeignSecurityPrincipal, even if this user
2321 * is in our own domain */
2323 msg = ldb_msg_new(sidstr);
2325 talloc_free(sidstr);
2326 return NT_STATUS_NO_MEMORY;
2329 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2330 ldb_get_default_basedn(sam_ctx),
2331 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2333 if (ret != LDB_SUCCESS) {
2334 DEBUG(0, ("Failed to find DN for "
2335 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2336 talloc_free(sidstr);
2337 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2340 /* add core elements to the ldb_message for the alias */
2342 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2343 talloc_free(sidstr);
2344 return NT_STATUS_NO_MEMORY;
2347 samdb_msg_add_string(sam_ctx, msg, msg,
2349 "foreignSecurityPrincipal");
2351 /* create the alias */
2352 ret = ldb_add(sam_ctx, msg);
2353 if (ret != LDB_SUCCESS) {
2354 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2356 ldb_dn_get_linearized(msg->dn),
2357 ldb_errstring(sam_ctx)));
2358 talloc_free(sidstr);
2359 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2362 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2363 talloc_free(sidstr);
2365 return NT_STATUS_OK;
2370 Find the DN of a domain, assuming it to be a dotted.dns name
2373 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2376 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2377 const char *binary_encoded;
2378 const char **split_realm;
2385 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2387 talloc_free(tmp_ctx);
2390 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2391 for (i=0; split_realm[i]; i++) {
2392 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2393 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2394 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2395 binary_encoded, ldb_dn_get_linearized(dn)));
2396 talloc_free(tmp_ctx);
2400 if (!ldb_dn_validate(dn)) {
2401 DEBUG(2, ("Failed to validated DN %s\n",
2402 ldb_dn_get_linearized(dn)));
2403 talloc_free(tmp_ctx);
2406 talloc_free(tmp_ctx);
2411 Find the DN of a domain, be it the netbios or DNS name
2413 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2414 const char *domain_name)
2416 const char * const domain_ref_attrs[] = {
2419 const char * const domain_ref2_attrs[] = {
2422 struct ldb_result *res_domain_ref;
2423 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2424 /* find the domain's DN */
2425 int ret_domain = ldb_search(ldb, mem_ctx,
2427 samdb_partitions_dn(ldb, mem_ctx),
2430 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2432 if (ret_domain != LDB_SUCCESS) {
2436 if (res_domain_ref->count == 0) {
2437 ret_domain = ldb_search(ldb, mem_ctx,
2439 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2442 "(objectclass=domain)");
2443 if (ret_domain != LDB_SUCCESS) {
2447 if (res_domain_ref->count == 1) {
2448 return res_domain_ref->msgs[0]->dn;
2453 if (res_domain_ref->count > 1) {
2454 DEBUG(0,("Found %d records matching domain [%s]\n",
2455 ret_domain, domain_name));
2459 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2465 use a GUID to find a DN
2467 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2468 TALLOC_CTX *mem_ctx,
2469 const struct GUID *guid, struct ldb_dn **dn)
2472 struct ldb_result *res;
2473 const char *attrs[] = { NULL };
2474 char *guid_str = GUID_string(mem_ctx, guid);
2477 return ldb_operr(ldb);
2480 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2481 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2482 DSDB_SEARCH_SHOW_EXTENDED_DN |
2483 DSDB_SEARCH_ONE_ONLY,
2484 "objectGUID=%s", guid_str);
2485 talloc_free(guid_str);
2486 if (ret != LDB_SUCCESS) {
2490 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2497 use a DN to find a GUID with a given attribute name
2499 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2500 struct ldb_dn *dn, const char *attribute,
2504 struct ldb_result *res;
2505 const char *attrs[2];
2506 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2508 attrs[0] = attribute;
2511 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2512 DSDB_SEARCH_SHOW_DELETED |
2513 DSDB_SEARCH_SHOW_RECYCLED);
2514 if (ret != LDB_SUCCESS) {
2515 talloc_free(tmp_ctx);
2518 if (res->count < 1) {
2519 talloc_free(tmp_ctx);
2520 return LDB_ERR_NO_SUCH_OBJECT;
2522 *guid = samdb_result_guid(res->msgs[0], attribute);
2523 talloc_free(tmp_ctx);
2528 use a DN to find a GUID
2530 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2531 struct ldb_dn *dn, struct GUID *guid)
2533 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2539 adds the given GUID to the given ldb_message. This value is added
2540 for the given attr_name (may be either "objectGUID" or "parentGUID").
2542 int dsdb_msg_add_guid(struct ldb_message *msg,
2544 const char *attr_name)
2549 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2551 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 ret = LDB_ERR_OPERATIONS_ERROR;
2557 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2558 if (ret != LDB_SUCCESS) {
2559 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2567 talloc_free(tmp_ctx);
2574 use a DN to find a SID
2576 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2577 struct ldb_dn *dn, struct dom_sid *sid)
2580 struct ldb_result *res;
2581 const char *attrs[] = { "objectSid", NULL };
2582 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2587 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2588 DSDB_SEARCH_SHOW_DELETED |
2589 DSDB_SEARCH_SHOW_RECYCLED);
2590 if (ret != LDB_SUCCESS) {
2591 talloc_free(tmp_ctx);
2594 if (res->count < 1) {
2595 talloc_free(tmp_ctx);
2596 return LDB_ERR_NO_SUCH_OBJECT;
2598 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2600 talloc_free(tmp_ctx);
2601 return LDB_ERR_NO_SUCH_OBJECT;
2604 talloc_free(tmp_ctx);
2609 use a SID to find a DN
2611 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2612 TALLOC_CTX *mem_ctx,
2613 struct dom_sid *sid, struct ldb_dn **dn)
2616 struct ldb_result *res;
2617 const char *attrs[] = { NULL };
2618 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2621 return ldb_operr(ldb);
2624 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2625 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2626 DSDB_SEARCH_SHOW_EXTENDED_DN |
2627 DSDB_SEARCH_ONE_ONLY,
2628 "objectSid=%s", sid_str);
2629 talloc_free(sid_str);
2630 if (ret != LDB_SUCCESS) {
2634 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2641 load a repsFromTo blob list for a given partition GUID
2642 attr must be "repsFrom" or "repsTo"
2644 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2645 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2647 const char *attrs[] = { attr, NULL };
2648 struct ldb_result *res = NULL;
2649 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2651 struct ldb_message_element *el;
2656 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2658 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2659 talloc_free(tmp_ctx);
2660 return WERR_DS_DRA_INTERNAL_ERROR;
2663 el = ldb_msg_find_element(res->msgs[0], attr);
2665 /* it's OK to be empty */
2666 talloc_free(tmp_ctx);
2670 *count = el->num_values;
2671 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2673 talloc_free(tmp_ctx);
2674 return WERR_DS_DRA_INTERNAL_ERROR;
2677 for (i=0; i<(*count); i++) {
2678 enum ndr_err_code ndr_err;
2679 ndr_err = ndr_pull_struct_blob(&el->values[i],
2682 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2683 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2684 talloc_free(tmp_ctx);
2685 return WERR_DS_DRA_INTERNAL_ERROR;
2689 talloc_free(tmp_ctx);
2695 save the repsFromTo blob list for a given partition GUID
2696 attr must be "repsFrom" or "repsTo"
2698 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2699 const char *attr, struct repsFromToBlob *r, uint32_t count)
2701 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2702 struct ldb_message *msg;
2703 struct ldb_message_element *el;
2706 msg = ldb_msg_new(tmp_ctx);
2708 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2712 el->values = talloc_array(msg, struct ldb_val, count);
2717 for (i=0; i<count; i++) {
2719 enum ndr_err_code ndr_err;
2721 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2723 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2732 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2733 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2737 talloc_free(tmp_ctx);
2742 talloc_free(tmp_ctx);
2743 return WERR_DS_DRA_INTERNAL_ERROR;
2748 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2749 object for a partition
2751 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2752 uint64_t *uSN, uint64_t *urgent_uSN)
2754 struct ldb_request *req;
2756 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2757 struct dsdb_control_current_partition *p_ctrl;
2758 struct ldb_result *res;
2760 res = talloc_zero(tmp_ctx, struct ldb_result);
2762 talloc_free(tmp_ctx);
2763 return ldb_oom(ldb);
2766 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2767 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2771 res, ldb_search_default_callback,
2773 if (ret != LDB_SUCCESS) {
2774 talloc_free(tmp_ctx);
2778 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2779 if (p_ctrl == NULL) {
2780 talloc_free(tmp_ctx);
2781 return ldb_oom(ldb);
2783 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2786 ret = ldb_request_add_control(req,
2787 DSDB_CONTROL_CURRENT_PARTITION_OID,
2789 if (ret != LDB_SUCCESS) {
2790 talloc_free(tmp_ctx);
2794 /* Run the new request */
2795 ret = ldb_request(ldb, req);
2797 if (ret == LDB_SUCCESS) {
2798 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2801 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2802 /* it hasn't been created yet, which means
2803 an implicit value of zero */
2805 talloc_free(tmp_ctx);
2809 if (ret != LDB_SUCCESS) {
2810 talloc_free(tmp_ctx);
2814 if (res->count < 1) {
2820 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2822 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2826 talloc_free(tmp_ctx);
2831 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2832 const struct drsuapi_DsReplicaCursor2 *c2)
2834 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2837 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2838 const struct drsuapi_DsReplicaCursor *c2)
2840 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2845 see if a computer identified by its invocationId is a RODC
2847 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2849 /* 1) find the DN for this servers NTDSDSA object
2850 2) search for the msDS-isRODC attribute
2851 3) if not present then not a RODC
2852 4) if present and TRUE then is a RODC
2854 struct ldb_dn *config_dn;
2855 const char *attrs[] = { "msDS-isRODC", NULL };
2857 struct ldb_result *res;
2858 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2860 config_dn = ldb_get_config_basedn(sam_ctx);
2862 talloc_free(tmp_ctx);
2863 return ldb_operr(sam_ctx);
2866 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2867 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2869 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2871 talloc_free(tmp_ctx);
2875 if (ret != LDB_SUCCESS) {
2876 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2877 GUID_string(tmp_ctx, objectGUID)));
2879 talloc_free(tmp_ctx);
2883 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2884 *is_rodc = (ret == 1);
2886 talloc_free(tmp_ctx);
2892 see if we are a RODC
2894 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2896 const struct GUID *objectGUID;
2900 /* see if we have a cached copy */
2901 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2907 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2909 return ldb_operr(sam_ctx);
2912 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2913 if (ret != LDB_SUCCESS) {
2917 cached = talloc(sam_ctx, bool);
2918 if (cached == NULL) {
2919 return ldb_oom(sam_ctx);
2923 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2924 if (ret != LDB_SUCCESS) {
2925 talloc_free(cached);
2926 return ldb_operr(sam_ctx);
2932 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2934 TALLOC_CTX *tmp_ctx;
2937 tmp_ctx = talloc_new(ldb);
2938 if (tmp_ctx == NULL) {
2942 cached = talloc(tmp_ctx, bool);
2948 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2952 talloc_steal(ldb, cached);
2953 talloc_free(tmp_ctx);
2957 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2958 talloc_free(tmp_ctx);
2964 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2966 flags are DS_NTDS_OPTION_*
2968 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2970 TALLOC_CTX *tmp_ctx;
2971 const char *attrs[] = { "options", NULL };
2973 struct ldb_result *res;
2975 tmp_ctx = talloc_new(ldb);
2976 if (tmp_ctx == NULL) {
2980 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2981 if (ret != LDB_SUCCESS) {
2985 if (res->count != 1) {
2989 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
2991 talloc_free(tmp_ctx);
2996 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2997 talloc_free(tmp_ctx);
2998 return LDB_ERR_NO_SUCH_OBJECT;
3001 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3003 const char *attrs[] = { "objectCategory", NULL };
3005 struct ldb_result *res;
3007 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3008 if (ret != LDB_SUCCESS) {
3012 if (res->count != 1) {
3016 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3019 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3024 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3025 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3027 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3029 char **tokens, *ret;
3032 tokens = str_list_make(mem_ctx, cn, " -_");
3036 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3037 tokens[0][0] = tolower(tokens[0][0]);
3038 for (i = 1; i < str_list_length((const char **)tokens); i++)
3039 tokens[i][0] = toupper(tokens[i][0]);
3041 ret = talloc_strdup(mem_ctx, tokens[0]);
3042 for (i = 1; i < str_list_length((const char **)tokens); i++)
3043 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3045 talloc_free(tokens);
3051 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3053 int dsdb_functional_level(struct ldb_context *ldb)
3055 int *domainFunctionality =
3056 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3057 if (!domainFunctionality) {
3058 /* this is expected during initial provision */
3059 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3060 return DS_DOMAIN_FUNCTION_2000;
3062 return *domainFunctionality;
3066 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3068 int dsdb_forest_functional_level(struct ldb_context *ldb)
3070 int *forestFunctionality =
3071 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3072 if (!forestFunctionality) {
3073 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3074 return DS_DOMAIN_FUNCTION_2000;
3076 return *forestFunctionality;
3080 set a GUID in an extended DN structure
3082 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3088 status = GUID_to_ndr_blob(guid, dn, &v);
3089 if (!NT_STATUS_IS_OK(status)) {
3090 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3093 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3099 return a GUID from a extended DN structure
3101 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3103 const struct ldb_val *v;
3105 v = ldb_dn_get_extended_component(dn, component_name);
3107 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3110 return GUID_from_ndr_blob(v, guid);
3114 return a uint64_t from a extended DN structure
3116 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3118 const struct ldb_val *v;
3121 v = ldb_dn_get_extended_component(dn, component_name);
3123 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3125 s = talloc_strndup(dn, (const char *)v->data, v->length);
3126 NT_STATUS_HAVE_NO_MEMORY(s);
3128 *val = strtoull(s, NULL, 0);
3131 return NT_STATUS_OK;
3135 return a NTTIME from a extended DN structure
3137 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3139 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3143 return a uint32_t from a extended DN structure
3145 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3147 const struct ldb_val *v;
3150 v = ldb_dn_get_extended_component(dn, component_name);
3152 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3155 s = talloc_strndup(dn, (const char *)v->data, v->length);
3156 NT_STATUS_HAVE_NO_MEMORY(s);
3158 *val = strtoul(s, NULL, 0);
3161 return NT_STATUS_OK;
3165 return a dom_sid from a extended DN structure
3167 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3169 const struct ldb_val *sid_blob;
3170 struct TALLOC_CTX *tmp_ctx;
3171 enum ndr_err_code ndr_err;
3173 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3175 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3178 tmp_ctx = talloc_new(NULL);
3180 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3181 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3182 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3183 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3184 talloc_free(tmp_ctx);
3188 talloc_free(tmp_ctx);
3189 return NT_STATUS_OK;
3194 return RMD_FLAGS directly from a ldb_dn
3195 returns 0 if not found
3197 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3199 const struct ldb_val *v;
3201 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3202 if (!v || v->length > sizeof(buf)-1) return 0;
3203 strncpy(buf, (const char *)v->data, v->length);
3205 return strtoul(buf, NULL, 10);
3209 return RMD_FLAGS directly from a ldb_val for a DN
3210 returns 0 if RMD_FLAGS is not found
3212 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3218 if (val->length < 13) {
3221 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3225 flags = strtoul(p+11, &end, 10);
3226 if (!end || *end != '>') {
3227 /* it must end in a > */
3234 return true if a ldb_val containing a DN in storage form is deleted
3236 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3238 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3242 return true if a ldb_val containing a DN in storage form is
3243 in the upgraded w2k3 linked attribute format
3245 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3247 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3251 return a DN for a wellknown GUID
3253 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3254 struct ldb_dn *nc_root, const char *wk_guid,
3255 struct ldb_dn **wkguid_dn)
3257 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3258 const char *attrs[] = { NULL };
3261 struct ldb_result *res;
3263 /* construct the magic WKGUID DN */
3264 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3265 wk_guid, ldb_dn_get_linearized(nc_root));
3267 talloc_free(tmp_ctx);
3268 return ldb_operr(samdb);
3271 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3272 DSDB_SEARCH_SHOW_DELETED |
3273 DSDB_SEARCH_SHOW_RECYCLED);
3274 if (ret != LDB_SUCCESS) {
3275 talloc_free(tmp_ctx);
3279 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3280 talloc_free(tmp_ctx);
3285 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3287 return ldb_dn_compare(*dn1, *dn2);
3291 find a NC root given a DN within the NC
3293 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3294 struct ldb_dn **nc_root)
3296 const char *root_attrs[] = { "namingContexts", NULL };
3297 TALLOC_CTX *tmp_ctx;
3299 struct ldb_message_element *el;
3300 struct ldb_result *root_res;
3302 struct ldb_dn **nc_dns;
3304 tmp_ctx = talloc_new(samdb);
3305 if (tmp_ctx == NULL) {
3306 return ldb_oom(samdb);
3309 ret = ldb_search(samdb, tmp_ctx, &root_res,
3310 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3311 if (ret != LDB_SUCCESS) {
3312 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3313 talloc_free(tmp_ctx);
3317 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3319 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3320 ldb_errstring(samdb)));
3321 talloc_free(tmp_ctx);
3322 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3325 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3327 talloc_free(tmp_ctx);
3328 return ldb_oom(samdb);
3331 for (i=0; i<el->num_values; i++) {
3332 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3333 if (nc_dns[i] == NULL) {
3334 talloc_free(tmp_ctx);
3335 return ldb_operr(samdb);
3339 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3341 for (i=0; i<el->num_values; i++) {
3342 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3343 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3344 talloc_free(tmp_ctx);
3349 talloc_free(tmp_ctx);
3350 return LDB_ERR_NO_SUCH_OBJECT;
3355 find the deleted objects DN for any object, by looking for the NC
3356 root, then looking up the wellknown GUID
3358 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3359 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3360 struct ldb_dn **do_dn)
3362 struct ldb_dn *nc_root;
3365 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3366 if (ret != LDB_SUCCESS) {
3370 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3371 talloc_free(nc_root);
3376 return the tombstoneLifetime, in days
3378 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3381 dn = ldb_get_config_basedn(ldb);
3383 return LDB_ERR_NO_SUCH_OBJECT;
3385 dn = ldb_dn_copy(ldb, dn);
3387 return ldb_operr(ldb);
3389 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3390 be a wellknown GUID for this */
3391 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3393 return ldb_operr(ldb);
3396 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3402 compare a ldb_val to a string case insensitively
3404 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3406 size_t len = strlen(s);
3408 if (len > v->length) return 1;
3409 ret = strncasecmp(s, (const char *)v->data, v->length);
3410 if (ret != 0) return ret;
3411 if (v->length > len && v->data[len] != 0) {
3419 load the UDV for a partition in v2 format
3420 The list is returned sorted, and with our local cursor added
3422 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3423 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3425 static const char *attrs[] = { "replUpToDateVector", NULL };
3426 struct ldb_result *r;
3427 const struct ldb_val *ouv_value;
3430 uint64_t highest_usn;
3431 const struct GUID *our_invocation_id;
3432 struct timeval now = timeval_current();
3434 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3435 if (ret != LDB_SUCCESS) {
3439 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3441 enum ndr_err_code ndr_err;
3442 struct replUpToDateVectorBlob ouv;
3444 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3445 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3446 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3448 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3450 if (ouv.version != 2) {
3451 /* we always store as version 2, and
3452 * replUpToDateVector is not replicated
3454 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3457 *count = ouv.ctr.ctr2.count;
3458 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3466 our_invocation_id = samdb_ntds_invocation_id(samdb);
3467 if (!our_invocation_id) {
3468 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3469 talloc_free(*cursors);
3470 return ldb_operr(samdb);
3473 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3474 if (ret != LDB_SUCCESS) {
3475 /* nothing to add - this can happen after a vampire */
3476 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3480 for (i=0; i<*count; i++) {
3481 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3482 (*cursors)[i].highest_usn = highest_usn;
3483 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3484 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3489 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3491 return ldb_oom(samdb);
3494 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3495 (*cursors)[*count].highest_usn = highest_usn;
3496 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3499 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3505 load the UDV for a partition in version 1 format
3506 The list is returned sorted, and with our local cursor added
3508 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3509 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3511 struct drsuapi_DsReplicaCursor2 *v2;
3515 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3516 if (ret != LDB_SUCCESS) {
3526 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3527 if (*cursors == NULL) {
3529 return ldb_oom(samdb);
3532 for (i=0; i<*count; i++) {
3533 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3534 (*cursors)[i].highest_usn = v2[i].highest_usn;
3541 add a set of controls to a ldb_request structure based on a set of
3542 flags. See util.h for a list of available flags
3544 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3547 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3548 struct ldb_search_options_control *options;
3549 /* Using the phantom root control allows us to search all partitions */
3550 options = talloc(req, struct ldb_search_options_control);
3551 if (options == NULL) {
3552 return LDB_ERR_OPERATIONS_ERROR;
3554 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3556 ret = ldb_request_add_control(req,
3557 LDB_CONTROL_SEARCH_OPTIONS_OID,
3559 if (ret != LDB_SUCCESS) {
3564 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3565 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3566 if (ret != LDB_SUCCESS) {
3571 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3572 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3573 if (ret != LDB_SUCCESS) {
3578 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3579 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3580 if (ret != LDB_SUCCESS) {
3585 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3586 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3587 if (!extended_ctrl) {
3588 return LDB_ERR_OPERATIONS_ERROR;
3590 extended_ctrl->type = 1;
3592 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3593 if (ret != LDB_SUCCESS) {
3598 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3599 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3600 if (ret != LDB_SUCCESS) {
3605 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3606 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3607 if (ret != LDB_SUCCESS) {
3612 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3613 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3614 if (ret != LDB_SUCCESS) {
3619 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3620 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3621 if (ret != LDB_SUCCESS) {
3626 if (dsdb_flags & DSDB_TREE_DELETE) {
3627 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3628 if (ret != LDB_SUCCESS) {
3637 an add with a set of controls
3639 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3640 uint32_t dsdb_flags)
3642 struct ldb_request *req;
3645 ret = ldb_build_add_req(&req, ldb, ldb,
3649 ldb_op_default_callback,
3652 if (ret != LDB_SUCCESS) return ret;
3654 ret = dsdb_request_add_controls(req, dsdb_flags);
3655 if (ret != LDB_SUCCESS) {
3660 ret = dsdb_autotransaction_request(ldb, req);
3667 a modify with a set of controls
3669 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3670 uint32_t dsdb_flags)
3672 struct ldb_request *req;
3675 ret = ldb_build_mod_req(&req, ldb, ldb,
3679 ldb_op_default_callback,
3682 if (ret != LDB_SUCCESS) return ret;
3684 ret = dsdb_request_add_controls(req, dsdb_flags);
3685 if (ret != LDB_SUCCESS) {
3690 ret = dsdb_autotransaction_request(ldb, req);
3697 like dsdb_modify() but set all the element flags to
3698 LDB_FLAG_MOD_REPLACE
3700 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3704 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3705 for (i=0;i<msg->num_elements;i++) {
3706 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3709 return dsdb_modify(ldb, msg, dsdb_flags);
3714 search for attrs on one DN, allowing for dsdb_flags controls
3716 int dsdb_search_dn(struct ldb_context *ldb,
3717 TALLOC_CTX *mem_ctx,
3718 struct ldb_result **_res,
3719 struct ldb_dn *basedn,
3720 const char * const *attrs,
3721 uint32_t dsdb_flags)
3724 struct ldb_request *req;
3725 struct ldb_result *res;
3727 res = talloc_zero(mem_ctx, struct ldb_result);
3729 return ldb_oom(ldb);
3732 ret = ldb_build_search_req(&req, ldb, res,
3739 ldb_search_default_callback,
3741 if (ret != LDB_SUCCESS) {
3746 ret = dsdb_request_add_controls(req, dsdb_flags);
3747 if (ret != LDB_SUCCESS) {
3752 ret = ldb_request(ldb, req);
3753 if (ret == LDB_SUCCESS) {
3754 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3758 if (ret != LDB_SUCCESS) {
3768 search for attrs on one DN, by the GUID of the DN, allowing for
3771 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3772 TALLOC_CTX *mem_ctx,
3773 struct ldb_result **_res,
3774 const struct GUID *guid,
3775 const char * const *attrs,
3776 uint32_t dsdb_flags)
3778 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3782 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3783 if (!ldb_dn_validate(dn)) {
3784 talloc_free(tmp_ctx);
3785 return LDB_ERR_INVALID_DN_SYNTAX;
3788 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3789 talloc_free(tmp_ctx);
3794 general search with dsdb_flags for controls
3796 int dsdb_search(struct ldb_context *ldb,
3797 TALLOC_CTX *mem_ctx,
3798 struct ldb_result **_res,
3799 struct ldb_dn *basedn,
3800 enum ldb_scope scope,
3801 const char * const *attrs,
3802 uint32_t dsdb_flags,
3803 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3806 struct ldb_request *req;
3807 struct ldb_result *res;
3809 char *expression = NULL;
3810 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3812 res = talloc_zero(tmp_ctx, struct ldb_result);
3814 talloc_free(tmp_ctx);
3815 return ldb_oom(ldb);
3819 va_start(ap, exp_fmt);
3820 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3824 talloc_free(tmp_ctx);
3825 return ldb_oom(ldb);
3829 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3836 ldb_search_default_callback,
3838 if (ret != LDB_SUCCESS) {
3839 talloc_free(tmp_ctx);
3843 ret = dsdb_request_add_controls(req, dsdb_flags);
3844 if (ret != LDB_SUCCESS) {
3845 talloc_free(tmp_ctx);
3846 ldb_reset_err_string(ldb);
3850 ret = ldb_request(ldb, req);
3851 if (ret == LDB_SUCCESS) {
3852 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3855 if (ret != LDB_SUCCESS) {
3856 talloc_free(tmp_ctx);
3860 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3861 if (res->count == 0) {
3862 talloc_free(tmp_ctx);
3863 ldb_reset_err_string(ldb);
3864 return LDB_ERR_NO_SUCH_OBJECT;
3866 if (res->count != 1) {
3867 talloc_free(tmp_ctx);
3868 ldb_reset_err_string(ldb);
3869 return LDB_ERR_CONSTRAINT_VIOLATION;
3873 *_res = talloc_steal(mem_ctx, res);
3874 talloc_free(tmp_ctx);
3881 general search with dsdb_flags for controls
3882 returns exactly 1 record or an error
3884 int dsdb_search_one(struct ldb_context *ldb,
3885 TALLOC_CTX *mem_ctx,
3886 struct ldb_message **msg,
3887 struct ldb_dn *basedn,
3888 enum ldb_scope scope,
3889 const char * const *attrs,
3890 uint32_t dsdb_flags,
3891 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3894 struct ldb_result *res;
3896 char *expression = NULL;
3897 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3899 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3901 res = talloc_zero(tmp_ctx, struct ldb_result);
3903 talloc_free(tmp_ctx);
3904 return ldb_oom(ldb);
3908 va_start(ap, exp_fmt);
3909 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3913 talloc_free(tmp_ctx);
3914 return ldb_oom(ldb);
3916 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3917 dsdb_flags, "%s", expression);
3919 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3923 if (ret != LDB_SUCCESS) {
3924 talloc_free(tmp_ctx);
3928 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3929 talloc_free(tmp_ctx);
3934 /* returns back the forest DNS name */
3935 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3937 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3938 ldb_get_root_basedn(ldb));
3941 if (forest_name == NULL) {
3945 p = strchr(forest_name, '/');
3954 validate that an DSA GUID belongs to the specified user sid.
3955 The user SID must be a domain controller account (either RODC or
3958 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3959 const struct GUID *dsa_guid,
3960 const struct dom_sid *sid)
3963 - find DN of record with the DSA GUID in the
3964 configuration partition (objectGUID)
3965 - remove "NTDS Settings" component from DN
3966 - do a base search on that DN for serverReference with
3968 - extract objectSid from resulting serverReference
3970 - check this sid matches the sid argument
3972 struct ldb_dn *config_dn;
3973 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3974 struct ldb_message *msg;
3975 const char *attrs1[] = { NULL };
3976 const char *attrs2[] = { "serverReference", NULL };
3978 struct ldb_dn *dn, *account_dn;
3979 struct dom_sid sid2;
3982 config_dn = ldb_get_config_basedn(ldb);
3984 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3985 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3986 if (ret != LDB_SUCCESS) {
3987 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3988 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3989 talloc_free(tmp_ctx);
3990 return ldb_operr(ldb);
3994 if (!ldb_dn_remove_child_components(dn, 1)) {
3995 talloc_free(tmp_ctx);
3996 return ldb_operr(ldb);
3999 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4000 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4001 "(objectClass=server)");
4002 if (ret != LDB_SUCCESS) {
4003 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4004 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4005 talloc_free(tmp_ctx);
4006 return ldb_operr(ldb);
4009 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4010 if (account_dn == NULL) {
4011 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4012 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4013 talloc_free(tmp_ctx);
4014 return ldb_operr(ldb);
4017 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4018 if (!NT_STATUS_IS_OK(status)) {
4019 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4020 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4021 talloc_free(tmp_ctx);
4022 return ldb_operr(ldb);
4025 if (!dom_sid_equal(sid, &sid2)) {
4026 /* someone is trying to spoof another account */
4027 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4028 GUID_string(tmp_ctx, dsa_guid),
4029 dom_sid_string(tmp_ctx, sid),
4030 dom_sid_string(tmp_ctx, &sid2)));
4031 talloc_free(tmp_ctx);
4032 return ldb_operr(ldb);
4035 talloc_free(tmp_ctx);
4039 static const char *secret_attributes[] = {
4042 "initialAuthIncoming",
4043 "initialAuthOutgoing",
4047 "supplementalCredentials",
4048 "trustAuthIncoming",
4049 "trustAuthOutgoing",
4055 check if the attribute belongs to the RODC filtered attribute set
4056 Note that attributes that are in the filtered attribute set are the
4057 ones that _are_ always sent to a RODC
4059 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4061 /* they never get secret attributes */
4062 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4066 /* they do get non-secret critical attributes */
4067 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4071 /* they do get non-secret attributes marked as being in the FAS */
4072 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4076 /* other attributes are denied */
4080 /* return fsmo role dn and role owner dn for a particular role*/
4081 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4082 struct ldb_context *ldb,
4084 struct ldb_dn **fsmo_role_dn,
4085 struct ldb_dn **role_owner_dn)
4089 case DREPL_NAMING_MASTER:
4090 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4091 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4092 if (ret != LDB_SUCCESS) {
4093 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4094 ldb_errstring(ldb)));
4095 talloc_free(tmp_ctx);
4096 return WERR_DS_DRA_INTERNAL_ERROR;
4099 case DREPL_INFRASTRUCTURE_MASTER:
4100 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4101 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4102 if (ret != LDB_SUCCESS) {
4103 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4104 ldb_errstring(ldb)));
4105 talloc_free(tmp_ctx);
4106 return WERR_DS_DRA_INTERNAL_ERROR;
4109 case DREPL_RID_MASTER:
4110 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4111 if (ret != LDB_SUCCESS) {
4112 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4113 talloc_free(tmp_ctx);
4114 return WERR_DS_DRA_INTERNAL_ERROR;
4117 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4118 if (ret != LDB_SUCCESS) {
4119 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4120 ldb_errstring(ldb)));
4121 talloc_free(tmp_ctx);
4122 return WERR_DS_DRA_INTERNAL_ERROR;
4125 case DREPL_SCHEMA_MASTER:
4126 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4127 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4128 if (ret != LDB_SUCCESS) {
4129 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4130 ldb_errstring(ldb)));
4131 talloc_free(tmp_ctx);
4132 return WERR_DS_DRA_INTERNAL_ERROR;
4135 case DREPL_PDC_MASTER:
4136 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4137 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4138 if (ret != LDB_SUCCESS) {
4139 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4140 ldb_errstring(ldb)));
4141 talloc_free(tmp_ctx);
4142 return WERR_DS_DRA_INTERNAL_ERROR;
4146 return WERR_DS_DRA_INTERNAL_ERROR;
4151 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4152 TALLOC_CTX *mem_ctx,
4153 struct ldb_dn *server_dn)
4156 struct ldb_result *res = NULL;
4157 const char * const attrs[] = { "dNSHostName", NULL};
4159 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4163 if (ldb_ret != LDB_SUCCESS) {
4164 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4165 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4169 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4173 returns true if an attribute is in the filter,
4174 false otherwise, provided that attribute value is provided with the expression
4176 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4180 switch (tree->operation) {
4183 for (i=0;i<tree->u.list.num_elements;i++) {
4184 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4190 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4191 case LDB_OP_EQUALITY:
4192 case LDB_OP_GREATER:
4195 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4199 case LDB_OP_SUBSTRING:
4200 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4204 case LDB_OP_PRESENT:
4205 /* (attrname=*) is not filtered out */
4207 case LDB_OP_EXTENDED:
4208 if (tree->u.extended.attr &&
4209 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4217 bool is_attr_in_list(const char * const * attrs, const char *attr)
4221 for (i = 0; attrs[i]; i++) {
4222 if (ldb_attr_cmp(attrs[i], attr) == 0)