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 char *s = talloc_strdup(mem_ctx, str);
774 char *a = talloc_strdup(mem_ctx, attr_name);
775 if (s == NULL || a == NULL) {
776 return ldb_oom(sam_ldb);
778 return ldb_msg_add_string(msg, a, s);
782 add a dom_sid element to a message
784 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name, struct dom_sid *sid)
788 enum ndr_err_code ndr_err;
790 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
792 (ndr_push_flags_fn_t)ndr_push_dom_sid);
793 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
794 return ldb_operr(sam_ldb);
796 return ldb_msg_add_value(msg, attr_name, &v, NULL);
801 add a delete element operation to a message
803 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
804 const char *attr_name)
806 /* we use an empty replace rather than a delete, as it allows for
807 dsdb_replace() to be used everywhere */
808 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
812 add an add attribute value to a message or enhance an existing attribute
813 which has the same name and the add flag set.
815 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
816 struct ldb_message *msg, const char *attr_name,
819 struct ldb_message_element *el;
820 struct ldb_val val, *vals;
826 v = talloc_strdup(mem_ctx, value);
828 return ldb_oom(sam_ldb);
831 val.data = (uint8_t *) v;
832 val.length = strlen(v);
834 if (val.length == 0) {
835 /* allow empty strings as non-existent attributes */
839 for (i = 0; i < msg->num_elements; i++) {
840 el = &msg->elements[i];
841 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
842 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
848 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
850 if (ret != LDB_SUCCESS) {
855 vals = talloc_realloc(msg, el->values, struct ldb_val,
858 return ldb_oom(sam_ldb);
861 el->values[el->num_values] = val;
868 add a delete attribute value to a message or enhance an existing attribute
869 which has the same name and the delete flag set.
871 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
872 struct ldb_message *msg, const char *attr_name,
875 struct ldb_message_element *el;
876 struct ldb_val val, *vals;
882 v = talloc_strdup(mem_ctx, value);
884 return ldb_oom(sam_ldb);
887 val.data = (uint8_t *) v;
888 val.length = strlen(v);
890 if (val.length == 0) {
891 /* allow empty strings as non-existent attributes */
895 for (i = 0; i < msg->num_elements; i++) {
896 el = &msg->elements[i];
897 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
898 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
904 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
906 if (ret != LDB_SUCCESS) {
911 vals = talloc_realloc(msg, el->values, struct ldb_val,
914 return ldb_oom(sam_ldb);
917 el->values[el->num_values] = val;
924 add a int element to a message
926 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927 const char *attr_name, int v)
929 const char *s = talloc_asprintf(mem_ctx, "%d", v);
930 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
934 add a unsigned int element to a message
936 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
937 const char *attr_name, unsigned int v)
939 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
943 add a (signed) int64_t element to a message
945 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
946 const char *attr_name, int64_t v)
948 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
949 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
953 add a uint64_t element to a message
955 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
956 const char *attr_name, uint64_t v)
958 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
962 add a samr_Password element to a message
964 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
965 const char *attr_name, const struct samr_Password *hash)
968 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
970 return ldb_oom(sam_ldb);
973 return ldb_msg_add_value(msg, attr_name, &val, NULL);
977 add a samr_Password array to a message
979 int samdb_msg_add_hashes(struct ldb_context *ldb,
980 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
981 const char *attr_name, struct samr_Password *hashes,
986 val.data = talloc_array_size(mem_ctx, 16, count);
987 val.length = count*16;
991 for (i=0;i<count;i++) {
992 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
994 return ldb_msg_add_value(msg, attr_name, &val, NULL);
998 add a acct_flags element to a message
1000 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001 const char *attr_name, uint32_t v)
1003 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1007 add a logon_hours element to a message
1009 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1010 const char *attr_name, struct samr_LogonHours *hours)
1013 val.length = hours->units_per_week / 8;
1014 val.data = hours->bits;
1015 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1019 add a parameters element to a message
1021 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1022 const char *attr_name, struct lsa_BinaryString *parameters)
1025 val.length = parameters->length;
1026 val.data = (uint8_t *)parameters->array;
1027 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1030 add a general value element to a message
1032 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1033 const char *attr_name, const struct ldb_val *val)
1035 return ldb_msg_add_value(msg, attr_name, val, NULL);
1039 sets a general value element to a message
1041 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1042 const char *attr_name, const struct ldb_val *val)
1044 struct ldb_message_element *el;
1046 el = ldb_msg_find_element(msg, attr_name);
1050 return ldb_msg_add_value(msg, attr_name, val, NULL);
1054 set a string element in a message
1056 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1057 const char *attr_name, const char *str)
1059 struct ldb_message_element *el;
1061 el = ldb_msg_find_element(msg, attr_name);
1065 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1069 * sets a signed integer in a message
1071 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1072 struct ldb_message *msg, const char *attr_name, int v)
1074 struct ldb_message_element *el;
1076 el = ldb_msg_find_element(msg, attr_name);
1080 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
1084 * sets an unsigned integer in a message
1086 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1087 struct ldb_message *msg, const char *attr_name,
1090 struct ldb_message_element *el;
1092 el = ldb_msg_find_element(msg, attr_name);
1096 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1100 * Handle ldb_request in transaction
1102 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1103 struct ldb_request *req)
1107 ret = ldb_transaction_start(sam_ldb);
1108 if (ret != LDB_SUCCESS) {
1112 ret = ldb_request(sam_ldb, req);
1113 if (ret == LDB_SUCCESS) {
1114 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1117 if (ret == LDB_SUCCESS) {
1118 return ldb_transaction_commit(sam_ldb);
1120 ldb_transaction_cancel(sam_ldb);
1126 return a default security descriptor
1128 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1130 struct security_descriptor *sd;
1132 sd = security_descriptor_initialise(mem_ctx);
1137 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1139 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1140 struct ldb_dn *aggregate_dn;
1145 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1146 if (!aggregate_dn) {
1149 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1152 return aggregate_dn;
1155 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1157 struct ldb_dn *new_dn;
1159 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1160 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1161 talloc_free(new_dn);
1167 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1169 struct ldb_dn *new_dn;
1171 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1172 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1173 talloc_free(new_dn);
1179 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1181 struct ldb_dn *new_dn;
1183 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1184 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1185 talloc_free(new_dn);
1192 work out the domain sid for the current open ldb
1194 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1196 TALLOC_CTX *tmp_ctx;
1197 const struct dom_sid *domain_sid;
1198 const char *attrs[] = {
1202 struct ldb_result *res;
1205 /* see if we have a cached copy */
1206 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1211 tmp_ctx = talloc_new(ldb);
1212 if (tmp_ctx == NULL) {
1216 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1218 if (ret != LDB_SUCCESS) {
1222 if (res->count != 1) {
1226 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1227 if (domain_sid == NULL) {
1231 /* cache the domain_sid in the ldb */
1232 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1236 talloc_steal(ldb, domain_sid);
1237 talloc_free(tmp_ctx);
1242 talloc_free(tmp_ctx);
1247 get domain sid from cache
1249 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1251 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1254 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1256 TALLOC_CTX *tmp_ctx;
1257 struct dom_sid *dom_sid_new;
1258 struct dom_sid *dom_sid_old;
1260 /* see if we have a cached copy */
1261 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1262 "cache.domain_sid"), struct dom_sid);
1264 tmp_ctx = talloc_new(ldb);
1265 if (tmp_ctx == NULL) {
1269 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1274 /* cache the domain_sid in the ldb */
1275 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1279 talloc_steal(ldb, dom_sid_new);
1280 talloc_free(tmp_ctx);
1281 talloc_free(dom_sid_old);
1286 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1287 talloc_free(tmp_ctx);
1291 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1293 TALLOC_CTX *tmp_ctx;
1294 struct ldb_dn *ntds_settings_dn_new;
1295 struct ldb_dn *ntds_settings_dn_old;
1297 /* see if we have a cached copy */
1298 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1299 "cache.ntds_settings_dn"), struct ldb_dn);
1301 tmp_ctx = talloc_new(ldb);
1302 if (tmp_ctx == NULL) {
1306 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1307 if (!ntds_settings_dn_new) {
1311 /* cache the domain_sid in the ldb */
1312 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1316 talloc_steal(ldb, ntds_settings_dn_new);
1317 talloc_free(tmp_ctx);
1318 talloc_free(ntds_settings_dn_old);
1323 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1324 talloc_free(tmp_ctx);
1328 /* Obtain the short name of the flexible single master operator
1329 * (FSMO), such as the PDC Emulator */
1330 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1333 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1334 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1335 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1336 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1338 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1339 /* Ensure this matches the format. This gives us a
1340 * bit more confidence that a 'cn' value will be a
1345 return (char *)val->data;
1351 work out the ntds settings dn for the current open ldb
1353 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1355 TALLOC_CTX *tmp_ctx;
1356 const char *root_attrs[] = { "dsServiceName", NULL };
1358 struct ldb_result *root_res;
1359 struct ldb_dn *settings_dn;
1361 /* see if we have a cached copy */
1362 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1367 tmp_ctx = talloc_new(ldb);
1368 if (tmp_ctx == NULL) {
1372 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1374 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1375 ldb_errstring(ldb)));
1379 if (root_res->count != 1) {
1383 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1385 /* cache the domain_sid in the ldb */
1386 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1390 talloc_steal(ldb, settings_dn);
1391 talloc_free(tmp_ctx);
1396 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1397 talloc_free(tmp_ctx);
1402 work out the ntds settings invocationId for the current open ldb
1404 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1406 TALLOC_CTX *tmp_ctx;
1407 const char *attrs[] = { "invocationId", NULL };
1409 struct ldb_result *res;
1410 struct GUID *invocation_id;
1412 /* see if we have a cached copy */
1413 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1414 if (invocation_id) {
1415 return invocation_id;
1418 tmp_ctx = talloc_new(ldb);
1419 if (tmp_ctx == NULL) {
1423 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1428 if (res->count != 1) {
1432 invocation_id = talloc(tmp_ctx, struct GUID);
1433 if (!invocation_id) {
1437 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1439 /* cache the domain_sid in the ldb */
1440 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1444 talloc_steal(ldb, invocation_id);
1445 talloc_free(tmp_ctx);
1447 return invocation_id;
1450 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1451 talloc_free(tmp_ctx);
1455 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1457 TALLOC_CTX *tmp_ctx;
1458 struct GUID *invocation_id_new;
1459 struct GUID *invocation_id_old;
1461 /* see if we have a cached copy */
1462 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1463 "cache.invocation_id");
1465 tmp_ctx = talloc_new(ldb);
1466 if (tmp_ctx == NULL) {
1470 invocation_id_new = talloc(tmp_ctx, struct GUID);
1471 if (!invocation_id_new) {
1475 *invocation_id_new = *invocation_id_in;
1477 /* cache the domain_sid in the ldb */
1478 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1482 talloc_steal(ldb, invocation_id_new);
1483 talloc_free(tmp_ctx);
1484 talloc_free(invocation_id_old);
1489 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1490 talloc_free(tmp_ctx);
1495 work out the ntds settings objectGUID for the current open ldb
1497 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1499 TALLOC_CTX *tmp_ctx;
1500 const char *attrs[] = { "objectGUID", NULL };
1502 struct ldb_result *res;
1503 struct GUID *ntds_guid;
1505 /* see if we have a cached copy */
1506 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1511 tmp_ctx = talloc_new(ldb);
1512 if (tmp_ctx == NULL) {
1516 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1521 if (res->count != 1) {
1525 ntds_guid = talloc(tmp_ctx, struct GUID);
1530 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1532 /* cache the domain_sid in the ldb */
1533 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1537 talloc_steal(ldb, ntds_guid);
1538 talloc_free(tmp_ctx);
1543 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1544 talloc_free(tmp_ctx);
1548 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1550 TALLOC_CTX *tmp_ctx;
1551 struct GUID *ntds_guid_new;
1552 struct GUID *ntds_guid_old;
1554 /* see if we have a cached copy */
1555 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1557 tmp_ctx = talloc_new(ldb);
1558 if (tmp_ctx == NULL) {
1562 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1563 if (!ntds_guid_new) {
1567 *ntds_guid_new = *ntds_guid_in;
1569 /* cache the domain_sid in the ldb */
1570 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1574 talloc_steal(ldb, ntds_guid_new);
1575 talloc_free(tmp_ctx);
1576 talloc_free(ntds_guid_old);
1581 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1582 talloc_free(tmp_ctx);
1587 work out the server dn for the current open ldb
1589 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1591 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1595 work out the server dn for the current open ldb
1597 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1599 struct ldb_dn *server_dn;
1600 struct ldb_dn *servers_dn;
1601 struct ldb_dn *server_site_dn;
1603 /* TODO: there must be a saner way to do this!! */
1604 server_dn = samdb_server_dn(ldb, mem_ctx);
1605 if (!server_dn) return NULL;
1607 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1608 talloc_free(server_dn);
1609 if (!servers_dn) return NULL;
1611 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1612 talloc_free(servers_dn);
1614 return server_site_dn;
1618 find the site name from a computers DN record
1620 int samdb_find_site_for_computer(struct ldb_context *ldb,
1621 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1622 const char **site_name)
1626 const struct ldb_val *rdn_val;
1630 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1631 if (ret != LDB_SUCCESS) {
1635 if (!ldb_dn_remove_child_components(dn, 2)) {
1637 return LDB_ERR_INVALID_DN_SYNTAX;
1639 rdn_val = ldb_dn_get_rdn_val(dn);
1640 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1643 return LDB_ERR_OPERATIONS_ERROR;
1649 find the NTDS GUID from a computers DN record
1651 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1652 struct GUID *ntds_guid)
1657 *ntds_guid = GUID_zero();
1659 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1660 if (ret != LDB_SUCCESS) {
1664 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1666 return LDB_ERR_OPERATIONS_ERROR;
1669 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1675 find a 'reference' DN that points at another object
1676 (eg. serverReference, rIDManagerReference etc)
1678 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1679 const char *attribute, struct ldb_dn **dn)
1681 const char *attrs[2];
1682 struct ldb_result *res;
1685 attrs[0] = attribute;
1688 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1689 if (ret != LDB_SUCCESS) {
1693 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1695 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1696 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1697 ldb_dn_get_linearized(base));
1699 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1700 ldb_dn_get_linearized(base));
1703 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1711 find our machine account via the serverReference attribute in the
1714 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1716 struct ldb_dn *server_dn;
1719 server_dn = samdb_server_dn(ldb, mem_ctx);
1720 if (server_dn == NULL) {
1721 return LDB_ERR_NO_SUCH_OBJECT;
1724 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1725 talloc_free(server_dn);
1731 find the RID Manager$ DN via the rIDManagerReference attribute in the
1734 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1736 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1737 "rIDManagerReference", dn);
1741 find the RID Set DN via the rIDSetReferences attribute in our
1744 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1746 struct ldb_dn *server_ref_dn;
1749 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1750 if (ret != LDB_SUCCESS) {
1753 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1754 talloc_free(server_ref_dn);
1758 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1760 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1767 return (const char *) val->data;
1771 * Finds the client site by using the client's IP address.
1772 * The "subnet_name" returns the name of the subnet if parameter != NULL
1774 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1775 const char *ip_address, char **subnet_name)
1777 const char *attrs[] = { "cn", "siteObject", NULL };
1778 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1779 struct ldb_result *res;
1780 const struct ldb_val *val;
1781 const char *site_name = NULL, *l_subnet_name = NULL;
1782 const char *allow_list[2] = { NULL, NULL };
1783 unsigned int i, count;
1787 * if we don't have a client ip e.g. ncalrpc
1788 * the server site is the client site
1790 if (ip_address == NULL) {
1791 return samdb_server_site_name(ldb, mem_ctx);
1794 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1795 if (sites_container_dn == NULL) {
1799 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1800 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1801 talloc_free(sites_container_dn);
1802 talloc_free(subnets_dn);
1806 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1808 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1810 } else if (ret != LDB_SUCCESS) {
1811 talloc_free(sites_container_dn);
1812 talloc_free(subnets_dn);
1818 for (i = 0; i < count; i++) {
1819 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1822 allow_list[0] = l_subnet_name;
1824 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1825 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1828 if (sites_dn == NULL) {
1829 /* No reference, maybe another subnet matches */
1833 /* "val" cannot be NULL here since "sites_dn" != NULL */
1834 val = ldb_dn_get_rdn_val(sites_dn);
1835 site_name = talloc_strdup(mem_ctx,
1836 (const char *) val->data);
1838 talloc_free(sites_dn);
1844 if (site_name == NULL) {
1845 /* This is the Windows Server fallback rule: when no subnet
1846 * exists and we have only one site available then use it (it
1847 * is for sure the same as our server site). If more sites do
1848 * exist then we don't know which one to use and set the site
1850 cnt = samdb_search_count(ldb, sites_container_dn,
1851 "(objectClass=site)");
1853 site_name = samdb_server_site_name(ldb, mem_ctx);
1855 site_name = talloc_strdup(mem_ctx, "");
1857 l_subnet_name = NULL;
1860 if (subnet_name != NULL) {
1861 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1864 talloc_free(sites_container_dn);
1865 talloc_free(subnets_dn);
1872 work out if we are the PDC for the domain of the current open ldb
1874 bool samdb_is_pdc(struct ldb_context *ldb)
1876 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1878 struct ldb_result *dom_res;
1879 TALLOC_CTX *tmp_ctx;
1883 tmp_ctx = talloc_new(ldb);
1884 if (tmp_ctx == NULL) {
1885 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1889 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1890 if (ret != LDB_SUCCESS) {
1891 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1892 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1893 ldb_errstring(ldb)));
1896 if (dom_res->count != 1) {
1900 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1902 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1908 talloc_free(tmp_ctx);
1913 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1914 talloc_free(tmp_ctx);
1919 work out if we are a Global Catalog server for the domain of the current open ldb
1921 bool samdb_is_gc(struct ldb_context *ldb)
1923 const char *attrs[] = { "options", NULL };
1925 struct ldb_result *res;
1926 TALLOC_CTX *tmp_ctx;
1928 tmp_ctx = talloc_new(ldb);
1929 if (tmp_ctx == NULL) {
1930 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1934 /* Query cn=ntds settings,.... */
1935 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1936 if (ret != LDB_SUCCESS) {
1937 talloc_free(tmp_ctx);
1940 if (res->count != 1) {
1941 talloc_free(tmp_ctx);
1945 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1946 talloc_free(tmp_ctx);
1948 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1949 if (options & 0x000000001) {
1955 /* Find a domain object in the parents of a particular DN. */
1956 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1957 struct ldb_dn **parent_dn, const char **errstring)
1959 TALLOC_CTX *local_ctx;
1960 struct ldb_dn *sdn = dn;
1961 struct ldb_result *res = NULL;
1962 int ret = LDB_SUCCESS;
1963 const char *attrs[] = { NULL };
1965 local_ctx = talloc_new(mem_ctx);
1966 if (local_ctx == NULL) return ldb_oom(ldb);
1968 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1969 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1970 "(|(objectClass=domain)(objectClass=builtinDomain))");
1971 if (ret == LDB_SUCCESS) {
1972 if (res->count == 1) {
1980 if (ret != LDB_SUCCESS) {
1981 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1982 ldb_dn_get_linearized(dn),
1983 ldb_dn_get_linearized(sdn),
1984 ldb_errstring(ldb));
1985 talloc_free(local_ctx);
1988 if (res->count != 1) {
1989 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1990 ldb_dn_get_linearized(dn));
1991 DEBUG(0,(__location__ ": %s\n", *errstring));
1992 talloc_free(local_ctx);
1993 return LDB_ERR_CONSTRAINT_VIOLATION;
1996 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1997 talloc_free(local_ctx);
2003 * Performs checks on a user password (plaintext UNIX format - attribute
2004 * "password"). The remaining parameters have to be extracted from the domain
2007 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2009 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2010 const uint32_t pwdProperties,
2011 const uint32_t minPwdLength)
2013 /* checks if the "minPwdLength" property is satisfied */
2014 if (minPwdLength > password->length)
2015 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2017 /* checks the password complexity */
2018 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2019 && (password->data != NULL)
2020 && (!check_password_quality((const char *) password->data)))
2021 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2023 return SAMR_VALIDATION_STATUS_SUCCESS;
2027 * Callback for "samdb_set_password" password change
2029 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2034 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2037 if (ares->error != LDB_SUCCESS) {
2039 req->context = talloc_steal(req,
2040 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2042 return ldb_request_done(req, ret);
2045 if (ares->type != LDB_REPLY_DONE) {
2047 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2050 req->context = talloc_steal(req,
2051 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2053 return ldb_request_done(req, LDB_SUCCESS);
2057 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2058 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2059 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2060 * user change or not. The "rejectReason" gives some more informations if the
2063 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2064 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2066 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2067 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2068 const DATA_BLOB *new_password,
2069 const struct samr_Password *lmNewHash,
2070 const struct samr_Password *ntNewHash,
2071 const struct samr_Password *lmOldHash,
2072 const struct samr_Password *ntOldHash,
2073 enum samPwdChangeReason *reject_reason,
2074 struct samr_DomInfo1 **_dominfo)
2076 struct ldb_message *msg;
2077 struct ldb_message_element *el;
2078 struct ldb_request *req;
2079 struct dsdb_control_password_change_status *pwd_stat = NULL;
2081 NTSTATUS status = NT_STATUS_OK;
2083 #define CHECK_RET(x) \
2084 if (x != LDB_SUCCESS) { \
2086 return NT_STATUS_NO_MEMORY; \
2089 msg = ldb_msg_new(mem_ctx);
2091 return NT_STATUS_NO_MEMORY;
2094 if ((new_password != NULL)
2095 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2096 /* we have the password as plaintext UTF16 */
2097 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2098 "clearTextPassword", new_password));
2099 el = ldb_msg_find_element(msg, "clearTextPassword");
2100 el->flags = LDB_FLAG_MOD_REPLACE;
2101 } else if ((new_password == NULL)
2102 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2103 /* we have a password as LM and/or NT hash */
2104 if (lmNewHash != NULL) {
2105 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2106 "dBCSPwd", lmNewHash));
2107 el = ldb_msg_find_element(msg, "dBCSPwd");
2108 el->flags = LDB_FLAG_MOD_REPLACE;
2110 if (ntNewHash != NULL) {
2111 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2112 "unicodePwd", ntNewHash));
2113 el = ldb_msg_find_element(msg, "unicodePwd");
2114 el->flags = LDB_FLAG_MOD_REPLACE;
2117 /* the password wasn't specified correctly */
2119 return NT_STATUS_INVALID_PARAMETER;
2122 /* build modify request */
2123 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2124 samdb_set_password_callback, NULL);
2125 if (ret != LDB_SUCCESS) {
2127 return NT_STATUS_NO_MEMORY;
2130 /* A password change operation */
2131 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2132 struct dsdb_control_password_change *change;
2134 change = talloc(req, struct dsdb_control_password_change);
2135 if (change == NULL) {
2138 return NT_STATUS_NO_MEMORY;
2141 change->old_nt_pwd_hash = ntOldHash;
2142 change->old_lm_pwd_hash = lmOldHash;
2144 ret = ldb_request_add_control(req,
2145 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2147 if (ret != LDB_SUCCESS) {
2150 return NT_STATUS_NO_MEMORY;
2153 ret = ldb_request_add_control(req,
2154 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2156 if (ret != LDB_SUCCESS) {
2159 return NT_STATUS_NO_MEMORY;
2161 ret = ldb_request_add_control(req,
2162 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2164 if (ret != LDB_SUCCESS) {
2167 return NT_STATUS_NO_MEMORY;
2170 ret = dsdb_autotransaction_request(ldb, req);
2172 if (req->context != NULL) {
2173 pwd_stat = talloc_steal(mem_ctx,
2174 ((struct ldb_control *)req->context)->data);
2180 /* Sets the domain info (if requested) */
2181 if (_dominfo != NULL) {
2182 struct samr_DomInfo1 *dominfo;
2184 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2185 if (dominfo == NULL) {
2186 return NT_STATUS_NO_MEMORY;
2189 if (pwd_stat != NULL) {
2190 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2191 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2192 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2193 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2194 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2197 *_dominfo = dominfo;
2200 if (reject_reason != NULL) {
2201 if (pwd_stat != NULL) {
2202 *reject_reason = pwd_stat->reject_reason;
2204 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2208 if (pwd_stat != NULL) {
2209 talloc_free(pwd_stat);
2212 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2213 const char *errmsg = ldb_errstring(ldb);
2214 char *endptr = NULL;
2215 WERROR werr = WERR_GENERAL_FAILURE;
2216 status = NT_STATUS_UNSUCCESSFUL;
2217 if (errmsg != NULL) {
2218 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2220 if (endptr != errmsg) {
2221 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2222 status = NT_STATUS_WRONG_PASSWORD;
2224 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2225 status = NT_STATUS_PASSWORD_RESTRICTION;
2228 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2229 /* don't let the caller know if an account doesn't exist */
2230 status = NT_STATUS_WRONG_PASSWORD;
2231 } else if (ret != LDB_SUCCESS) {
2232 status = NT_STATUS_UNSUCCESSFUL;
2239 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2240 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2241 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2242 * user change or not. The "rejectReason" gives some more informations if the
2245 * This wrapper function for "samdb_set_password" takes a SID as input rather
2248 * This call encapsulates a new LDB transaction for changing the password;
2249 * therefore the user hasn't to start a new one.
2251 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2252 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2253 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2254 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2256 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2257 const struct dom_sid *user_sid,
2258 const DATA_BLOB *new_password,
2259 const struct samr_Password *lmNewHash,
2260 const struct samr_Password *ntNewHash,
2261 const struct samr_Password *lmOldHash,
2262 const struct samr_Password *ntOldHash,
2263 enum samPwdChangeReason *reject_reason,
2264 struct samr_DomInfo1 **_dominfo)
2267 struct ldb_dn *user_dn;
2270 ret = ldb_transaction_start(ldb);
2271 if (ret != LDB_SUCCESS) {
2272 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2273 return NT_STATUS_TRANSACTION_ABORTED;
2276 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2277 "(&(objectSid=%s)(objectClass=user))",
2278 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2280 ldb_transaction_cancel(ldb);
2281 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2282 dom_sid_string(mem_ctx, user_sid)));
2283 return NT_STATUS_NO_SUCH_USER;
2286 nt_status = samdb_set_password(ldb, mem_ctx,
2289 lmNewHash, ntNewHash,
2290 lmOldHash, ntOldHash,
2291 reject_reason, _dominfo);
2292 if (!NT_STATUS_IS_OK(nt_status)) {
2293 ldb_transaction_cancel(ldb);
2294 talloc_free(user_dn);
2298 ret = ldb_transaction_commit(ldb);
2299 if (ret != LDB_SUCCESS) {
2300 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2301 ldb_dn_get_linearized(user_dn),
2302 ldb_errstring(ldb)));
2303 talloc_free(user_dn);
2304 return NT_STATUS_TRANSACTION_ABORTED;
2307 talloc_free(user_dn);
2308 return NT_STATUS_OK;
2312 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2313 struct dom_sid *sid, struct ldb_dn **ret_dn)
2315 struct ldb_message *msg;
2316 struct ldb_dn *basedn;
2320 sidstr = dom_sid_string(mem_ctx, sid);
2321 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2323 /* We might have to create a ForeignSecurityPrincipal, even if this user
2324 * is in our own domain */
2326 msg = ldb_msg_new(sidstr);
2328 talloc_free(sidstr);
2329 return NT_STATUS_NO_MEMORY;
2332 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2333 ldb_get_default_basedn(sam_ctx),
2334 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2336 if (ret != LDB_SUCCESS) {
2337 DEBUG(0, ("Failed to find DN for "
2338 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2339 talloc_free(sidstr);
2340 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2343 /* add core elements to the ldb_message for the alias */
2345 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2346 talloc_free(sidstr);
2347 return NT_STATUS_NO_MEMORY;
2350 samdb_msg_add_string(sam_ctx, msg, msg,
2352 "foreignSecurityPrincipal");
2354 /* create the alias */
2355 ret = ldb_add(sam_ctx, msg);
2356 if (ret != LDB_SUCCESS) {
2357 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2359 ldb_dn_get_linearized(msg->dn),
2360 ldb_errstring(sam_ctx)));
2361 talloc_free(sidstr);
2362 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2365 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2366 talloc_free(sidstr);
2368 return NT_STATUS_OK;
2373 Find the DN of a domain, assuming it to be a dotted.dns name
2376 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2379 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2380 const char *binary_encoded;
2381 const char **split_realm;
2388 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2390 talloc_free(tmp_ctx);
2393 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2394 for (i=0; split_realm[i]; i++) {
2395 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2396 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2397 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2398 binary_encoded, ldb_dn_get_linearized(dn)));
2399 talloc_free(tmp_ctx);
2403 if (!ldb_dn_validate(dn)) {
2404 DEBUG(2, ("Failed to validated DN %s\n",
2405 ldb_dn_get_linearized(dn)));
2406 talloc_free(tmp_ctx);
2409 talloc_free(tmp_ctx);
2414 Find the DN of a domain, be it the netbios or DNS name
2416 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2417 const char *domain_name)
2419 const char * const domain_ref_attrs[] = {
2422 const char * const domain_ref2_attrs[] = {
2425 struct ldb_result *res_domain_ref;
2426 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2427 /* find the domain's DN */
2428 int ret_domain = ldb_search(ldb, mem_ctx,
2430 samdb_partitions_dn(ldb, mem_ctx),
2433 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2435 if (ret_domain != LDB_SUCCESS) {
2439 if (res_domain_ref->count == 0) {
2440 ret_domain = ldb_search(ldb, mem_ctx,
2442 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2445 "(objectclass=domain)");
2446 if (ret_domain != LDB_SUCCESS) {
2450 if (res_domain_ref->count == 1) {
2451 return res_domain_ref->msgs[0]->dn;
2456 if (res_domain_ref->count > 1) {
2457 DEBUG(0,("Found %d records matching domain [%s]\n",
2458 ret_domain, domain_name));
2462 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2468 use a GUID to find a DN
2470 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2471 TALLOC_CTX *mem_ctx,
2472 const struct GUID *guid, struct ldb_dn **dn)
2475 struct ldb_result *res;
2476 const char *attrs[] = { NULL };
2477 char *guid_str = GUID_string(mem_ctx, guid);
2480 return ldb_operr(ldb);
2483 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2484 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2485 DSDB_SEARCH_SHOW_EXTENDED_DN |
2486 DSDB_SEARCH_ONE_ONLY,
2487 "objectGUID=%s", guid_str);
2488 talloc_free(guid_str);
2489 if (ret != LDB_SUCCESS) {
2493 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2500 use a DN to find a GUID with a given attribute name
2502 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2503 struct ldb_dn *dn, const char *attribute,
2507 struct ldb_result *res;
2508 const char *attrs[2];
2509 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2511 attrs[0] = attribute;
2514 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2515 DSDB_SEARCH_SHOW_DELETED |
2516 DSDB_SEARCH_SHOW_RECYCLED);
2517 if (ret != LDB_SUCCESS) {
2518 talloc_free(tmp_ctx);
2521 if (res->count < 1) {
2522 talloc_free(tmp_ctx);
2523 return LDB_ERR_NO_SUCH_OBJECT;
2525 *guid = samdb_result_guid(res->msgs[0], attribute);
2526 talloc_free(tmp_ctx);
2531 use a DN to find a GUID
2533 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2534 struct ldb_dn *dn, struct GUID *guid)
2536 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2542 adds the given GUID to the given ldb_message. This value is added
2543 for the given attr_name (may be either "objectGUID" or "parentGUID").
2545 int dsdb_msg_add_guid(struct ldb_message *msg,
2547 const char *attr_name)
2552 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2554 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 ret = LDB_ERR_OPERATIONS_ERROR;
2560 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2561 if (ret != LDB_SUCCESS) {
2562 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2570 talloc_free(tmp_ctx);
2577 use a DN to find a SID
2579 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2580 struct ldb_dn *dn, struct dom_sid *sid)
2583 struct ldb_result *res;
2584 const char *attrs[] = { "objectSid", NULL };
2585 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2590 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2591 DSDB_SEARCH_SHOW_DELETED |
2592 DSDB_SEARCH_SHOW_RECYCLED);
2593 if (ret != LDB_SUCCESS) {
2594 talloc_free(tmp_ctx);
2597 if (res->count < 1) {
2598 talloc_free(tmp_ctx);
2599 return LDB_ERR_NO_SUCH_OBJECT;
2601 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2603 talloc_free(tmp_ctx);
2604 return LDB_ERR_NO_SUCH_OBJECT;
2607 talloc_free(tmp_ctx);
2612 use a SID to find a DN
2614 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2615 TALLOC_CTX *mem_ctx,
2616 struct dom_sid *sid, struct ldb_dn **dn)
2619 struct ldb_result *res;
2620 const char *attrs[] = { NULL };
2621 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2624 return ldb_operr(ldb);
2627 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2628 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2629 DSDB_SEARCH_SHOW_EXTENDED_DN |
2630 DSDB_SEARCH_ONE_ONLY,
2631 "objectSid=%s", sid_str);
2632 talloc_free(sid_str);
2633 if (ret != LDB_SUCCESS) {
2637 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2644 load a repsFromTo blob list for a given partition GUID
2645 attr must be "repsFrom" or "repsTo"
2647 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2648 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2650 const char *attrs[] = { attr, NULL };
2651 struct ldb_result *res = NULL;
2652 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2654 struct ldb_message_element *el;
2659 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2661 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2662 talloc_free(tmp_ctx);
2663 return WERR_DS_DRA_INTERNAL_ERROR;
2666 el = ldb_msg_find_element(res->msgs[0], attr);
2668 /* it's OK to be empty */
2669 talloc_free(tmp_ctx);
2673 *count = el->num_values;
2674 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2676 talloc_free(tmp_ctx);
2677 return WERR_DS_DRA_INTERNAL_ERROR;
2680 for (i=0; i<(*count); i++) {
2681 enum ndr_err_code ndr_err;
2682 ndr_err = ndr_pull_struct_blob(&el->values[i],
2685 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2686 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2687 talloc_free(tmp_ctx);
2688 return WERR_DS_DRA_INTERNAL_ERROR;
2692 talloc_free(tmp_ctx);
2698 save the repsFromTo blob list for a given partition GUID
2699 attr must be "repsFrom" or "repsTo"
2701 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2702 const char *attr, struct repsFromToBlob *r, uint32_t count)
2704 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2705 struct ldb_message *msg;
2706 struct ldb_message_element *el;
2709 msg = ldb_msg_new(tmp_ctx);
2711 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2715 el->values = talloc_array(msg, struct ldb_val, count);
2720 for (i=0; i<count; i++) {
2722 enum ndr_err_code ndr_err;
2724 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2726 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2735 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2736 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2740 talloc_free(tmp_ctx);
2745 talloc_free(tmp_ctx);
2746 return WERR_DS_DRA_INTERNAL_ERROR;
2751 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2752 object for a partition
2754 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2755 uint64_t *uSN, uint64_t *urgent_uSN)
2757 struct ldb_request *req;
2759 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2760 struct dsdb_control_current_partition *p_ctrl;
2761 struct ldb_result *res;
2763 res = talloc_zero(tmp_ctx, struct ldb_result);
2765 talloc_free(tmp_ctx);
2766 return ldb_oom(ldb);
2769 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2770 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2774 res, ldb_search_default_callback,
2776 if (ret != LDB_SUCCESS) {
2777 talloc_free(tmp_ctx);
2781 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2782 if (p_ctrl == NULL) {
2783 talloc_free(tmp_ctx);
2784 return ldb_oom(ldb);
2786 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2789 ret = ldb_request_add_control(req,
2790 DSDB_CONTROL_CURRENT_PARTITION_OID,
2792 if (ret != LDB_SUCCESS) {
2793 talloc_free(tmp_ctx);
2797 /* Run the new request */
2798 ret = ldb_request(ldb, req);
2800 if (ret == LDB_SUCCESS) {
2801 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2804 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2805 /* it hasn't been created yet, which means
2806 an implicit value of zero */
2808 talloc_free(tmp_ctx);
2812 if (ret != LDB_SUCCESS) {
2813 talloc_free(tmp_ctx);
2817 if (res->count < 1) {
2823 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2825 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2829 talloc_free(tmp_ctx);
2834 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2835 const struct drsuapi_DsReplicaCursor2 *c2)
2837 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2840 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2841 const struct drsuapi_DsReplicaCursor *c2)
2843 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2848 see if a computer identified by its invocationId is a RODC
2850 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2852 /* 1) find the DN for this servers NTDSDSA object
2853 2) search for the msDS-isRODC attribute
2854 3) if not present then not a RODC
2855 4) if present and TRUE then is a RODC
2857 struct ldb_dn *config_dn;
2858 const char *attrs[] = { "msDS-isRODC", NULL };
2860 struct ldb_result *res;
2861 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2863 config_dn = ldb_get_config_basedn(sam_ctx);
2865 talloc_free(tmp_ctx);
2866 return ldb_operr(sam_ctx);
2869 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2870 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2872 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2874 talloc_free(tmp_ctx);
2878 if (ret != LDB_SUCCESS) {
2879 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2880 GUID_string(tmp_ctx, objectGUID)));
2882 talloc_free(tmp_ctx);
2886 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2887 *is_rodc = (ret == 1);
2889 talloc_free(tmp_ctx);
2895 see if we are a RODC
2897 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2899 const struct GUID *objectGUID;
2903 /* see if we have a cached copy */
2904 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2910 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2912 return ldb_operr(sam_ctx);
2915 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2916 if (ret != LDB_SUCCESS) {
2920 cached = talloc(sam_ctx, bool);
2921 if (cached == NULL) {
2922 return ldb_oom(sam_ctx);
2926 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2927 if (ret != LDB_SUCCESS) {
2928 talloc_free(cached);
2929 return ldb_operr(sam_ctx);
2935 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2937 TALLOC_CTX *tmp_ctx;
2940 tmp_ctx = talloc_new(ldb);
2941 if (tmp_ctx == NULL) {
2945 cached = talloc(tmp_ctx, bool);
2951 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2955 talloc_steal(ldb, cached);
2956 talloc_free(tmp_ctx);
2960 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2961 talloc_free(tmp_ctx);
2967 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2969 flags are DS_NTDS_OPTION_*
2971 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2973 TALLOC_CTX *tmp_ctx;
2974 const char *attrs[] = { "options", NULL };
2976 struct ldb_result *res;
2978 tmp_ctx = talloc_new(ldb);
2979 if (tmp_ctx == NULL) {
2983 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2984 if (ret != LDB_SUCCESS) {
2988 if (res->count != 1) {
2992 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
2994 talloc_free(tmp_ctx);
2999 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3000 talloc_free(tmp_ctx);
3001 return LDB_ERR_NO_SUCH_OBJECT;
3004 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3006 const char *attrs[] = { "objectCategory", NULL };
3008 struct ldb_result *res;
3010 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3011 if (ret != LDB_SUCCESS) {
3015 if (res->count != 1) {
3019 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3022 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3027 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3028 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3030 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3032 char **tokens, *ret;
3035 tokens = str_list_make(mem_ctx, cn, " -_");
3039 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3040 tokens[0][0] = tolower(tokens[0][0]);
3041 for (i = 1; i < str_list_length((const char **)tokens); i++)
3042 tokens[i][0] = toupper(tokens[i][0]);
3044 ret = talloc_strdup(mem_ctx, tokens[0]);
3045 for (i = 1; i < str_list_length((const char **)tokens); i++)
3046 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3048 talloc_free(tokens);
3054 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3056 int dsdb_functional_level(struct ldb_context *ldb)
3058 int *domainFunctionality =
3059 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3060 if (!domainFunctionality) {
3061 /* this is expected during initial provision */
3062 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3063 return DS_DOMAIN_FUNCTION_2000;
3065 return *domainFunctionality;
3069 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3071 int dsdb_forest_functional_level(struct ldb_context *ldb)
3073 int *forestFunctionality =
3074 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3075 if (!forestFunctionality) {
3076 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3077 return DS_DOMAIN_FUNCTION_2000;
3079 return *forestFunctionality;
3083 set a GUID in an extended DN structure
3085 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3091 status = GUID_to_ndr_blob(guid, dn, &v);
3092 if (!NT_STATUS_IS_OK(status)) {
3093 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3096 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3102 return a GUID from a extended DN structure
3104 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3106 const struct ldb_val *v;
3108 v = ldb_dn_get_extended_component(dn, component_name);
3110 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3113 return GUID_from_ndr_blob(v, guid);
3117 return a uint64_t from a extended DN structure
3119 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3121 const struct ldb_val *v;
3124 v = ldb_dn_get_extended_component(dn, component_name);
3126 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3128 s = talloc_strndup(dn, (const char *)v->data, v->length);
3129 NT_STATUS_HAVE_NO_MEMORY(s);
3131 *val = strtoull(s, NULL, 0);
3134 return NT_STATUS_OK;
3138 return a NTTIME from a extended DN structure
3140 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3142 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3146 return a uint32_t from a extended DN structure
3148 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3150 const struct ldb_val *v;
3153 v = ldb_dn_get_extended_component(dn, component_name);
3155 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3158 s = talloc_strndup(dn, (const char *)v->data, v->length);
3159 NT_STATUS_HAVE_NO_MEMORY(s);
3161 *val = strtoul(s, NULL, 0);
3164 return NT_STATUS_OK;
3168 return a dom_sid from a extended DN structure
3170 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3172 const struct ldb_val *sid_blob;
3173 struct TALLOC_CTX *tmp_ctx;
3174 enum ndr_err_code ndr_err;
3176 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3178 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3181 tmp_ctx = talloc_new(NULL);
3183 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3184 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3186 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3187 talloc_free(tmp_ctx);
3191 talloc_free(tmp_ctx);
3192 return NT_STATUS_OK;
3197 return RMD_FLAGS directly from a ldb_dn
3198 returns 0 if not found
3200 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3202 const struct ldb_val *v;
3204 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3205 if (!v || v->length > sizeof(buf)-1) return 0;
3206 strncpy(buf, (const char *)v->data, v->length);
3208 return strtoul(buf, NULL, 10);
3212 return RMD_FLAGS directly from a ldb_val for a DN
3213 returns 0 if RMD_FLAGS is not found
3215 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3221 if (val->length < 13) {
3224 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3228 flags = strtoul(p+11, &end, 10);
3229 if (!end || *end != '>') {
3230 /* it must end in a > */
3237 return true if a ldb_val containing a DN in storage form is deleted
3239 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3241 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3245 return true if a ldb_val containing a DN in storage form is
3246 in the upgraded w2k3 linked attribute format
3248 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3250 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3254 return a DN for a wellknown GUID
3256 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3257 struct ldb_dn *nc_root, const char *wk_guid,
3258 struct ldb_dn **wkguid_dn)
3260 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3261 const char *attrs[] = { NULL };
3264 struct ldb_result *res;
3266 /* construct the magic WKGUID DN */
3267 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3268 wk_guid, ldb_dn_get_linearized(nc_root));
3270 talloc_free(tmp_ctx);
3271 return ldb_operr(samdb);
3274 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3275 DSDB_SEARCH_SHOW_DELETED |
3276 DSDB_SEARCH_SHOW_RECYCLED);
3277 if (ret != LDB_SUCCESS) {
3278 talloc_free(tmp_ctx);
3282 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3283 talloc_free(tmp_ctx);
3288 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3290 return ldb_dn_compare(*dn1, *dn2);
3294 find a NC root given a DN within the NC
3296 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3297 struct ldb_dn **nc_root)
3299 const char *root_attrs[] = { "namingContexts", NULL };
3300 TALLOC_CTX *tmp_ctx;
3302 struct ldb_message_element *el;
3303 struct ldb_result *root_res;
3305 struct ldb_dn **nc_dns;
3307 tmp_ctx = talloc_new(samdb);
3308 if (tmp_ctx == NULL) {
3309 return ldb_oom(samdb);
3312 ret = ldb_search(samdb, tmp_ctx, &root_res,
3313 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3314 if (ret != LDB_SUCCESS) {
3315 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3316 talloc_free(tmp_ctx);
3320 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3322 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3323 ldb_errstring(samdb)));
3324 talloc_free(tmp_ctx);
3325 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3328 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3330 talloc_free(tmp_ctx);
3331 return ldb_oom(samdb);
3334 for (i=0; i<el->num_values; i++) {
3335 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3336 if (nc_dns[i] == NULL) {
3337 talloc_free(tmp_ctx);
3338 return ldb_operr(samdb);
3342 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3344 for (i=0; i<el->num_values; i++) {
3345 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3346 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3347 talloc_free(tmp_ctx);
3352 talloc_free(tmp_ctx);
3353 return LDB_ERR_NO_SUCH_OBJECT;
3358 find the deleted objects DN for any object, by looking for the NC
3359 root, then looking up the wellknown GUID
3361 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3362 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3363 struct ldb_dn **do_dn)
3365 struct ldb_dn *nc_root;
3368 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3369 if (ret != LDB_SUCCESS) {
3373 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3374 talloc_free(nc_root);
3379 return the tombstoneLifetime, in days
3381 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3384 dn = ldb_get_config_basedn(ldb);
3386 return LDB_ERR_NO_SUCH_OBJECT;
3388 dn = ldb_dn_copy(ldb, dn);
3390 return ldb_operr(ldb);
3392 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3393 be a wellknown GUID for this */
3394 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3396 return ldb_operr(ldb);
3399 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3405 compare a ldb_val to a string case insensitively
3407 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3409 size_t len = strlen(s);
3411 if (len > v->length) return 1;
3412 ret = strncasecmp(s, (const char *)v->data, v->length);
3413 if (ret != 0) return ret;
3414 if (v->length > len && v->data[len] != 0) {
3422 load the UDV for a partition in v2 format
3423 The list is returned sorted, and with our local cursor added
3425 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3426 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3428 static const char *attrs[] = { "replUpToDateVector", NULL };
3429 struct ldb_result *r;
3430 const struct ldb_val *ouv_value;
3433 uint64_t highest_usn;
3434 const struct GUID *our_invocation_id;
3435 struct timeval now = timeval_current();
3437 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3438 if (ret != LDB_SUCCESS) {
3442 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3444 enum ndr_err_code ndr_err;
3445 struct replUpToDateVectorBlob ouv;
3447 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3448 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3449 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3451 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3453 if (ouv.version != 2) {
3454 /* we always store as version 2, and
3455 * replUpToDateVector is not replicated
3457 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3460 *count = ouv.ctr.ctr2.count;
3461 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3469 our_invocation_id = samdb_ntds_invocation_id(samdb);
3470 if (!our_invocation_id) {
3471 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3472 talloc_free(*cursors);
3473 return ldb_operr(samdb);
3476 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3477 if (ret != LDB_SUCCESS) {
3478 /* nothing to add - this can happen after a vampire */
3479 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3483 for (i=0; i<*count; i++) {
3484 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3485 (*cursors)[i].highest_usn = highest_usn;
3486 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3487 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3492 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3494 return ldb_oom(samdb);
3497 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3498 (*cursors)[*count].highest_usn = highest_usn;
3499 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3502 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3508 load the UDV for a partition in version 1 format
3509 The list is returned sorted, and with our local cursor added
3511 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3512 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3514 struct drsuapi_DsReplicaCursor2 *v2;
3518 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3519 if (ret != LDB_SUCCESS) {
3529 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3530 if (*cursors == NULL) {
3532 return ldb_oom(samdb);
3535 for (i=0; i<*count; i++) {
3536 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3537 (*cursors)[i].highest_usn = v2[i].highest_usn;
3544 add a set of controls to a ldb_request structure based on a set of
3545 flags. See util.h for a list of available flags
3547 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3550 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3551 struct ldb_search_options_control *options;
3552 /* Using the phantom root control allows us to search all partitions */
3553 options = talloc(req, struct ldb_search_options_control);
3554 if (options == NULL) {
3555 return LDB_ERR_OPERATIONS_ERROR;
3557 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3559 ret = ldb_request_add_control(req,
3560 LDB_CONTROL_SEARCH_OPTIONS_OID,
3562 if (ret != LDB_SUCCESS) {
3567 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3568 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3569 if (ret != LDB_SUCCESS) {
3574 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3575 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3576 if (ret != LDB_SUCCESS) {
3581 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3582 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3583 if (ret != LDB_SUCCESS) {
3588 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3589 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3590 if (!extended_ctrl) {
3591 return LDB_ERR_OPERATIONS_ERROR;
3593 extended_ctrl->type = 1;
3595 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3596 if (ret != LDB_SUCCESS) {
3601 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3602 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3603 if (ret != LDB_SUCCESS) {
3608 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3609 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3610 if (ret != LDB_SUCCESS) {
3615 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3616 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3617 if (ret != LDB_SUCCESS) {
3622 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3623 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3624 if (ret != LDB_SUCCESS) {
3629 if (dsdb_flags & DSDB_TREE_DELETE) {
3630 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3631 if (ret != LDB_SUCCESS) {
3640 an add with a set of controls
3642 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3643 uint32_t dsdb_flags)
3645 struct ldb_request *req;
3648 ret = ldb_build_add_req(&req, ldb, ldb,
3652 ldb_op_default_callback,
3655 if (ret != LDB_SUCCESS) return ret;
3657 ret = dsdb_request_add_controls(req, dsdb_flags);
3658 if (ret != LDB_SUCCESS) {
3663 ret = dsdb_autotransaction_request(ldb, req);
3670 a modify with a set of controls
3672 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3673 uint32_t dsdb_flags)
3675 struct ldb_request *req;
3678 ret = ldb_build_mod_req(&req, ldb, ldb,
3682 ldb_op_default_callback,
3685 if (ret != LDB_SUCCESS) return ret;
3687 ret = dsdb_request_add_controls(req, dsdb_flags);
3688 if (ret != LDB_SUCCESS) {
3693 ret = dsdb_autotransaction_request(ldb, req);
3700 like dsdb_modify() but set all the element flags to
3701 LDB_FLAG_MOD_REPLACE
3703 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3707 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3708 for (i=0;i<msg->num_elements;i++) {
3709 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3712 return dsdb_modify(ldb, msg, dsdb_flags);
3717 search for attrs on one DN, allowing for dsdb_flags controls
3719 int dsdb_search_dn(struct ldb_context *ldb,
3720 TALLOC_CTX *mem_ctx,
3721 struct ldb_result **_res,
3722 struct ldb_dn *basedn,
3723 const char * const *attrs,
3724 uint32_t dsdb_flags)
3727 struct ldb_request *req;
3728 struct ldb_result *res;
3730 res = talloc_zero(mem_ctx, struct ldb_result);
3732 return ldb_oom(ldb);
3735 ret = ldb_build_search_req(&req, ldb, res,
3742 ldb_search_default_callback,
3744 if (ret != LDB_SUCCESS) {
3749 ret = dsdb_request_add_controls(req, dsdb_flags);
3750 if (ret != LDB_SUCCESS) {
3755 ret = ldb_request(ldb, req);
3756 if (ret == LDB_SUCCESS) {
3757 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3761 if (ret != LDB_SUCCESS) {
3771 search for attrs on one DN, by the GUID of the DN, allowing for
3774 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3775 TALLOC_CTX *mem_ctx,
3776 struct ldb_result **_res,
3777 const struct GUID *guid,
3778 const char * const *attrs,
3779 uint32_t dsdb_flags)
3781 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3785 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3786 if (!ldb_dn_validate(dn)) {
3787 talloc_free(tmp_ctx);
3788 return LDB_ERR_INVALID_DN_SYNTAX;
3791 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3792 talloc_free(tmp_ctx);
3797 general search with dsdb_flags for controls
3799 int dsdb_search(struct ldb_context *ldb,
3800 TALLOC_CTX *mem_ctx,
3801 struct ldb_result **_res,
3802 struct ldb_dn *basedn,
3803 enum ldb_scope scope,
3804 const char * const *attrs,
3805 uint32_t dsdb_flags,
3806 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3809 struct ldb_request *req;
3810 struct ldb_result *res;
3812 char *expression = NULL;
3813 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3815 res = talloc_zero(tmp_ctx, struct ldb_result);
3817 talloc_free(tmp_ctx);
3818 return ldb_oom(ldb);
3822 va_start(ap, exp_fmt);
3823 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3827 talloc_free(tmp_ctx);
3828 return ldb_oom(ldb);
3832 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3839 ldb_search_default_callback,
3841 if (ret != LDB_SUCCESS) {
3842 talloc_free(tmp_ctx);
3846 ret = dsdb_request_add_controls(req, dsdb_flags);
3847 if (ret != LDB_SUCCESS) {
3848 talloc_free(tmp_ctx);
3849 ldb_reset_err_string(ldb);
3853 ret = ldb_request(ldb, req);
3854 if (ret == LDB_SUCCESS) {
3855 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3858 if (ret != LDB_SUCCESS) {
3859 talloc_free(tmp_ctx);
3863 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3864 if (res->count == 0) {
3865 talloc_free(tmp_ctx);
3866 ldb_reset_err_string(ldb);
3867 return LDB_ERR_NO_SUCH_OBJECT;
3869 if (res->count != 1) {
3870 talloc_free(tmp_ctx);
3871 ldb_reset_err_string(ldb);
3872 return LDB_ERR_CONSTRAINT_VIOLATION;
3876 *_res = talloc_steal(mem_ctx, res);
3877 talloc_free(tmp_ctx);
3884 general search with dsdb_flags for controls
3885 returns exactly 1 record or an error
3887 int dsdb_search_one(struct ldb_context *ldb,
3888 TALLOC_CTX *mem_ctx,
3889 struct ldb_message **msg,
3890 struct ldb_dn *basedn,
3891 enum ldb_scope scope,
3892 const char * const *attrs,
3893 uint32_t dsdb_flags,
3894 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3897 struct ldb_result *res;
3899 char *expression = NULL;
3900 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3902 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3904 res = talloc_zero(tmp_ctx, struct ldb_result);
3906 talloc_free(tmp_ctx);
3907 return ldb_oom(ldb);
3911 va_start(ap, exp_fmt);
3912 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3916 talloc_free(tmp_ctx);
3917 return ldb_oom(ldb);
3919 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3920 dsdb_flags, "%s", expression);
3922 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3926 if (ret != LDB_SUCCESS) {
3927 talloc_free(tmp_ctx);
3931 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3932 talloc_free(tmp_ctx);
3937 /* returns back the forest DNS name */
3938 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3940 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3941 ldb_get_root_basedn(ldb));
3944 if (forest_name == NULL) {
3948 p = strchr(forest_name, '/');
3957 validate that an DSA GUID belongs to the specified user sid.
3958 The user SID must be a domain controller account (either RODC or
3961 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3962 const struct GUID *dsa_guid,
3963 const struct dom_sid *sid)
3966 - find DN of record with the DSA GUID in the
3967 configuration partition (objectGUID)
3968 - remove "NTDS Settings" component from DN
3969 - do a base search on that DN for serverReference with
3971 - extract objectSid from resulting serverReference
3973 - check this sid matches the sid argument
3975 struct ldb_dn *config_dn;
3976 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3977 struct ldb_message *msg;
3978 const char *attrs1[] = { NULL };
3979 const char *attrs2[] = { "serverReference", NULL };
3981 struct ldb_dn *dn, *account_dn;
3982 struct dom_sid sid2;
3985 config_dn = ldb_get_config_basedn(ldb);
3987 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3988 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3989 if (ret != LDB_SUCCESS) {
3990 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3991 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3992 talloc_free(tmp_ctx);
3993 return ldb_operr(ldb);
3997 if (!ldb_dn_remove_child_components(dn, 1)) {
3998 talloc_free(tmp_ctx);
3999 return ldb_operr(ldb);
4002 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4003 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4004 "(objectClass=server)");
4005 if (ret != LDB_SUCCESS) {
4006 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4007 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4008 talloc_free(tmp_ctx);
4009 return ldb_operr(ldb);
4012 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4013 if (account_dn == NULL) {
4014 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4015 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4016 talloc_free(tmp_ctx);
4017 return ldb_operr(ldb);
4020 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4021 if (!NT_STATUS_IS_OK(status)) {
4022 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4023 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4024 talloc_free(tmp_ctx);
4025 return ldb_operr(ldb);
4028 if (!dom_sid_equal(sid, &sid2)) {
4029 /* someone is trying to spoof another account */
4030 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4031 GUID_string(tmp_ctx, dsa_guid),
4032 dom_sid_string(tmp_ctx, sid),
4033 dom_sid_string(tmp_ctx, &sid2)));
4034 talloc_free(tmp_ctx);
4035 return ldb_operr(ldb);
4038 talloc_free(tmp_ctx);
4042 static const char *secret_attributes[] = {
4045 "initialAuthIncoming",
4046 "initialAuthOutgoing",
4050 "supplementalCredentials",
4051 "trustAuthIncoming",
4052 "trustAuthOutgoing",
4058 check if the attribute belongs to the RODC filtered attribute set
4059 Note that attributes that are in the filtered attribute set are the
4060 ones that _are_ always sent to a RODC
4062 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4064 /* they never get secret attributes */
4065 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4069 /* they do get non-secret critical attributes */
4070 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4074 /* they do get non-secret attributes marked as being in the FAS */
4075 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4079 /* other attributes are denied */
4083 /* return fsmo role dn and role owner dn for a particular role*/
4084 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4085 struct ldb_context *ldb,
4087 struct ldb_dn **fsmo_role_dn,
4088 struct ldb_dn **role_owner_dn)
4092 case DREPL_NAMING_MASTER:
4093 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4094 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4095 if (ret != LDB_SUCCESS) {
4096 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4097 ldb_errstring(ldb)));
4098 talloc_free(tmp_ctx);
4099 return WERR_DS_DRA_INTERNAL_ERROR;
4102 case DREPL_INFRASTRUCTURE_MASTER:
4103 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4104 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4105 if (ret != LDB_SUCCESS) {
4106 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4107 ldb_errstring(ldb)));
4108 talloc_free(tmp_ctx);
4109 return WERR_DS_DRA_INTERNAL_ERROR;
4112 case DREPL_RID_MASTER:
4113 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4114 if (ret != LDB_SUCCESS) {
4115 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4116 talloc_free(tmp_ctx);
4117 return WERR_DS_DRA_INTERNAL_ERROR;
4120 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4121 if (ret != LDB_SUCCESS) {
4122 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4123 ldb_errstring(ldb)));
4124 talloc_free(tmp_ctx);
4125 return WERR_DS_DRA_INTERNAL_ERROR;
4128 case DREPL_SCHEMA_MASTER:
4129 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4130 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4131 if (ret != LDB_SUCCESS) {
4132 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4133 ldb_errstring(ldb)));
4134 talloc_free(tmp_ctx);
4135 return WERR_DS_DRA_INTERNAL_ERROR;
4138 case DREPL_PDC_MASTER:
4139 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4140 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4141 if (ret != LDB_SUCCESS) {
4142 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4143 ldb_errstring(ldb)));
4144 talloc_free(tmp_ctx);
4145 return WERR_DS_DRA_INTERNAL_ERROR;
4149 return WERR_DS_DRA_INTERNAL_ERROR;
4154 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4155 TALLOC_CTX *mem_ctx,
4156 struct ldb_dn *server_dn)
4159 struct ldb_result *res = NULL;
4160 const char * const attrs[] = { "dNSHostName", NULL};
4162 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4166 if (ldb_ret != LDB_SUCCESS) {
4167 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4168 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4172 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
4176 returns true if an attribute is in the filter,
4177 false otherwise, provided that attribute value is provided with the expression
4179 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4183 switch (tree->operation) {
4186 for (i=0;i<tree->u.list.num_elements;i++) {
4187 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4193 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4194 case LDB_OP_EQUALITY:
4195 case LDB_OP_GREATER:
4198 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4202 case LDB_OP_SUBSTRING:
4203 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4207 case LDB_OP_PRESENT:
4208 /* (attrname=*) is not filtered out */
4210 case LDB_OP_EXTENDED:
4211 if (tree->u.extended.attr &&
4212 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
4220 bool is_attr_in_list(const char * const * attrs, const char *attr)
4224 for (i = 0; attrs[i]; i++) {
4225 if (ldb_attr_cmp(attrs[i], attr) == 0)