2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "dsdb/samdb/ldb_modules/util.h"
46 #include "librpc/gen_ndr/irpc.h"
49 search the sam for the specified attributes in a specific domain, filter on
50 objectSid being in domain_sid.
52 int samdb_search_domain(struct ldb_context *sam_ldb,
54 struct ldb_dn *basedn,
55 struct ldb_message ***res,
56 const char * const *attrs,
57 const struct dom_sid *domain_sid,
58 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
64 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
65 res, attrs, format, ap);
71 struct dom_sid *entry_sid;
73 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
75 if ((entry_sid == NULL) ||
76 (!dom_sid_in_domain(domain_sid, entry_sid))) {
77 /* Delete that entry from the result set */
78 (*res)[i] = (*res)[count-1];
80 talloc_free(entry_sid);
83 talloc_free(entry_sid);
91 search the sam for a single string attribute in exactly 1 record
93 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
95 struct ldb_dn *basedn,
96 const char *attr_name,
97 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
100 const char *attrs[2] = { NULL, NULL };
101 struct ldb_message **res = NULL;
103 attrs[0] = attr_name;
105 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
107 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
108 attr_name, format, count));
115 return samdb_result_string(res[0], attr_name, NULL);
119 search the sam for a single string attribute in exactly 1 record
121 const char *samdb_search_string(struct ldb_context *sam_ldb,
123 struct ldb_dn *basedn,
124 const char *attr_name,
125 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
130 va_start(ap, format);
131 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
137 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
139 struct ldb_dn *basedn,
140 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
144 struct ldb_message **res = NULL;
147 va_start(ap, format);
148 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
151 if (count != 1) return NULL;
153 ret = talloc_steal(mem_ctx, res[0]->dn);
160 search the sam for a dom_sid attribute in exactly 1 record
162 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
164 struct ldb_dn *basedn,
165 const char *attr_name,
166 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
170 struct ldb_message **res;
171 const char *attrs[2] = { NULL, NULL };
174 attrs[0] = attr_name;
176 va_start(ap, format);
177 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
180 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
181 attr_name, format, count));
187 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
193 return the count of the number of records in the sam matching the query
195 int samdb_search_count(struct ldb_context *sam_ldb,
196 struct ldb_dn *basedn,
197 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
200 struct ldb_message **res;
201 const char *attrs[] = { NULL };
203 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
205 va_start(ap, format);
206 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
208 talloc_free(tmp_ctx);
215 search the sam for a single integer attribute in exactly 1 record
217 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
219 unsigned int default_value,
220 struct ldb_dn *basedn,
221 const char *attr_name,
222 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
226 struct ldb_message **res;
227 const char *attrs[2] = { NULL, NULL };
229 attrs[0] = attr_name;
231 va_start(ap, format);
232 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
236 return default_value;
239 return samdb_result_uint(res[0], attr_name, default_value);
243 search the sam for a single signed 64 bit integer attribute in exactly 1 record
245 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
247 int64_t default_value,
248 struct ldb_dn *basedn,
249 const char *attr_name,
250 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
254 struct ldb_message **res;
255 const char *attrs[2] = { NULL, NULL };
257 attrs[0] = attr_name;
259 va_start(ap, format);
260 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
264 return default_value;
267 return samdb_result_int64(res[0], attr_name, default_value);
271 search the sam for multipe records each giving a single string attribute
272 return the number of matches, or -1 on error
274 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
276 struct ldb_dn *basedn,
278 const char *attr_name,
279 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
283 const char *attrs[2] = { NULL, NULL };
284 struct ldb_message **res = NULL;
286 attrs[0] = attr_name;
288 va_start(ap, format);
289 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
296 /* make sure its single valued */
297 for (i=0;i<count;i++) {
298 if (res[i]->num_elements != 1) {
299 DEBUG(1,("samdb: search for %s %s not single valued\n",
306 *strs = talloc_array(mem_ctx, const char *, count+1);
312 for (i=0;i<count;i++) {
313 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
315 (*strs)[count] = NULL;
321 pull a uint from a result set.
323 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
325 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
329 pull a (signed) int64 from a result set.
331 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
333 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
337 pull a string from a result set.
339 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
340 const char *default_value)
342 return ldb_msg_find_attr_as_string(msg, attr, default_value);
345 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
346 const char *attr, struct ldb_dn *default_value)
348 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
350 return default_value;
356 pull a rid from a objectSid in a result set.
358 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
359 const char *attr, uint32_t default_value)
364 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
366 return default_value;
368 rid = sid->sub_auths[sid->num_auths-1];
374 pull a dom_sid structure from a objectSid in a result set.
376 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
379 const struct ldb_val *v;
381 enum ndr_err_code ndr_err;
382 v = ldb_msg_find_ldb_val(msg, attr);
386 sid = talloc(mem_ctx, struct dom_sid);
390 ndr_err = ndr_pull_struct_blob(v, sid, sid,
391 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
400 pull a guid structure from a objectGUID in a result set.
402 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
404 const struct ldb_val *v;
408 v = ldb_msg_find_ldb_val(msg, attr);
409 if (!v) return GUID_zero();
411 status = GUID_from_ndr_blob(v, &guid);
412 if (!NT_STATUS_IS_OK(status)) {
420 pull a sid prefix from a objectSid in a result set.
421 this is used to find the domain sid for a user
423 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
426 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
427 if (!sid || sid->num_auths < 1) return NULL;
433 pull a NTTIME in a result set.
435 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
436 NTTIME default_value)
438 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
442 * Windows stores 0 for lastLogoff.
443 * But when a MS DC return the lastLogoff (as Logoff Time)
444 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
445 * cause windows 2008 and newer version to fail for SMB requests
447 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
449 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
452 ret = 0x7FFFFFFFFFFFFFFFULL;
458 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
459 * indicate an account doesn't expire.
461 * When Windows initially creates an account, it sets
462 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
463 * when changing from an account having a specific expiration date to
464 * that account never expiring, it sets accountExpires = 0.
466 * Consolidate that logic here to allow clearer logic for account expiry in
467 * the rest of the code.
469 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
471 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
475 ret = 0x7FFFFFFFFFFFFFFFULL;
481 pull a uint64_t from a result set.
483 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
484 uint64_t default_value)
486 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
491 construct the allow_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
496 struct ldb_dn *domain_dn,
497 struct ldb_message *msg,
500 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
503 if (attr_time == 0) {
507 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
509 /* yes, this is a -= not a += as minPwdAge is stored as the negative
510 of the number of 100-nano-seconds */
511 attr_time -= minPwdAge;
517 construct the force_password_change field from the PwdLastSet
518 attribute, the userAccountControl and the domain password settings
520 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
522 struct ldb_dn *domain_dn,
523 struct ldb_message *msg)
525 int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
526 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
527 "userAccountControl",
531 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
532 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
533 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
534 return 0x7FFFFFFFFFFFFFFFULL;
537 if (attr_time == 0) {
540 if (attr_time == -1) {
541 return 0x7FFFFFFFFFFFFFFFULL;
544 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
546 if (maxPwdAge == 0) {
547 return 0x7FFFFFFFFFFFFFFFULL;
549 attr_time -= maxPwdAge;
556 pull a samr_Password structutre from a result set.
558 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
560 struct samr_Password *hash = NULL;
561 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
562 if (val && (val->length >= sizeof(hash->hash))) {
563 hash = talloc(mem_ctx, struct samr_Password);
564 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
570 pull an array of samr_Password structures from a result set.
572 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
573 const char *attr, struct samr_Password **hashes)
575 unsigned int count, i;
576 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
582 count = val->length / 16;
587 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
592 for (i=0;i<count;i++) {
593 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
599 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
600 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
602 struct samr_Password *lmPwdHash, *ntPwdHash;
605 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
608 } else if (num_nt > 1) {
609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
611 *nt_pwd = &ntPwdHash[0];
615 /* Ensure that if we have turned off LM
616 * authentication, that we never use the LM hash, even
618 if (lpcfg_lanman_auth(lp_ctx)) {
620 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
623 } else if (num_lm > 1) {
624 return NT_STATUS_INTERNAL_DB_CORRUPTION;
626 *lm_pwd = &lmPwdHash[0];
636 pull a samr_LogonHours structutre from a result set.
638 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
640 struct samr_LogonHours hours;
641 size_t units_per_week = 168;
642 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
647 units_per_week = val->length * 8;
650 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
654 hours.units_per_week = units_per_week;
655 memset(hours.bits, 0xFF, units_per_week/8);
657 memcpy(hours.bits, val->data, val->length);
664 pull a set of account_flags from a result set.
666 This requires that the attributes:
671 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
672 struct ldb_message *msg, struct ldb_dn *domain_dn)
674 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
675 uint32_t acct_flags = ds_uf2acb(userAccountControl);
676 NTTIME must_change_time;
679 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
682 /* Test account expire time */
683 unix_to_nt_time(&now, time(NULL));
684 /* check for expired password */
685 if (must_change_time < now) {
686 acct_flags |= ACB_PW_EXPIRED;
691 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
692 struct ldb_message *msg,
695 struct lsa_BinaryString s;
696 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
704 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
708 s.length = s.size = val->length;
709 memcpy(s.array, val->data, val->length);
714 /* Find an attribute, with a particular value */
716 /* The current callers of this function expect a very specific
717 * behaviour: In particular, objectClass subclass equivilance is not
718 * wanted. This means that we should not lookup the schema for the
719 * comparison function */
720 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
721 const struct ldb_message *msg,
722 const char *name, const char *value)
725 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
731 for (i=0;i<el->num_values;i++) {
732 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
741 * This is intended for use by the "password hash" module since there
742 * password changes can be specified through one message element with the
743 * new password (to set) and another one with the old password (to unset).
745 * The first which sets a password (new value) can have flags
746 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
747 * for entries). The latter (old value) has always specified
748 * LDB_FLAG_MOD_DELETE.
750 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
751 * doesn't contain only one value (this is the Windows Server behaviour)
752 * otherwise LDB_SUCCESS.
754 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
756 const struct ldb_val **new_val,
757 const struct ldb_val **old_val)
768 for (i = 0; i < msg->num_elements; i++) {
769 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
770 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
771 *old_val = &msg->elements[i].values[0];
773 *new_val = &msg->elements[i].values[0];
781 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
783 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
784 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
789 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
791 struct ldb_message_element *el;
793 el = ldb_msg_find_element(msg, name);
798 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
804 add a string element to a message
806 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
807 const char *attr_name, const char *str)
809 char *s = talloc_strdup(mem_ctx, str);
810 char *a = talloc_strdup(mem_ctx, attr_name);
811 if (s == NULL || a == NULL) {
812 return ldb_oom(sam_ldb);
814 return ldb_msg_add_string(msg, a, s);
818 add a dom_sid element to a message
820 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, struct dom_sid *sid)
824 enum ndr_err_code ndr_err;
826 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
828 (ndr_push_flags_fn_t)ndr_push_dom_sid);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 return ldb_operr(sam_ldb);
832 return ldb_msg_add_value(msg, attr_name, &v, NULL);
837 add a delete element operation to a message
839 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name)
842 /* we use an empty replace rather than a delete, as it allows for
843 dsdb_replace() to be used everywhere */
844 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
848 add an add attribute value to a message or enhance an existing attribute
849 which has the same name and the add flag set.
851 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
852 struct ldb_message *msg, const char *attr_name,
855 struct ldb_message_element *el;
856 struct ldb_val val, *vals;
862 v = talloc_strdup(mem_ctx, value);
864 return ldb_oom(sam_ldb);
867 val.data = (uint8_t *) v;
868 val.length = strlen(v);
870 if (val.length == 0) {
871 /* allow empty strings as non-existent attributes */
875 for (i = 0; i < msg->num_elements; i++) {
876 el = &msg->elements[i];
877 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
878 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
884 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
886 if (ret != LDB_SUCCESS) {
891 vals = talloc_realloc(msg, el->values, struct ldb_val,
894 return ldb_oom(sam_ldb);
897 el->values[el->num_values] = val;
904 add a delete attribute value to a message or enhance an existing attribute
905 which has the same name and the delete flag set.
907 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
908 struct ldb_message *msg, const char *attr_name,
911 struct ldb_message_element *el;
912 struct ldb_val val, *vals;
918 v = talloc_strdup(mem_ctx, value);
920 return ldb_oom(sam_ldb);
923 val.data = (uint8_t *) v;
924 val.length = strlen(v);
926 if (val.length == 0) {
927 /* allow empty strings as non-existent attributes */
931 for (i = 0; i < msg->num_elements; i++) {
932 el = &msg->elements[i];
933 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
934 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
940 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
942 if (ret != LDB_SUCCESS) {
947 vals = talloc_realloc(msg, el->values, struct ldb_val,
950 return ldb_oom(sam_ldb);
953 el->values[el->num_values] = val;
960 add a int element to a message
962 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, int v)
965 const char *s = talloc_asprintf(mem_ctx, "%d", v);
966 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
970 add a unsigned int element to a message
972 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
973 const char *attr_name, unsigned int v)
975 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
979 add a (signed) int64_t element to a message
981 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
982 const char *attr_name, int64_t v)
984 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
985 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
989 add a uint64_t element to a message
991 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992 const char *attr_name, uint64_t v)
994 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
998 add a samr_Password element to a message
1000 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001 const char *attr_name, const struct samr_Password *hash)
1004 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1006 return ldb_oom(sam_ldb);
1009 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1013 add a samr_Password array to a message
1015 int samdb_msg_add_hashes(struct ldb_context *ldb,
1016 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1017 const char *attr_name, struct samr_Password *hashes,
1022 val.data = talloc_array_size(mem_ctx, 16, count);
1023 val.length = count*16;
1025 return ldb_oom(ldb);
1027 for (i=0;i<count;i++) {
1028 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1030 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1034 add a acct_flags element to a message
1036 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037 const char *attr_name, uint32_t v)
1039 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1043 add a logon_hours element to a message
1045 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1046 const char *attr_name, struct samr_LogonHours *hours)
1049 val.length = hours->units_per_week / 8;
1050 val.data = hours->bits;
1051 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1055 add a parameters element to a message
1057 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1058 const char *attr_name, struct lsa_BinaryString *parameters)
1061 val.length = parameters->length;
1062 val.data = (uint8_t *)parameters->array;
1063 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1066 add a general value element to a message
1068 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1069 const char *attr_name, const struct ldb_val *val)
1071 return ldb_msg_add_value(msg, attr_name, val, NULL);
1075 sets a general value element to a message
1077 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1078 const char *attr_name, const struct ldb_val *val)
1080 struct ldb_message_element *el;
1082 el = ldb_msg_find_element(msg, attr_name);
1086 return ldb_msg_add_value(msg, attr_name, val, NULL);
1090 set a string element in a message
1092 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1093 const char *attr_name, const char *str)
1095 struct ldb_message_element *el;
1097 el = ldb_msg_find_element(msg, attr_name);
1101 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1105 * Handle ldb_request in transaction
1107 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1108 struct ldb_request *req)
1112 ret = ldb_transaction_start(sam_ldb);
1113 if (ret != LDB_SUCCESS) {
1117 ret = ldb_request(sam_ldb, req);
1118 if (ret == LDB_SUCCESS) {
1119 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1122 if (ret == LDB_SUCCESS) {
1123 return ldb_transaction_commit(sam_ldb);
1125 ldb_transaction_cancel(sam_ldb);
1131 return a default security descriptor
1133 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1135 struct security_descriptor *sd;
1137 sd = security_descriptor_initialise(mem_ctx);
1142 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1144 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1145 struct ldb_dn *aggregate_dn;
1150 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1151 if (!aggregate_dn) {
1154 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1157 return aggregate_dn;
1160 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1162 struct ldb_dn *new_dn;
1164 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1165 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1166 talloc_free(new_dn);
1172 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1174 struct ldb_dn *new_dn;
1176 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1177 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1178 talloc_free(new_dn);
1184 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1186 struct ldb_dn *new_dn;
1188 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1189 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1190 talloc_free(new_dn);
1197 work out the domain sid for the current open ldb
1199 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1201 TALLOC_CTX *tmp_ctx;
1202 const struct dom_sid *domain_sid;
1203 const char *attrs[] = {
1207 struct ldb_result *res;
1210 /* see if we have a cached copy */
1211 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1216 tmp_ctx = talloc_new(ldb);
1217 if (tmp_ctx == NULL) {
1221 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1223 if (ret != LDB_SUCCESS) {
1227 if (res->count != 1) {
1231 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1232 if (domain_sid == NULL) {
1236 /* cache the domain_sid in the ldb */
1237 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1241 talloc_steal(ldb, domain_sid);
1242 talloc_free(tmp_ctx);
1247 talloc_free(tmp_ctx);
1252 get domain sid from cache
1254 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1256 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1259 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1261 TALLOC_CTX *tmp_ctx;
1262 struct dom_sid *dom_sid_new;
1263 struct dom_sid *dom_sid_old;
1265 /* see if we have a cached copy */
1266 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1267 "cache.domain_sid"), struct dom_sid);
1269 tmp_ctx = talloc_new(ldb);
1270 if (tmp_ctx == NULL) {
1274 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1279 /* cache the domain_sid in the ldb */
1280 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1284 talloc_steal(ldb, dom_sid_new);
1285 talloc_free(tmp_ctx);
1286 talloc_free(dom_sid_old);
1291 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1292 talloc_free(tmp_ctx);
1296 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1298 TALLOC_CTX *tmp_ctx;
1299 struct ldb_dn *ntds_settings_dn_new;
1300 struct ldb_dn *ntds_settings_dn_old;
1302 /* see if we have a cached copy */
1303 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1304 "cache.ntds_settings_dn"), struct ldb_dn);
1306 tmp_ctx = talloc_new(ldb);
1307 if (tmp_ctx == NULL) {
1311 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1312 if (!ntds_settings_dn_new) {
1316 /* cache the domain_sid in the ldb */
1317 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1321 talloc_steal(ldb, ntds_settings_dn_new);
1322 talloc_free(tmp_ctx);
1323 talloc_free(ntds_settings_dn_old);
1328 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1329 talloc_free(tmp_ctx);
1333 /* Obtain the short name of the flexible single master operator
1334 * (FSMO), such as the PDC Emulator */
1335 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1338 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1339 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1340 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1341 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1343 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1344 /* Ensure this matches the format. This gives us a
1345 * bit more confidence that a 'cn' value will be a
1350 return (char *)val->data;
1356 work out the ntds settings dn for the current open ldb
1358 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1360 TALLOC_CTX *tmp_ctx;
1361 const char *root_attrs[] = { "dsServiceName", NULL };
1363 struct ldb_result *root_res;
1364 struct ldb_dn *settings_dn;
1366 /* see if we have a cached copy */
1367 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1372 tmp_ctx = talloc_new(ldb);
1373 if (tmp_ctx == NULL) {
1377 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1379 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1380 ldb_errstring(ldb)));
1384 if (root_res->count != 1) {
1388 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1390 /* cache the domain_sid in the ldb */
1391 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1395 talloc_steal(ldb, settings_dn);
1396 talloc_free(tmp_ctx);
1401 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1402 talloc_free(tmp_ctx);
1407 work out the ntds settings invocationId for the current open ldb
1409 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1411 TALLOC_CTX *tmp_ctx;
1412 const char *attrs[] = { "invocationId", NULL };
1414 struct ldb_result *res;
1415 struct GUID *invocation_id;
1417 /* see if we have a cached copy */
1418 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1419 if (invocation_id) {
1420 return invocation_id;
1423 tmp_ctx = talloc_new(ldb);
1424 if (tmp_ctx == NULL) {
1428 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1433 if (res->count != 1) {
1437 invocation_id = talloc(tmp_ctx, struct GUID);
1438 if (!invocation_id) {
1442 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1444 /* cache the domain_sid in the ldb */
1445 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1449 talloc_steal(ldb, invocation_id);
1450 talloc_free(tmp_ctx);
1452 return invocation_id;
1455 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1456 talloc_free(tmp_ctx);
1460 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1462 TALLOC_CTX *tmp_ctx;
1463 struct GUID *invocation_id_new;
1464 struct GUID *invocation_id_old;
1466 /* see if we have a cached copy */
1467 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1468 "cache.invocation_id");
1470 tmp_ctx = talloc_new(ldb);
1471 if (tmp_ctx == NULL) {
1475 invocation_id_new = talloc(tmp_ctx, struct GUID);
1476 if (!invocation_id_new) {
1480 *invocation_id_new = *invocation_id_in;
1482 /* cache the domain_sid in the ldb */
1483 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1487 talloc_steal(ldb, invocation_id_new);
1488 talloc_free(tmp_ctx);
1489 talloc_free(invocation_id_old);
1494 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1495 talloc_free(tmp_ctx);
1500 work out the ntds settings objectGUID for the current open ldb
1502 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1504 TALLOC_CTX *tmp_ctx;
1505 const char *attrs[] = { "objectGUID", NULL };
1507 struct ldb_result *res;
1508 struct GUID *ntds_guid;
1510 /* see if we have a cached copy */
1511 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1516 tmp_ctx = talloc_new(ldb);
1517 if (tmp_ctx == NULL) {
1521 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1526 if (res->count != 1) {
1530 ntds_guid = talloc(tmp_ctx, struct GUID);
1535 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1537 /* cache the domain_sid in the ldb */
1538 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1542 talloc_steal(ldb, ntds_guid);
1543 talloc_free(tmp_ctx);
1548 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1549 talloc_free(tmp_ctx);
1553 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1555 TALLOC_CTX *tmp_ctx;
1556 struct GUID *ntds_guid_new;
1557 struct GUID *ntds_guid_old;
1559 /* see if we have a cached copy */
1560 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1562 tmp_ctx = talloc_new(ldb);
1563 if (tmp_ctx == NULL) {
1567 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1568 if (!ntds_guid_new) {
1572 *ntds_guid_new = *ntds_guid_in;
1574 /* cache the domain_sid in the ldb */
1575 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1579 talloc_steal(ldb, ntds_guid_new);
1580 talloc_free(tmp_ctx);
1581 talloc_free(ntds_guid_old);
1586 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1587 talloc_free(tmp_ctx);
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1600 work out the server dn for the current open ldb
1602 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1604 struct ldb_dn *server_dn;
1605 struct ldb_dn *servers_dn;
1606 struct ldb_dn *server_site_dn;
1608 /* TODO: there must be a saner way to do this!! */
1609 server_dn = samdb_server_dn(ldb, mem_ctx);
1610 if (!server_dn) return NULL;
1612 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1613 talloc_free(server_dn);
1614 if (!servers_dn) return NULL;
1616 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1617 talloc_free(servers_dn);
1619 return server_site_dn;
1623 find the site name from a computers DN record
1625 int samdb_find_site_for_computer(struct ldb_context *ldb,
1626 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1627 const char **site_name)
1631 const struct ldb_val *rdn_val;
1635 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1636 if (ret != LDB_SUCCESS) {
1640 if (!ldb_dn_remove_child_components(dn, 2)) {
1642 return LDB_ERR_INVALID_DN_SYNTAX;
1644 rdn_val = ldb_dn_get_rdn_val(dn);
1645 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1648 return LDB_ERR_OPERATIONS_ERROR;
1654 find the NTDS GUID from a computers DN record
1656 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1657 struct GUID *ntds_guid)
1662 *ntds_guid = GUID_zero();
1664 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1665 if (ret != LDB_SUCCESS) {
1669 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1671 return LDB_ERR_OPERATIONS_ERROR;
1674 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1680 find a 'reference' DN that points at another object
1681 (eg. serverReference, rIDManagerReference etc)
1683 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1684 const char *attribute, struct ldb_dn **dn)
1686 const char *attrs[2];
1687 struct ldb_result *res;
1690 attrs[0] = attribute;
1693 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
1694 if (ret != LDB_SUCCESS) {
1698 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1700 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1701 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1702 ldb_dn_get_linearized(base));
1704 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1705 ldb_dn_get_linearized(base));
1708 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1716 find our machine account via the serverReference attribute in the
1719 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1721 struct ldb_dn *server_dn;
1724 server_dn = samdb_server_dn(ldb, mem_ctx);
1725 if (server_dn == NULL) {
1726 return LDB_ERR_NO_SUCH_OBJECT;
1729 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1730 talloc_free(server_dn);
1736 find the RID Manager$ DN via the rIDManagerReference attribute in the
1739 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1741 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1742 "rIDManagerReference", dn);
1746 find the RID Set DN via the rIDSetReferences attribute in our
1749 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1751 struct ldb_dn *server_ref_dn;
1754 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1755 if (ret != LDB_SUCCESS) {
1758 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1759 talloc_free(server_ref_dn);
1763 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1765 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1772 return (const char *) val->data;
1776 * Finds the client site by using the client's IP address.
1777 * The "subnet_name" returns the name of the subnet if parameter != NULL
1779 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1780 const char *ip_address, char **subnet_name)
1782 const char *attrs[] = { "cn", "siteObject", NULL };
1783 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1784 struct ldb_result *res;
1785 const struct ldb_val *val;
1786 const char *site_name = NULL, *l_subnet_name = NULL;
1787 const char *allow_list[2] = { NULL, NULL };
1788 unsigned int i, count;
1792 * if we don't have a client ip e.g. ncalrpc
1793 * the server site is the client site
1795 if (ip_address == NULL) {
1796 return samdb_server_site_name(ldb, mem_ctx);
1799 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1800 if (sites_container_dn == NULL) {
1804 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1805 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1806 talloc_free(sites_container_dn);
1807 talloc_free(subnets_dn);
1811 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1813 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1815 } else if (ret != LDB_SUCCESS) {
1816 talloc_free(sites_container_dn);
1817 talloc_free(subnets_dn);
1823 for (i = 0; i < count; i++) {
1824 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1827 allow_list[0] = l_subnet_name;
1829 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1830 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1833 if (sites_dn == NULL) {
1834 /* No reference, maybe another subnet matches */
1838 /* "val" cannot be NULL here since "sites_dn" != NULL */
1839 val = ldb_dn_get_rdn_val(sites_dn);
1840 site_name = talloc_strdup(mem_ctx,
1841 (const char *) val->data);
1843 talloc_free(sites_dn);
1849 if (site_name == NULL) {
1850 /* This is the Windows Server fallback rule: when no subnet
1851 * exists and we have only one site available then use it (it
1852 * is for sure the same as our server site). If more sites do
1853 * exist then we don't know which one to use and set the site
1855 cnt = samdb_search_count(ldb, sites_container_dn,
1856 "(objectClass=site)");
1858 site_name = samdb_server_site_name(ldb, mem_ctx);
1860 site_name = talloc_strdup(mem_ctx, "");
1862 l_subnet_name = NULL;
1865 if (subnet_name != NULL) {
1866 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1869 talloc_free(sites_container_dn);
1870 talloc_free(subnets_dn);
1877 work out if we are the PDC for the domain of the current open ldb
1879 bool samdb_is_pdc(struct ldb_context *ldb)
1881 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1883 struct ldb_result *dom_res;
1884 TALLOC_CTX *tmp_ctx;
1888 tmp_ctx = talloc_new(ldb);
1889 if (tmp_ctx == NULL) {
1890 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1894 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1895 if (ret != LDB_SUCCESS) {
1896 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1897 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1898 ldb_errstring(ldb)));
1901 if (dom_res->count != 1) {
1905 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1907 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1913 talloc_free(tmp_ctx);
1918 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1919 talloc_free(tmp_ctx);
1924 work out if we are a Global Catalog server for the domain of the current open ldb
1926 bool samdb_is_gc(struct ldb_context *ldb)
1928 const char *attrs[] = { "options", NULL };
1930 struct ldb_result *res;
1931 TALLOC_CTX *tmp_ctx;
1933 tmp_ctx = talloc_new(ldb);
1934 if (tmp_ctx == NULL) {
1935 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1939 /* Query cn=ntds settings,.... */
1940 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1941 if (ret != LDB_SUCCESS) {
1942 talloc_free(tmp_ctx);
1945 if (res->count != 1) {
1946 talloc_free(tmp_ctx);
1950 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1951 talloc_free(tmp_ctx);
1953 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1954 if (options & 0x000000001) {
1960 /* Find a domain object in the parents of a particular DN. */
1961 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1962 struct ldb_dn **parent_dn, const char **errstring)
1964 TALLOC_CTX *local_ctx;
1965 struct ldb_dn *sdn = dn;
1966 struct ldb_result *res = NULL;
1967 int ret = LDB_SUCCESS;
1968 const char *attrs[] = { NULL };
1970 local_ctx = talloc_new(mem_ctx);
1971 if (local_ctx == NULL) return ldb_oom(ldb);
1973 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1974 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1975 "(|(objectClass=domain)(objectClass=builtinDomain))");
1976 if (ret == LDB_SUCCESS) {
1977 if (res->count == 1) {
1985 if (ret != LDB_SUCCESS) {
1986 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1987 ldb_dn_get_linearized(dn),
1988 ldb_dn_get_linearized(sdn),
1989 ldb_errstring(ldb));
1990 talloc_free(local_ctx);
1993 if (res->count != 1) {
1994 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1995 ldb_dn_get_linearized(dn));
1996 DEBUG(0,(__location__ ": %s\n", *errstring));
1997 talloc_free(local_ctx);
1998 return LDB_ERR_CONSTRAINT_VIOLATION;
2001 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2002 talloc_free(local_ctx);
2008 * Performs checks on a user password (plaintext UNIX format - attribute
2009 * "password"). The remaining parameters have to be extracted from the domain
2012 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2014 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2015 const uint32_t pwdProperties,
2016 const uint32_t minPwdLength)
2018 /* checks if the "minPwdLength" property is satisfied */
2019 if (minPwdLength > password->length)
2020 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2022 /* checks the password complexity */
2023 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2024 && (password->data != NULL)
2025 && (!check_password_quality((const char *) password->data)))
2026 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2028 return SAMR_VALIDATION_STATUS_SUCCESS;
2032 * Callback for "samdb_set_password" password change
2034 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2039 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2042 if (ares->error != LDB_SUCCESS) {
2044 req->context = talloc_steal(req,
2045 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2047 return ldb_request_done(req, ret);
2050 if (ares->type != LDB_REPLY_DONE) {
2052 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2055 req->context = talloc_steal(req,
2056 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2058 return ldb_request_done(req, LDB_SUCCESS);
2062 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2063 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2064 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2065 * user change or not. The "rejectReason" gives some more informations if the
2068 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2069 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2071 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2072 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2073 const DATA_BLOB *new_password,
2074 const struct samr_Password *lmNewHash,
2075 const struct samr_Password *ntNewHash,
2076 const struct samr_Password *lmOldHash,
2077 const struct samr_Password *ntOldHash,
2078 enum samPwdChangeReason *reject_reason,
2079 struct samr_DomInfo1 **_dominfo)
2081 struct ldb_message *msg;
2082 struct ldb_message_element *el;
2083 struct ldb_request *req;
2084 struct dsdb_control_password_change_status *pwd_stat = NULL;
2086 NTSTATUS status = NT_STATUS_OK;
2088 #define CHECK_RET(x) \
2089 if (x != LDB_SUCCESS) { \
2091 return NT_STATUS_NO_MEMORY; \
2094 msg = ldb_msg_new(mem_ctx);
2096 return NT_STATUS_NO_MEMORY;
2099 if ((new_password != NULL)
2100 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2101 /* we have the password as plaintext UTF16 */
2102 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2103 "clearTextPassword", new_password));
2104 el = ldb_msg_find_element(msg, "clearTextPassword");
2105 el->flags = LDB_FLAG_MOD_REPLACE;
2106 } else if ((new_password == NULL)
2107 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2108 /* we have a password as LM and/or NT hash */
2109 if (lmNewHash != NULL) {
2110 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2111 "dBCSPwd", lmNewHash));
2112 el = ldb_msg_find_element(msg, "dBCSPwd");
2113 el->flags = LDB_FLAG_MOD_REPLACE;
2115 if (ntNewHash != NULL) {
2116 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2117 "unicodePwd", ntNewHash));
2118 el = ldb_msg_find_element(msg, "unicodePwd");
2119 el->flags = LDB_FLAG_MOD_REPLACE;
2122 /* the password wasn't specified correctly */
2124 return NT_STATUS_INVALID_PARAMETER;
2127 /* build modify request */
2128 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2129 samdb_set_password_callback, NULL);
2130 if (ret != LDB_SUCCESS) {
2132 return NT_STATUS_NO_MEMORY;
2135 /* A password change operation */
2136 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2137 struct dsdb_control_password_change *change;
2139 change = talloc(req, struct dsdb_control_password_change);
2140 if (change == NULL) {
2143 return NT_STATUS_NO_MEMORY;
2146 change->old_nt_pwd_hash = ntOldHash;
2147 change->old_lm_pwd_hash = lmOldHash;
2149 ret = ldb_request_add_control(req,
2150 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2152 if (ret != LDB_SUCCESS) {
2155 return NT_STATUS_NO_MEMORY;
2158 ret = ldb_request_add_control(req,
2159 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2161 if (ret != LDB_SUCCESS) {
2164 return NT_STATUS_NO_MEMORY;
2166 ret = ldb_request_add_control(req,
2167 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2169 if (ret != LDB_SUCCESS) {
2172 return NT_STATUS_NO_MEMORY;
2175 ret = dsdb_autotransaction_request(ldb, req);
2177 if (req->context != NULL) {
2178 pwd_stat = talloc_steal(mem_ctx,
2179 ((struct ldb_control *)req->context)->data);
2185 /* Sets the domain info (if requested) */
2186 if (_dominfo != NULL) {
2187 struct samr_DomInfo1 *dominfo;
2189 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2190 if (dominfo == NULL) {
2191 return NT_STATUS_NO_MEMORY;
2194 if (pwd_stat != NULL) {
2195 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2196 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2197 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2198 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2199 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2202 *_dominfo = dominfo;
2205 if (reject_reason != NULL) {
2206 if (pwd_stat != NULL) {
2207 *reject_reason = pwd_stat->reject_reason;
2209 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2213 if (pwd_stat != NULL) {
2214 talloc_free(pwd_stat);
2217 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2218 const char *errmsg = ldb_errstring(ldb);
2219 char *endptr = NULL;
2220 WERROR werr = WERR_GENERAL_FAILURE;
2221 status = NT_STATUS_UNSUCCESSFUL;
2222 if (errmsg != NULL) {
2223 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2225 if (endptr != errmsg) {
2226 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2227 status = NT_STATUS_WRONG_PASSWORD;
2229 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2230 status = NT_STATUS_PASSWORD_RESTRICTION;
2233 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2234 /* don't let the caller know if an account doesn't exist */
2235 status = NT_STATUS_WRONG_PASSWORD;
2236 } else if (ret != LDB_SUCCESS) {
2237 status = NT_STATUS_UNSUCCESSFUL;
2244 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2245 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2246 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2247 * user change or not. The "rejectReason" gives some more informations if the
2250 * This wrapper function for "samdb_set_password" takes a SID as input rather
2253 * This call encapsulates a new LDB transaction for changing the password;
2254 * therefore the user hasn't to start a new one.
2256 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2257 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2258 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2259 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2261 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2262 const struct dom_sid *user_sid,
2263 const DATA_BLOB *new_password,
2264 const struct samr_Password *lmNewHash,
2265 const struct samr_Password *ntNewHash,
2266 const struct samr_Password *lmOldHash,
2267 const struct samr_Password *ntOldHash,
2268 enum samPwdChangeReason *reject_reason,
2269 struct samr_DomInfo1 **_dominfo)
2272 struct ldb_dn *user_dn;
2275 ret = ldb_transaction_start(ldb);
2276 if (ret != LDB_SUCCESS) {
2277 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2278 return NT_STATUS_TRANSACTION_ABORTED;
2281 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2282 "(&(objectSid=%s)(objectClass=user))",
2283 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2285 ldb_transaction_cancel(ldb);
2286 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2287 dom_sid_string(mem_ctx, user_sid)));
2288 return NT_STATUS_NO_SUCH_USER;
2291 nt_status = samdb_set_password(ldb, mem_ctx,
2294 lmNewHash, ntNewHash,
2295 lmOldHash, ntOldHash,
2296 reject_reason, _dominfo);
2297 if (!NT_STATUS_IS_OK(nt_status)) {
2298 ldb_transaction_cancel(ldb);
2299 talloc_free(user_dn);
2303 ret = ldb_transaction_commit(ldb);
2304 if (ret != LDB_SUCCESS) {
2305 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2306 ldb_dn_get_linearized(user_dn),
2307 ldb_errstring(ldb)));
2308 talloc_free(user_dn);
2309 return NT_STATUS_TRANSACTION_ABORTED;
2312 talloc_free(user_dn);
2313 return NT_STATUS_OK;
2317 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2318 struct dom_sid *sid, struct ldb_dn **ret_dn)
2320 struct ldb_message *msg;
2321 struct ldb_dn *basedn;
2325 sidstr = dom_sid_string(mem_ctx, sid);
2326 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2328 /* We might have to create a ForeignSecurityPrincipal, even if this user
2329 * is in our own domain */
2331 msg = ldb_msg_new(sidstr);
2333 talloc_free(sidstr);
2334 return NT_STATUS_NO_MEMORY;
2337 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2338 ldb_get_default_basedn(sam_ctx),
2339 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2341 if (ret != LDB_SUCCESS) {
2342 DEBUG(0, ("Failed to find DN for "
2343 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2344 talloc_free(sidstr);
2345 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2348 /* add core elements to the ldb_message for the alias */
2350 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2351 talloc_free(sidstr);
2352 return NT_STATUS_NO_MEMORY;
2355 samdb_msg_add_string(sam_ctx, msg, msg,
2357 "foreignSecurityPrincipal");
2359 /* create the alias */
2360 ret = ldb_add(sam_ctx, msg);
2361 if (ret != LDB_SUCCESS) {
2362 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2364 ldb_dn_get_linearized(msg->dn),
2365 ldb_errstring(sam_ctx)));
2366 talloc_free(sidstr);
2367 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2370 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2371 talloc_free(sidstr);
2373 return NT_STATUS_OK;
2378 Find the DN of a domain, assuming it to be a dotted.dns name
2381 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2384 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2385 const char *binary_encoded;
2386 const char **split_realm;
2393 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2395 talloc_free(tmp_ctx);
2398 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2399 for (i=0; split_realm[i]; i++) {
2400 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2401 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2402 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2403 binary_encoded, ldb_dn_get_linearized(dn)));
2404 talloc_free(tmp_ctx);
2408 if (!ldb_dn_validate(dn)) {
2409 DEBUG(2, ("Failed to validated DN %s\n",
2410 ldb_dn_get_linearized(dn)));
2411 talloc_free(tmp_ctx);
2414 talloc_free(tmp_ctx);
2419 Find the DN of a domain, be it the netbios or DNS name
2421 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2422 const char *domain_name)
2424 const char * const domain_ref_attrs[] = {
2427 const char * const domain_ref2_attrs[] = {
2430 struct ldb_result *res_domain_ref;
2431 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2432 /* find the domain's DN */
2433 int ret_domain = ldb_search(ldb, mem_ctx,
2435 samdb_partitions_dn(ldb, mem_ctx),
2438 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2440 if (ret_domain != LDB_SUCCESS) {
2444 if (res_domain_ref->count == 0) {
2445 ret_domain = ldb_search(ldb, mem_ctx,
2447 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2450 "(objectclass=domain)");
2451 if (ret_domain != LDB_SUCCESS) {
2455 if (res_domain_ref->count == 1) {
2456 return res_domain_ref->msgs[0]->dn;
2461 if (res_domain_ref->count > 1) {
2462 DEBUG(0,("Found %d records matching domain [%s]\n",
2463 ret_domain, domain_name));
2467 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2473 use a GUID to find a DN
2475 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2476 TALLOC_CTX *mem_ctx,
2477 const struct GUID *guid, struct ldb_dn **dn)
2480 struct ldb_result *res;
2481 const char *attrs[] = { NULL };
2482 char *guid_str = GUID_string(mem_ctx, guid);
2485 return ldb_operr(ldb);
2488 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2489 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2490 DSDB_SEARCH_SHOW_EXTENDED_DN |
2491 DSDB_SEARCH_ONE_ONLY,
2492 "objectGUID=%s", guid_str);
2493 talloc_free(guid_str);
2494 if (ret != LDB_SUCCESS) {
2498 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2505 use a DN to find a GUID with a given attribute name
2507 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2508 struct ldb_dn *dn, const char *attribute,
2512 struct ldb_result *res;
2513 const char *attrs[2];
2514 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2516 attrs[0] = attribute;
2519 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2520 DSDB_SEARCH_SHOW_DELETED |
2521 DSDB_SEARCH_SHOW_RECYCLED);
2522 if (ret != LDB_SUCCESS) {
2523 talloc_free(tmp_ctx);
2526 if (res->count < 1) {
2527 talloc_free(tmp_ctx);
2528 return LDB_ERR_NO_SUCH_OBJECT;
2530 *guid = samdb_result_guid(res->msgs[0], attribute);
2531 talloc_free(tmp_ctx);
2536 use a DN to find a GUID
2538 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2539 struct ldb_dn *dn, struct GUID *guid)
2541 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2547 adds the given GUID to the given ldb_message. This value is added
2548 for the given attr_name (may be either "objectGUID" or "parentGUID").
2550 int dsdb_msg_add_guid(struct ldb_message *msg,
2552 const char *attr_name)
2557 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2559 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 ret = LDB_ERR_OPERATIONS_ERROR;
2565 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2566 if (ret != LDB_SUCCESS) {
2567 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2575 talloc_free(tmp_ctx);
2582 use a DN to find a SID
2584 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2585 struct ldb_dn *dn, struct dom_sid *sid)
2588 struct ldb_result *res;
2589 const char *attrs[] = { "objectSid", NULL };
2590 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2595 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
2596 DSDB_SEARCH_SHOW_DELETED |
2597 DSDB_SEARCH_SHOW_RECYCLED);
2598 if (ret != LDB_SUCCESS) {
2599 talloc_free(tmp_ctx);
2602 if (res->count < 1) {
2603 talloc_free(tmp_ctx);
2604 return LDB_ERR_NO_SUCH_OBJECT;
2606 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2608 talloc_free(tmp_ctx);
2609 return LDB_ERR_NO_SUCH_OBJECT;
2612 talloc_free(tmp_ctx);
2617 use a SID to find a DN
2619 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2620 TALLOC_CTX *mem_ctx,
2621 struct dom_sid *sid, struct ldb_dn **dn)
2624 struct ldb_result *res;
2625 const char *attrs[] = { NULL };
2626 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2629 return ldb_operr(ldb);
2632 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2633 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2634 DSDB_SEARCH_SHOW_EXTENDED_DN |
2635 DSDB_SEARCH_ONE_ONLY,
2636 "objectSid=%s", sid_str);
2637 talloc_free(sid_str);
2638 if (ret != LDB_SUCCESS) {
2642 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2649 load a repsFromTo blob list for a given partition GUID
2650 attr must be "repsFrom" or "repsTo"
2652 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2653 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2655 const char *attrs[] = { attr, NULL };
2656 struct ldb_result *res = NULL;
2657 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2659 struct ldb_message_element *el;
2664 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2666 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2667 talloc_free(tmp_ctx);
2668 return WERR_DS_DRA_INTERNAL_ERROR;
2671 el = ldb_msg_find_element(res->msgs[0], attr);
2673 /* it's OK to be empty */
2674 talloc_free(tmp_ctx);
2678 *count = el->num_values;
2679 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2681 talloc_free(tmp_ctx);
2682 return WERR_DS_DRA_INTERNAL_ERROR;
2685 for (i=0; i<(*count); i++) {
2686 enum ndr_err_code ndr_err;
2687 ndr_err = ndr_pull_struct_blob(&el->values[i],
2690 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2691 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2692 talloc_free(tmp_ctx);
2693 return WERR_DS_DRA_INTERNAL_ERROR;
2697 talloc_free(tmp_ctx);
2703 save the repsFromTo blob list for a given partition GUID
2704 attr must be "repsFrom" or "repsTo"
2706 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2707 const char *attr, struct repsFromToBlob *r, uint32_t count)
2709 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2710 struct ldb_message *msg;
2711 struct ldb_message_element *el;
2714 msg = ldb_msg_new(tmp_ctx);
2716 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2720 el->values = talloc_array(msg, struct ldb_val, count);
2725 for (i=0; i<count; i++) {
2727 enum ndr_err_code ndr_err;
2729 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2731 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2732 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2740 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2741 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2745 talloc_free(tmp_ctx);
2750 talloc_free(tmp_ctx);
2751 return WERR_DS_DRA_INTERNAL_ERROR;
2756 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2757 object for a partition
2759 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2760 uint64_t *uSN, uint64_t *urgent_uSN)
2762 struct ldb_request *req;
2764 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2765 struct dsdb_control_current_partition *p_ctrl;
2766 struct ldb_result *res;
2768 res = talloc_zero(tmp_ctx, struct ldb_result);
2770 talloc_free(tmp_ctx);
2771 return ldb_oom(ldb);
2774 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2775 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2779 res, ldb_search_default_callback,
2781 if (ret != LDB_SUCCESS) {
2782 talloc_free(tmp_ctx);
2786 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2787 if (p_ctrl == NULL) {
2788 talloc_free(tmp_ctx);
2789 return ldb_oom(ldb);
2791 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2794 ret = ldb_request_add_control(req,
2795 DSDB_CONTROL_CURRENT_PARTITION_OID,
2797 if (ret != LDB_SUCCESS) {
2798 talloc_free(tmp_ctx);
2802 /* Run the new request */
2803 ret = ldb_request(ldb, req);
2805 if (ret == LDB_SUCCESS) {
2806 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2809 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2810 /* it hasn't been created yet, which means
2811 an implicit value of zero */
2813 talloc_free(tmp_ctx);
2817 if (ret != LDB_SUCCESS) {
2818 talloc_free(tmp_ctx);
2822 if (res->count < 1) {
2828 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2830 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2834 talloc_free(tmp_ctx);
2839 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2840 const struct drsuapi_DsReplicaCursor2 *c2)
2842 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2845 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2846 const struct drsuapi_DsReplicaCursor *c2)
2848 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2853 see if a computer identified by its invocationId is a RODC
2855 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2857 /* 1) find the DN for this servers NTDSDSA object
2858 2) search for the msDS-isRODC attribute
2859 3) if not present then not a RODC
2860 4) if present and TRUE then is a RODC
2862 struct ldb_dn *config_dn;
2863 const char *attrs[] = { "msDS-isRODC", NULL };
2865 struct ldb_result *res;
2866 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2868 config_dn = ldb_get_config_basedn(sam_ctx);
2870 talloc_free(tmp_ctx);
2871 return ldb_operr(sam_ctx);
2874 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2875 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2877 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2879 talloc_free(tmp_ctx);
2883 if (ret != LDB_SUCCESS) {
2884 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2885 GUID_string(tmp_ctx, objectGUID)));
2887 talloc_free(tmp_ctx);
2891 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2892 *is_rodc = (ret == 1);
2894 talloc_free(tmp_ctx);
2900 see if we are a RODC
2902 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2904 const struct GUID *objectGUID;
2908 /* see if we have a cached copy */
2909 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2915 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2917 return ldb_operr(sam_ctx);
2920 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2921 if (ret != LDB_SUCCESS) {
2925 cached = talloc(sam_ctx, bool);
2926 if (cached == NULL) {
2927 return ldb_oom(sam_ctx);
2931 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2932 if (ret != LDB_SUCCESS) {
2933 talloc_free(cached);
2934 return ldb_operr(sam_ctx);
2940 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2942 TALLOC_CTX *tmp_ctx;
2945 tmp_ctx = talloc_new(ldb);
2946 if (tmp_ctx == NULL) {
2950 cached = talloc(tmp_ctx, bool);
2956 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2960 talloc_steal(ldb, cached);
2961 talloc_free(tmp_ctx);
2965 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2966 talloc_free(tmp_ctx);
2972 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2974 flags are DS_NTDS_OPTION_*
2976 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2978 TALLOC_CTX *tmp_ctx;
2979 const char *attrs[] = { "options", NULL };
2981 struct ldb_result *res;
2983 tmp_ctx = talloc_new(ldb);
2984 if (tmp_ctx == NULL) {
2988 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2989 if (ret != LDB_SUCCESS) {
2993 if (res->count != 1) {
2997 *options = samdb_result_uint(res->msgs[0], "options", 0);
2999 talloc_free(tmp_ctx);
3004 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3005 talloc_free(tmp_ctx);
3006 return LDB_ERR_NO_SUCH_OBJECT;
3009 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3011 const char *attrs[] = { "objectCategory", NULL };
3013 struct ldb_result *res;
3015 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3016 if (ret != LDB_SUCCESS) {
3020 if (res->count != 1) {
3024 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
3027 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3032 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3033 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3035 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3037 char **tokens, *ret;
3040 tokens = str_list_make(mem_ctx, cn, " -_");
3044 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3045 tokens[0][0] = tolower(tokens[0][0]);
3046 for (i = 1; i < str_list_length((const char **)tokens); i++)
3047 tokens[i][0] = toupper(tokens[i][0]);
3049 ret = talloc_strdup(mem_ctx, tokens[0]);
3050 for (i = 1; i < str_list_length((const char **)tokens); i++)
3051 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3053 talloc_free(tokens);
3059 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3061 int dsdb_functional_level(struct ldb_context *ldb)
3063 int *domainFunctionality =
3064 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3065 if (!domainFunctionality) {
3066 /* this is expected during initial provision */
3067 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3068 return DS_DOMAIN_FUNCTION_2000;
3070 return *domainFunctionality;
3074 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3076 int dsdb_forest_functional_level(struct ldb_context *ldb)
3078 int *forestFunctionality =
3079 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3080 if (!forestFunctionality) {
3081 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3082 return DS_DOMAIN_FUNCTION_2000;
3084 return *forestFunctionality;
3088 set a GUID in an extended DN structure
3090 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3096 status = GUID_to_ndr_blob(guid, dn, &v);
3097 if (!NT_STATUS_IS_OK(status)) {
3098 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3101 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3107 return a GUID from a extended DN structure
3109 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3111 const struct ldb_val *v;
3113 v = ldb_dn_get_extended_component(dn, component_name);
3115 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3118 return GUID_from_ndr_blob(v, guid);
3122 return a uint64_t from a extended DN structure
3124 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3126 const struct ldb_val *v;
3129 v = ldb_dn_get_extended_component(dn, component_name);
3131 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3133 s = talloc_strndup(dn, (const char *)v->data, v->length);
3134 NT_STATUS_HAVE_NO_MEMORY(s);
3136 *val = strtoull(s, NULL, 0);
3139 return NT_STATUS_OK;
3143 return a NTTIME from a extended DN structure
3145 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3147 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3151 return a uint32_t from a extended DN structure
3153 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3155 const struct ldb_val *v;
3158 v = ldb_dn_get_extended_component(dn, component_name);
3160 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3163 s = talloc_strndup(dn, (const char *)v->data, v->length);
3164 NT_STATUS_HAVE_NO_MEMORY(s);
3166 *val = strtoul(s, NULL, 0);
3169 return NT_STATUS_OK;
3173 return a dom_sid from a extended DN structure
3175 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3177 const struct ldb_val *sid_blob;
3178 struct TALLOC_CTX *tmp_ctx;
3179 enum ndr_err_code ndr_err;
3181 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3183 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3186 tmp_ctx = talloc_new(NULL);
3188 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3189 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3190 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3191 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3192 talloc_free(tmp_ctx);
3196 talloc_free(tmp_ctx);
3197 return NT_STATUS_OK;
3202 return RMD_FLAGS directly from a ldb_dn
3203 returns 0 if not found
3205 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3207 const struct ldb_val *v;
3209 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3210 if (!v || v->length > sizeof(buf)-1) return 0;
3211 strncpy(buf, (const char *)v->data, v->length);
3213 return strtoul(buf, NULL, 10);
3217 return RMD_FLAGS directly from a ldb_val for a DN
3218 returns 0 if RMD_FLAGS is not found
3220 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3226 if (val->length < 13) {
3229 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3233 flags = strtoul(p+11, &end, 10);
3234 if (!end || *end != '>') {
3235 /* it must end in a > */
3242 return true if a ldb_val containing a DN in storage form is deleted
3244 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3246 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3250 return true if a ldb_val containing a DN in storage form is
3251 in the upgraded w2k3 linked attribute format
3253 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3255 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3259 return a DN for a wellknown GUID
3261 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3262 struct ldb_dn *nc_root, const char *wk_guid,
3263 struct ldb_dn **wkguid_dn)
3265 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3266 const char *attrs[] = { NULL };
3269 struct ldb_result *res;
3271 /* construct the magic WKGUID DN */
3272 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3273 wk_guid, ldb_dn_get_linearized(nc_root));
3275 talloc_free(tmp_ctx);
3276 return ldb_operr(samdb);
3279 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3280 DSDB_SEARCH_SHOW_DELETED |
3281 DSDB_SEARCH_SHOW_RECYCLED);
3282 if (ret != LDB_SUCCESS) {
3283 talloc_free(tmp_ctx);
3287 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3288 talloc_free(tmp_ctx);
3293 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3295 return ldb_dn_compare(*dn1, *dn2);
3299 find a NC root given a DN within the NC
3301 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3302 struct ldb_dn **nc_root)
3304 const char *root_attrs[] = { "namingContexts", NULL };
3305 TALLOC_CTX *tmp_ctx;
3307 struct ldb_message_element *el;
3308 struct ldb_result *root_res;
3310 struct ldb_dn **nc_dns;
3312 tmp_ctx = talloc_new(samdb);
3313 if (tmp_ctx == NULL) {
3314 return ldb_oom(samdb);
3317 ret = ldb_search(samdb, tmp_ctx, &root_res,
3318 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3319 if (ret != LDB_SUCCESS) {
3320 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3321 talloc_free(tmp_ctx);
3325 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3327 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3328 ldb_errstring(samdb)));
3329 talloc_free(tmp_ctx);
3330 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3333 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3335 talloc_free(tmp_ctx);
3336 return ldb_oom(samdb);
3339 for (i=0; i<el->num_values; i++) {
3340 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3341 if (nc_dns[i] == NULL) {
3342 talloc_free(tmp_ctx);
3343 return ldb_operr(samdb);
3347 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3349 for (i=0; i<el->num_values; i++) {
3350 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3351 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3352 talloc_free(tmp_ctx);
3357 talloc_free(tmp_ctx);
3358 return LDB_ERR_NO_SUCH_OBJECT;
3363 find the deleted objects DN for any object, by looking for the NC
3364 root, then looking up the wellknown GUID
3366 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3367 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3368 struct ldb_dn **do_dn)
3370 struct ldb_dn *nc_root;
3373 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3374 if (ret != LDB_SUCCESS) {
3378 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3379 talloc_free(nc_root);
3384 return the tombstoneLifetime, in days
3386 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3389 dn = ldb_get_config_basedn(ldb);
3391 return LDB_ERR_NO_SUCH_OBJECT;
3393 dn = ldb_dn_copy(ldb, dn);
3395 return ldb_operr(ldb);
3397 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3398 be a wellknown GUID for this */
3399 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3401 return ldb_operr(ldb);
3404 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3410 compare a ldb_val to a string case insensitively
3412 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3414 size_t len = strlen(s);
3416 if (len > v->length) return 1;
3417 ret = strncasecmp(s, (const char *)v->data, v->length);
3418 if (ret != 0) return ret;
3419 if (v->length > len && v->data[len] != 0) {
3427 load the UDV for a partition in v2 format
3428 The list is returned sorted, and with our local cursor added
3430 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3431 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3433 static const char *attrs[] = { "replUpToDateVector", NULL };
3434 struct ldb_result *r;
3435 const struct ldb_val *ouv_value;
3438 uint64_t highest_usn;
3439 const struct GUID *our_invocation_id;
3440 struct timeval now = timeval_current();
3442 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3443 if (ret != LDB_SUCCESS) {
3447 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3449 enum ndr_err_code ndr_err;
3450 struct replUpToDateVectorBlob ouv;
3452 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3453 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3454 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3456 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3458 if (ouv.version != 2) {
3459 /* we always store as version 2, and
3460 * replUpToDateVector is not replicated
3462 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3465 *count = ouv.ctr.ctr2.count;
3466 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3474 our_invocation_id = samdb_ntds_invocation_id(samdb);
3475 if (!our_invocation_id) {
3476 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3477 talloc_free(*cursors);
3478 return ldb_operr(samdb);
3481 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3482 if (ret != LDB_SUCCESS) {
3483 /* nothing to add - this can happen after a vampire */
3484 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3488 for (i=0; i<*count; i++) {
3489 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3490 (*cursors)[i].highest_usn = highest_usn;
3491 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3492 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3497 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3499 return ldb_oom(samdb);
3502 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3503 (*cursors)[*count].highest_usn = highest_usn;
3504 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3507 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3513 load the UDV for a partition in version 1 format
3514 The list is returned sorted, and with our local cursor added
3516 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3517 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3519 struct drsuapi_DsReplicaCursor2 *v2;
3523 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3524 if (ret != LDB_SUCCESS) {
3534 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3535 if (*cursors == NULL) {
3537 return ldb_oom(samdb);
3540 for (i=0; i<*count; i++) {
3541 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3542 (*cursors)[i].highest_usn = v2[i].highest_usn;
3549 add a set of controls to a ldb_request structure based on a set of
3550 flags. See util.h for a list of available flags
3552 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3555 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3556 struct ldb_search_options_control *options;
3557 /* Using the phantom root control allows us to search all partitions */
3558 options = talloc(req, struct ldb_search_options_control);
3559 if (options == NULL) {
3560 return LDB_ERR_OPERATIONS_ERROR;
3562 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3564 ret = ldb_request_add_control(req,
3565 LDB_CONTROL_SEARCH_OPTIONS_OID,
3567 if (ret != LDB_SUCCESS) {
3572 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3573 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3574 if (ret != LDB_SUCCESS) {
3579 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
3580 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
3581 if (ret != LDB_SUCCESS) {
3586 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3587 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3588 if (ret != LDB_SUCCESS) {
3593 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3594 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3595 if (!extended_ctrl) {
3596 return LDB_ERR_OPERATIONS_ERROR;
3598 extended_ctrl->type = 1;
3600 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3601 if (ret != LDB_SUCCESS) {
3606 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3607 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3608 if (ret != LDB_SUCCESS) {
3613 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3614 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3615 if (ret != LDB_SUCCESS) {
3620 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3621 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3622 if (ret != LDB_SUCCESS) {
3627 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3628 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3629 if (ret != LDB_SUCCESS) {
3634 if (dsdb_flags & DSDB_TREE_DELETE) {
3635 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3636 if (ret != LDB_SUCCESS) {
3645 an add with a set of controls
3647 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3648 uint32_t dsdb_flags)
3650 struct ldb_request *req;
3653 ret = ldb_build_add_req(&req, ldb, ldb,
3657 ldb_op_default_callback,
3660 if (ret != LDB_SUCCESS) return ret;
3662 ret = dsdb_request_add_controls(req, dsdb_flags);
3663 if (ret != LDB_SUCCESS) {
3668 ret = dsdb_autotransaction_request(ldb, req);
3675 a modify with a set of controls
3677 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3678 uint32_t dsdb_flags)
3680 struct ldb_request *req;
3683 ret = ldb_build_mod_req(&req, ldb, ldb,
3687 ldb_op_default_callback,
3690 if (ret != LDB_SUCCESS) return ret;
3692 ret = dsdb_request_add_controls(req, dsdb_flags);
3693 if (ret != LDB_SUCCESS) {
3698 ret = dsdb_autotransaction_request(ldb, req);
3705 like dsdb_modify() but set all the element flags to
3706 LDB_FLAG_MOD_REPLACE
3708 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3712 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3713 for (i=0;i<msg->num_elements;i++) {
3714 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3717 return dsdb_modify(ldb, msg, dsdb_flags);
3722 search for attrs on one DN, allowing for dsdb_flags controls
3724 int dsdb_search_dn(struct ldb_context *ldb,
3725 TALLOC_CTX *mem_ctx,
3726 struct ldb_result **_res,
3727 struct ldb_dn *basedn,
3728 const char * const *attrs,
3729 uint32_t dsdb_flags)
3732 struct ldb_request *req;
3733 struct ldb_result *res;
3735 res = talloc_zero(mem_ctx, struct ldb_result);
3737 return ldb_oom(ldb);
3740 ret = ldb_build_search_req(&req, ldb, res,
3747 ldb_search_default_callback,
3749 if (ret != LDB_SUCCESS) {
3754 ret = dsdb_request_add_controls(req, dsdb_flags);
3755 if (ret != LDB_SUCCESS) {
3760 ret = ldb_request(ldb, req);
3761 if (ret == LDB_SUCCESS) {
3762 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3766 if (ret != LDB_SUCCESS) {
3776 search for attrs on one DN, by the GUID of the DN, allowing for
3779 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
3780 TALLOC_CTX *mem_ctx,
3781 struct ldb_result **_res,
3782 const struct GUID *guid,
3783 const char * const *attrs,
3784 uint32_t dsdb_flags)
3786 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3790 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
3791 if (!ldb_dn_validate(dn)) {
3792 talloc_free(tmp_ctx);
3793 return LDB_ERR_INVALID_DN_SYNTAX;
3796 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
3797 talloc_free(tmp_ctx);
3802 general search with dsdb_flags for controls
3804 int dsdb_search(struct ldb_context *ldb,
3805 TALLOC_CTX *mem_ctx,
3806 struct ldb_result **_res,
3807 struct ldb_dn *basedn,
3808 enum ldb_scope scope,
3809 const char * const *attrs,
3810 uint32_t dsdb_flags,
3811 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3814 struct ldb_request *req;
3815 struct ldb_result *res;
3817 char *expression = NULL;
3818 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3820 res = talloc_zero(tmp_ctx, struct ldb_result);
3822 talloc_free(tmp_ctx);
3823 return ldb_oom(ldb);
3827 va_start(ap, exp_fmt);
3828 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3832 talloc_free(tmp_ctx);
3833 return ldb_oom(ldb);
3837 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3844 ldb_search_default_callback,
3846 if (ret != LDB_SUCCESS) {
3847 talloc_free(tmp_ctx);
3851 ret = dsdb_request_add_controls(req, dsdb_flags);
3852 if (ret != LDB_SUCCESS) {
3853 talloc_free(tmp_ctx);
3854 ldb_reset_err_string(ldb);
3858 ret = ldb_request(ldb, req);
3859 if (ret == LDB_SUCCESS) {
3860 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3863 if (ret != LDB_SUCCESS) {
3864 talloc_free(tmp_ctx);
3868 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3869 if (res->count == 0) {
3870 talloc_free(tmp_ctx);
3871 ldb_reset_err_string(ldb);
3872 return LDB_ERR_NO_SUCH_OBJECT;
3874 if (res->count != 1) {
3875 talloc_free(tmp_ctx);
3876 ldb_reset_err_string(ldb);
3877 return LDB_ERR_CONSTRAINT_VIOLATION;
3881 *_res = talloc_steal(mem_ctx, res);
3882 talloc_free(tmp_ctx);
3889 general search with dsdb_flags for controls
3890 returns exactly 1 record or an error
3892 int dsdb_search_one(struct ldb_context *ldb,
3893 TALLOC_CTX *mem_ctx,
3894 struct ldb_message **msg,
3895 struct ldb_dn *basedn,
3896 enum ldb_scope scope,
3897 const char * const *attrs,
3898 uint32_t dsdb_flags,
3899 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3902 struct ldb_result *res;
3904 char *expression = NULL;
3905 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3907 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3909 res = talloc_zero(tmp_ctx, struct ldb_result);
3911 talloc_free(tmp_ctx);
3912 return ldb_oom(ldb);
3916 va_start(ap, exp_fmt);
3917 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3921 talloc_free(tmp_ctx);
3922 return ldb_oom(ldb);
3924 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3925 dsdb_flags, "%s", expression);
3927 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3931 if (ret != LDB_SUCCESS) {
3932 talloc_free(tmp_ctx);
3936 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3937 talloc_free(tmp_ctx);
3942 /* returns back the forest DNS name */
3943 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3945 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3946 ldb_get_root_basedn(ldb));
3949 if (forest_name == NULL) {
3953 p = strchr(forest_name, '/');
3962 validate that an DSA GUID belongs to the specified user sid.
3963 The user SID must be a domain controller account (either RODC or
3966 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3967 const struct GUID *dsa_guid,
3968 const struct dom_sid *sid)
3971 - find DN of record with the DSA GUID in the
3972 configuration partition (objectGUID)
3973 - remove "NTDS Settings" component from DN
3974 - do a base search on that DN for serverReference with
3976 - extract objectSid from resulting serverReference
3978 - check this sid matches the sid argument
3980 struct ldb_dn *config_dn;
3981 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3982 struct ldb_message *msg;
3983 const char *attrs1[] = { NULL };
3984 const char *attrs2[] = { "serverReference", NULL };
3986 struct ldb_dn *dn, *account_dn;
3987 struct dom_sid sid2;
3990 config_dn = ldb_get_config_basedn(ldb);
3992 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3993 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3994 if (ret != LDB_SUCCESS) {
3995 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3996 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3997 talloc_free(tmp_ctx);
3998 return ldb_operr(ldb);
4002 if (!ldb_dn_remove_child_components(dn, 1)) {
4003 talloc_free(tmp_ctx);
4004 return ldb_operr(ldb);
4007 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4008 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4009 "(objectClass=server)");
4010 if (ret != LDB_SUCCESS) {
4011 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4012 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4013 talloc_free(tmp_ctx);
4014 return ldb_operr(ldb);
4017 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4018 if (account_dn == NULL) {
4019 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
4020 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4021 talloc_free(tmp_ctx);
4022 return ldb_operr(ldb);
4025 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4026 if (!NT_STATUS_IS_OK(status)) {
4027 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4028 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4029 talloc_free(tmp_ctx);
4030 return ldb_operr(ldb);
4033 if (!dom_sid_equal(sid, &sid2)) {
4034 /* someone is trying to spoof another account */
4035 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4036 GUID_string(tmp_ctx, dsa_guid),
4037 dom_sid_string(tmp_ctx, sid),
4038 dom_sid_string(tmp_ctx, &sid2)));
4039 talloc_free(tmp_ctx);
4040 return ldb_operr(ldb);
4043 talloc_free(tmp_ctx);
4047 static const char *secret_attributes[] = {
4050 "initialAuthIncoming",
4051 "initialAuthOutgoing",
4055 "supplementalCredentials",
4056 "trustAuthIncoming",
4057 "trustAuthOutgoing",
4063 check if the attribute belongs to the RODC filtered attribute set
4064 Note that attributes that are in the filtered attribute set are the
4065 ones that _are_ always sent to a RODC
4067 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4069 /* they never get secret attributes */
4070 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4074 /* they do get non-secret critical attributes */
4075 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4079 /* they do get non-secret attributes marked as being in the FAS */
4080 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4084 /* other attributes are denied */
4088 /* return fsmo role dn and role owner dn for a particular role*/
4089 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4090 struct ldb_context *ldb,
4092 struct ldb_dn **fsmo_role_dn,
4093 struct ldb_dn **role_owner_dn)
4097 case DREPL_NAMING_MASTER:
4098 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4099 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4100 if (ret != LDB_SUCCESS) {
4101 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4102 ldb_errstring(ldb)));
4103 talloc_free(tmp_ctx);
4104 return WERR_DS_DRA_INTERNAL_ERROR;
4107 case DREPL_INFRASTRUCTURE_MASTER:
4108 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4109 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4110 if (ret != LDB_SUCCESS) {
4111 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4112 ldb_errstring(ldb)));
4113 talloc_free(tmp_ctx);
4114 return WERR_DS_DRA_INTERNAL_ERROR;
4117 case DREPL_RID_MASTER:
4118 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4119 if (ret != LDB_SUCCESS) {
4120 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4121 talloc_free(tmp_ctx);
4122 return WERR_DS_DRA_INTERNAL_ERROR;
4125 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4126 if (ret != LDB_SUCCESS) {
4127 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4128 ldb_errstring(ldb)));
4129 talloc_free(tmp_ctx);
4130 return WERR_DS_DRA_INTERNAL_ERROR;
4133 case DREPL_SCHEMA_MASTER:
4134 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4135 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4136 if (ret != LDB_SUCCESS) {
4137 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4138 ldb_errstring(ldb)));
4139 talloc_free(tmp_ctx);
4140 return WERR_DS_DRA_INTERNAL_ERROR;
4143 case DREPL_PDC_MASTER:
4144 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4145 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4146 if (ret != LDB_SUCCESS) {
4147 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4148 ldb_errstring(ldb)));
4149 talloc_free(tmp_ctx);
4150 return WERR_DS_DRA_INTERNAL_ERROR;
4154 return WERR_DS_DRA_INTERNAL_ERROR;
4159 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4160 TALLOC_CTX *mem_ctx,
4161 struct ldb_dn *server_dn)
4164 struct ldb_result *res = NULL;
4165 const char * const attrs[] = { "dNSHostName", NULL};
4167 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4171 if (ldb_ret != LDB_SUCCESS) {
4172 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4173 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4177 return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
4181 returns true if an attribute is in the filter,
4182 false otherwise, provided that attribute value is provided with the expression
4184 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4188 switch (tree->operation) {
4191 for (i=0;i<tree->u.list.num_elements;i++) {
4192 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4198 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4199 case LDB_OP_EQUALITY:
4200 case LDB_OP_GREATER:
4203 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4207 case LDB_OP_SUBSTRING:
4208 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4212 case LDB_OP_PRESENT:
4213 /* (attrname=*) is not filtered out */
4215 case LDB_OP_EXTENDED:
4216 if (tree->u.extended.attr &&
4217 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {