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"
48 search the sam for the specified attributes in a specific domain, filter on
49 objectSid being in domain_sid.
51 int samdb_search_domain(struct ldb_context *sam_ldb,
53 struct ldb_dn *basedn,
54 struct ldb_message ***res,
55 const char * const *attrs,
56 const struct dom_sid *domain_sid,
57 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
63 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
64 res, attrs, format, ap);
70 struct dom_sid *entry_sid;
72 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
74 if ((entry_sid == NULL) ||
75 (!dom_sid_in_domain(domain_sid, entry_sid))) {
76 /* Delete that entry from the result set */
77 (*res)[i] = (*res)[count-1];
79 talloc_free(entry_sid);
82 talloc_free(entry_sid);
90 search the sam for a single string attribute in exactly 1 record
92 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
94 struct ldb_dn *basedn,
95 const char *attr_name,
96 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
99 const char *attrs[2] = { NULL, NULL };
100 struct ldb_message **res = NULL;
102 attrs[0] = attr_name;
104 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
106 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
107 attr_name, format, count));
114 return samdb_result_string(res[0], attr_name, NULL);
118 search the sam for a single string attribute in exactly 1 record
120 const char *samdb_search_string(struct ldb_context *sam_ldb,
122 struct ldb_dn *basedn,
123 const char *attr_name,
124 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
129 va_start(ap, format);
130 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
136 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
138 struct ldb_dn *basedn,
139 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
143 struct ldb_message **res = NULL;
146 va_start(ap, format);
147 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
150 if (count != 1) return NULL;
152 ret = talloc_steal(mem_ctx, res[0]->dn);
159 search the sam for a dom_sid attribute in exactly 1 record
161 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
163 struct ldb_dn *basedn,
164 const char *attr_name,
165 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
169 struct ldb_message **res;
170 const char *attrs[2] = { NULL, NULL };
173 attrs[0] = attr_name;
175 va_start(ap, format);
176 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
179 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
180 attr_name, format, count));
186 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
192 return the count of the number of records in the sam matching the query
194 int samdb_search_count(struct ldb_context *sam_ldb,
195 struct ldb_dn *basedn,
196 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
199 struct ldb_message **res;
200 const char *attrs[] = { NULL };
202 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
204 va_start(ap, format);
205 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
207 talloc_free(tmp_ctx);
214 search the sam for a single integer attribute in exactly 1 record
216 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
218 unsigned int default_value,
219 struct ldb_dn *basedn,
220 const char *attr_name,
221 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
225 struct ldb_message **res;
226 const char *attrs[2] = { NULL, NULL };
228 attrs[0] = attr_name;
230 va_start(ap, format);
231 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
235 return default_value;
238 return samdb_result_uint(res[0], attr_name, default_value);
242 search the sam for a single signed 64 bit integer attribute in exactly 1 record
244 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
246 int64_t default_value,
247 struct ldb_dn *basedn,
248 const char *attr_name,
249 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
253 struct ldb_message **res;
254 const char *attrs[2] = { NULL, NULL };
256 attrs[0] = attr_name;
258 va_start(ap, format);
259 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
263 return default_value;
266 return samdb_result_int64(res[0], attr_name, default_value);
270 search the sam for multipe records each giving a single string attribute
271 return the number of matches, or -1 on error
273 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
275 struct ldb_dn *basedn,
277 const char *attr_name,
278 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
282 const char *attrs[2] = { NULL, NULL };
283 struct ldb_message **res = NULL;
285 attrs[0] = attr_name;
287 va_start(ap, format);
288 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
295 /* make sure its single valued */
296 for (i=0;i<count;i++) {
297 if (res[i]->num_elements != 1) {
298 DEBUG(1,("samdb: search for %s %s not single valued\n",
305 *strs = talloc_array(mem_ctx, const char *, count+1);
311 for (i=0;i<count;i++) {
312 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
314 (*strs)[count] = NULL;
320 pull a uint from a result set.
322 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
324 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
328 pull a (signed) int64 from a result set.
330 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
332 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
336 pull a string from a result set.
338 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
339 const char *default_value)
341 return ldb_msg_find_attr_as_string(msg, attr, default_value);
344 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
345 const char *attr, struct ldb_dn *default_value)
347 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
349 return default_value;
355 pull a rid from a objectSid in a result set.
357 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
358 const char *attr, uint32_t default_value)
363 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
365 return default_value;
367 rid = sid->sub_auths[sid->num_auths-1];
373 pull a dom_sid structure from a objectSid in a result set.
375 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
378 const struct ldb_val *v;
380 enum ndr_err_code ndr_err;
381 v = ldb_msg_find_ldb_val(msg, attr);
385 sid = talloc(mem_ctx, struct dom_sid);
389 ndr_err = ndr_pull_struct_blob(v, sid, sid,
390 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
391 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
399 pull a guid structure from a objectGUID in a result set.
401 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
403 const struct ldb_val *v;
407 v = ldb_msg_find_ldb_val(msg, attr);
408 if (!v) return GUID_zero();
410 status = GUID_from_ndr_blob(v, &guid);
411 if (!NT_STATUS_IS_OK(status)) {
419 pull a sid prefix from a objectSid in a result set.
420 this is used to find the domain sid for a user
422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426 if (!sid || sid->num_auths < 1) return NULL;
432 pull a NTTIME in a result set.
434 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
435 NTTIME default_value)
437 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
441 * Windows stores 0 for lastLogoff.
442 * But when a MS DC return the lastLogoff (as Logoff Time)
443 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
444 * cause windows 2008 and newer version to fail for SMB requests
446 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
448 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
451 ret = 0x7FFFFFFFFFFFFFFFULL;
457 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
458 * indicate an account doesn't expire.
460 * When Windows initially creates an account, it sets
461 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
462 * when changing from an account having a specific expiration date to
463 * that account never expiring, it sets accountExpires = 0.
465 * Consolidate that logic here to allow clearer logic for account expiry in
466 * the rest of the code.
468 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
470 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
474 ret = 0x7FFFFFFFFFFFFFFFULL;
480 pull a uint64_t from a result set.
482 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
483 uint64_t default_value)
485 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
490 construct the allow_password_change field from the PwdLastSet attribute and the
491 domain password settings
493 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
495 struct ldb_dn *domain_dn,
496 struct ldb_message *msg,
499 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
502 if (attr_time == 0) {
506 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
508 /* yes, this is a -= not a += as minPwdAge is stored as the negative
509 of the number of 100-nano-seconds */
510 attr_time -= minPwdAge;
516 construct the force_password_change field from the PwdLastSet
517 attribute, the userAccountControl and the domain password settings
519 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
521 struct ldb_dn *domain_dn,
522 struct ldb_message *msg)
524 int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
525 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
526 "userAccountControl",
530 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
531 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
532 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
533 return 0x7FFFFFFFFFFFFFFFULL;
536 if (attr_time == 0) {
539 if (attr_time == -1) {
540 return 0x7FFFFFFFFFFFFFFFULL;
543 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
545 if (maxPwdAge == 0) {
546 return 0x7FFFFFFFFFFFFFFFULL;
548 attr_time -= maxPwdAge;
555 pull a samr_Password structutre from a result set.
557 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
559 struct samr_Password *hash = NULL;
560 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
561 if (val && (val->length >= sizeof(hash->hash))) {
562 hash = talloc(mem_ctx, struct samr_Password);
563 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
569 pull an array of samr_Password structures from a result set.
571 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
572 const char *attr, struct samr_Password **hashes)
574 unsigned int count, i;
575 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
581 count = val->length / 16;
586 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
591 for (i=0;i<count;i++) {
592 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
598 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
599 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
601 struct samr_Password *lmPwdHash, *ntPwdHash;
604 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
607 } else if (num_nt > 1) {
608 return NT_STATUS_INTERNAL_DB_CORRUPTION;
610 *nt_pwd = &ntPwdHash[0];
614 /* Ensure that if we have turned off LM
615 * authentication, that we never use the LM hash, even
617 if (lpcfg_lanman_auth(lp_ctx)) {
619 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
622 } else if (num_lm > 1) {
623 return NT_STATUS_INTERNAL_DB_CORRUPTION;
625 *lm_pwd = &lmPwdHash[0];
635 pull a samr_LogonHours structutre from a result set.
637 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
639 struct samr_LogonHours hours;
640 size_t units_per_week = 168;
641 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
646 units_per_week = val->length * 8;
649 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
653 hours.units_per_week = units_per_week;
654 memset(hours.bits, 0xFF, units_per_week/8);
656 memcpy(hours.bits, val->data, val->length);
663 pull a set of account_flags from a result set.
665 This requires that the attributes:
670 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
671 struct ldb_message *msg, struct ldb_dn *domain_dn)
673 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
674 uint32_t acct_flags = ds_uf2acb(userAccountControl);
675 NTTIME must_change_time;
678 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
681 /* Test account expire time */
682 unix_to_nt_time(&now, time(NULL));
683 /* check for expired password */
684 if (must_change_time < now) {
685 acct_flags |= ACB_PW_EXPIRED;
690 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
691 struct ldb_message *msg,
694 struct lsa_BinaryString s;
695 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
703 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
707 s.length = s.size = val->length;
708 memcpy(s.array, val->data, val->length);
713 /* Find an attribute, with a particular value */
715 /* The current callers of this function expect a very specific
716 * behaviour: In particular, objectClass subclass equivilance is not
717 * wanted. This means that we should not lookup the schema for the
718 * comparison function */
719 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
720 const struct ldb_message *msg,
721 const char *name, const char *value)
724 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
730 for (i=0;i<el->num_values;i++) {
731 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
740 * This is intended for use by the "password hash" module since there
741 * password changes can be specified through one message element with the
742 * new password (to set) and another one with the old password (to unset).
744 * The first which sets a password (new value) can have flags
745 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
746 * for entries). The latter (old value) has always specified
747 * LDB_FLAG_MOD_DELETE.
749 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
750 * doesn't contain only one value (this is the Windows Server behaviour)
751 * otherwise LDB_SUCCESS.
753 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
755 const struct ldb_val **new_val,
756 const struct ldb_val **old_val)
767 for (i = 0; i < msg->num_elements; i++) {
768 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
769 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
770 *old_val = &msg->elements[i].values[0];
772 *new_val = &msg->elements[i].values[0];
780 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
782 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
783 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
788 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
790 struct ldb_message_element *el;
792 el = ldb_msg_find_element(msg, name);
797 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
803 add a string element to a message
805 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
806 const char *attr_name, const char *str)
808 char *s = talloc_strdup(mem_ctx, str);
809 char *a = talloc_strdup(mem_ctx, attr_name);
810 if (s == NULL || a == NULL) {
811 return ldb_oom(sam_ldb);
813 return ldb_msg_add_string(msg, a, s);
817 add a dom_sid element to a message
819 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820 const char *attr_name, struct dom_sid *sid)
823 enum ndr_err_code ndr_err;
825 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
827 (ndr_push_flags_fn_t)ndr_push_dom_sid);
828 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
829 return ldb_operr(sam_ldb);
831 return ldb_msg_add_value(msg, attr_name, &v, NULL);
836 add a delete element operation to a message
838 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
839 const char *attr_name)
841 /* we use an empty replace rather than a delete, as it allows for
842 dsdb_replace() to be used everywhere */
843 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
847 add an add attribute value to a message or enhance an existing attribute
848 which has the same name and the add flag set.
850 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
851 struct ldb_message *msg, const char *attr_name,
854 struct ldb_message_element *el;
855 struct ldb_val val, *vals;
861 v = talloc_strdup(mem_ctx, value);
863 return ldb_oom(sam_ldb);
866 val.data = (uint8_t *) v;
867 val.length = strlen(v);
869 if (val.length == 0) {
870 /* allow empty strings as non-existent attributes */
874 for (i = 0; i < msg->num_elements; i++) {
875 el = &msg->elements[i];
876 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
877 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
883 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
885 if (ret != LDB_SUCCESS) {
890 vals = talloc_realloc(msg, el->values, struct ldb_val,
893 return ldb_oom(sam_ldb);
896 el->values[el->num_values] = val;
903 add a delete attribute value to a message or enhance an existing attribute
904 which has the same name and the delete flag set.
906 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
907 struct ldb_message *msg, const char *attr_name,
910 struct ldb_message_element *el;
911 struct ldb_val val, *vals;
917 v = talloc_strdup(mem_ctx, value);
919 return ldb_oom(sam_ldb);
922 val.data = (uint8_t *) v;
923 val.length = strlen(v);
925 if (val.length == 0) {
926 /* allow empty strings as non-existent attributes */
930 for (i = 0; i < msg->num_elements; i++) {
931 el = &msg->elements[i];
932 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
933 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
939 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
941 if (ret != LDB_SUCCESS) {
946 vals = talloc_realloc(msg, el->values, struct ldb_val,
949 return ldb_oom(sam_ldb);
952 el->values[el->num_values] = val;
959 add a int element to a message
961 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
962 const char *attr_name, int v)
964 const char *s = talloc_asprintf(mem_ctx, "%d", v);
965 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
969 add a unsigned int element to a message
971 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
972 const char *attr_name, unsigned int v)
974 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
978 add a (signed) int64_t element to a message
980 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
981 const char *attr_name, int64_t v)
983 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
984 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
988 add a uint64_t element to a message
990 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
991 const char *attr_name, uint64_t v)
993 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
997 add a samr_Password element to a message
999 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1000 const char *attr_name, const struct samr_Password *hash)
1003 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1005 return ldb_oom(sam_ldb);
1008 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1012 add a samr_Password array to a message
1014 int samdb_msg_add_hashes(struct ldb_context *ldb,
1015 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1016 const char *attr_name, struct samr_Password *hashes,
1021 val.data = talloc_array_size(mem_ctx, 16, count);
1022 val.length = count*16;
1024 return ldb_oom(ldb);
1026 for (i=0;i<count;i++) {
1027 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1029 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1033 add a acct_flags element to a message
1035 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1036 const char *attr_name, uint32_t v)
1038 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1042 add a logon_hours element to a message
1044 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1045 const char *attr_name, struct samr_LogonHours *hours)
1048 val.length = hours->units_per_week / 8;
1049 val.data = hours->bits;
1050 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1054 add a parameters element to a message
1056 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1057 const char *attr_name, struct lsa_BinaryString *parameters)
1060 val.length = parameters->length;
1061 val.data = (uint8_t *)parameters->array;
1062 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1065 add a general value element to a message
1067 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1068 const char *attr_name, const struct ldb_val *val)
1070 return ldb_msg_add_value(msg, attr_name, val, NULL);
1074 sets a general value element to a message
1076 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1077 const char *attr_name, const struct ldb_val *val)
1079 struct ldb_message_element *el;
1081 el = ldb_msg_find_element(msg, attr_name);
1085 return ldb_msg_add_value(msg, attr_name, val, NULL);
1089 set a string element in a message
1091 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1092 const char *attr_name, const char *str)
1094 struct ldb_message_element *el;
1096 el = ldb_msg_find_element(msg, attr_name);
1100 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1104 * Handle ldb_request in transaction
1106 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1107 struct ldb_request *req)
1111 ret = ldb_transaction_start(sam_ldb);
1112 if (ret != LDB_SUCCESS) {
1116 ret = ldb_request(sam_ldb, req);
1117 if (ret == LDB_SUCCESS) {
1118 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1121 if (ret == LDB_SUCCESS) {
1122 return ldb_transaction_commit(sam_ldb);
1124 ldb_transaction_cancel(sam_ldb);
1130 return a default security descriptor
1132 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1134 struct security_descriptor *sd;
1136 sd = security_descriptor_initialise(mem_ctx);
1141 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1143 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1144 struct ldb_dn *aggregate_dn;
1149 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1150 if (!aggregate_dn) {
1153 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1156 return aggregate_dn;
1159 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1161 struct ldb_dn *new_dn;
1163 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1164 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1165 talloc_free(new_dn);
1171 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1173 struct ldb_dn *new_dn;
1175 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1176 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1177 talloc_free(new_dn);
1183 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1185 struct ldb_dn *new_dn;
1187 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1188 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1189 talloc_free(new_dn);
1196 work out the domain sid for the current open ldb
1198 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1200 TALLOC_CTX *tmp_ctx;
1201 const struct dom_sid *domain_sid;
1202 const char *attrs[] = {
1206 struct ldb_result *res;
1209 /* see if we have a cached copy */
1210 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1215 tmp_ctx = talloc_new(ldb);
1216 if (tmp_ctx == NULL) {
1220 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1222 if (ret != LDB_SUCCESS) {
1226 if (res->count != 1) {
1230 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1231 if (domain_sid == NULL) {
1235 /* cache the domain_sid in the ldb */
1236 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1240 talloc_steal(ldb, domain_sid);
1241 talloc_free(tmp_ctx);
1246 talloc_free(tmp_ctx);
1251 get domain sid from cache
1253 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1255 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1258 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1260 TALLOC_CTX *tmp_ctx;
1261 struct dom_sid *dom_sid_new;
1262 struct dom_sid *dom_sid_old;
1264 /* see if we have a cached copy */
1265 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1266 "cache.domain_sid"), struct dom_sid);
1268 tmp_ctx = talloc_new(ldb);
1269 if (tmp_ctx == NULL) {
1273 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1278 /* cache the domain_sid in the ldb */
1279 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1283 talloc_steal(ldb, dom_sid_new);
1284 talloc_free(tmp_ctx);
1285 talloc_free(dom_sid_old);
1290 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1291 talloc_free(tmp_ctx);
1295 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1297 TALLOC_CTX *tmp_ctx;
1298 struct ldb_dn *ntds_settings_dn_new;
1299 struct ldb_dn *ntds_settings_dn_old;
1301 /* see if we have a cached copy */
1302 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1303 "cache.ntds_settings_dn"), struct ldb_dn);
1305 tmp_ctx = talloc_new(ldb);
1306 if (tmp_ctx == NULL) {
1310 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1311 if (!ntds_settings_dn_new) {
1315 /* cache the domain_sid in the ldb */
1316 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1320 talloc_steal(ldb, ntds_settings_dn_new);
1321 talloc_free(tmp_ctx);
1322 talloc_free(ntds_settings_dn_old);
1327 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1328 talloc_free(tmp_ctx);
1332 /* Obtain the short name of the flexible single master operator
1333 * (FSMO), such as the PDC Emulator */
1334 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1337 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1338 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1339 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1340 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1342 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1343 /* Ensure this matches the format. This gives us a
1344 * bit more confidence that a 'cn' value will be a
1349 return (char *)val->data;
1355 work out the ntds settings dn for the current open ldb
1357 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1359 TALLOC_CTX *tmp_ctx;
1360 const char *root_attrs[] = { "dsServiceName", NULL };
1362 struct ldb_result *root_res;
1363 struct ldb_dn *settings_dn;
1365 /* see if we have a cached copy */
1366 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1371 tmp_ctx = talloc_new(ldb);
1372 if (tmp_ctx == NULL) {
1376 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1378 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1379 ldb_errstring(ldb)));
1383 if (root_res->count != 1) {
1387 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1389 /* cache the domain_sid in the ldb */
1390 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1394 talloc_steal(ldb, settings_dn);
1395 talloc_free(tmp_ctx);
1400 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1401 talloc_free(tmp_ctx);
1406 work out the ntds settings invocationId for the current open ldb
1408 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1410 TALLOC_CTX *tmp_ctx;
1411 const char *attrs[] = { "invocationId", NULL };
1413 struct ldb_result *res;
1414 struct GUID *invocation_id;
1416 /* see if we have a cached copy */
1417 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1418 if (invocation_id) {
1419 return invocation_id;
1422 tmp_ctx = talloc_new(ldb);
1423 if (tmp_ctx == NULL) {
1427 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1432 if (res->count != 1) {
1436 invocation_id = talloc(tmp_ctx, struct GUID);
1437 if (!invocation_id) {
1441 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1443 /* cache the domain_sid in the ldb */
1444 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1448 talloc_steal(ldb, invocation_id);
1449 talloc_free(tmp_ctx);
1451 return invocation_id;
1454 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1455 talloc_free(tmp_ctx);
1459 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1461 TALLOC_CTX *tmp_ctx;
1462 struct GUID *invocation_id_new;
1463 struct GUID *invocation_id_old;
1465 /* see if we have a cached copy */
1466 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1467 "cache.invocation_id");
1469 tmp_ctx = talloc_new(ldb);
1470 if (tmp_ctx == NULL) {
1474 invocation_id_new = talloc(tmp_ctx, struct GUID);
1475 if (!invocation_id_new) {
1479 *invocation_id_new = *invocation_id_in;
1481 /* cache the domain_sid in the ldb */
1482 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1486 talloc_steal(ldb, invocation_id_new);
1487 talloc_free(tmp_ctx);
1488 talloc_free(invocation_id_old);
1493 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1494 talloc_free(tmp_ctx);
1499 work out the ntds settings objectGUID for the current open ldb
1501 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1503 TALLOC_CTX *tmp_ctx;
1504 const char *attrs[] = { "objectGUID", NULL };
1506 struct ldb_result *res;
1507 struct GUID *ntds_guid;
1509 /* see if we have a cached copy */
1510 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1515 tmp_ctx = talloc_new(ldb);
1516 if (tmp_ctx == NULL) {
1520 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1525 if (res->count != 1) {
1529 ntds_guid = talloc(tmp_ctx, struct GUID);
1534 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1536 /* cache the domain_sid in the ldb */
1537 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1541 talloc_steal(ldb, ntds_guid);
1542 talloc_free(tmp_ctx);
1547 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1548 talloc_free(tmp_ctx);
1552 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1554 TALLOC_CTX *tmp_ctx;
1555 struct GUID *ntds_guid_new;
1556 struct GUID *ntds_guid_old;
1558 /* see if we have a cached copy */
1559 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1561 tmp_ctx = talloc_new(ldb);
1562 if (tmp_ctx == NULL) {
1566 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1567 if (!ntds_guid_new) {
1571 *ntds_guid_new = *ntds_guid_in;
1573 /* cache the domain_sid in the ldb */
1574 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1578 talloc_steal(ldb, ntds_guid_new);
1579 talloc_free(tmp_ctx);
1580 talloc_free(ntds_guid_old);
1585 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1586 talloc_free(tmp_ctx);
1591 work out the server dn for the current open ldb
1593 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1595 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1599 work out the server dn for the current open ldb
1601 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1603 struct ldb_dn *server_dn;
1604 struct ldb_dn *servers_dn;
1605 struct ldb_dn *server_site_dn;
1607 /* TODO: there must be a saner way to do this!! */
1608 server_dn = samdb_server_dn(ldb, mem_ctx);
1609 if (!server_dn) return NULL;
1611 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1612 talloc_free(server_dn);
1613 if (!servers_dn) return NULL;
1615 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1616 talloc_free(servers_dn);
1618 return server_site_dn;
1622 find a 'reference' DN that points at another object
1623 (eg. serverReference, rIDManagerReference etc)
1625 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1626 const char *attribute, struct ldb_dn **dn)
1628 const char *attrs[2];
1629 struct ldb_result *res;
1632 attrs[0] = attribute;
1635 ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
1636 if (ret != LDB_SUCCESS) {
1639 if (res->count != 1) {
1641 return LDB_ERR_NO_SUCH_OBJECT;
1644 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1647 ldb_asprintf_errstring(ldb, "Cannot find dn of attribute %s of %s", attribute,
1648 ldb_dn_get_linearized(base));
1649 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1657 find our machine account via the serverReference attribute in the
1660 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1662 struct ldb_dn *server_dn;
1665 server_dn = samdb_server_dn(ldb, mem_ctx);
1666 if (server_dn == NULL) {
1667 return LDB_ERR_NO_SUCH_OBJECT;
1670 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1671 talloc_free(server_dn);
1677 find the RID Manager$ DN via the rIDManagerReference attribute in the
1680 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1682 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1683 "rIDManagerReference", dn);
1687 find the RID Set DN via the rIDSetReferences attribute in our
1690 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1692 struct ldb_dn *server_ref_dn;
1695 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1696 if (ret != LDB_SUCCESS) {
1699 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1700 talloc_free(server_ref_dn);
1704 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1706 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1713 return (const char *) val->data;
1717 * Finds the client site by using the client's IP address.
1718 * The "subnet_name" returns the name of the subnet if parameter != NULL
1720 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1721 const char *ip_address, char **subnet_name)
1723 const char *attrs[] = { "cn", "siteObject", NULL };
1724 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1725 struct ldb_result *res;
1726 const struct ldb_val *val;
1727 const char *site_name = NULL, *l_subnet_name = NULL;
1728 const char *allow_list[2] = { NULL, NULL };
1729 unsigned int i, count;
1733 * if we don't have a client ip e.g. ncalrpc
1734 * the server site is the client site
1736 if (ip_address == NULL) {
1737 return samdb_server_site_name(ldb, mem_ctx);
1740 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1741 if (sites_container_dn == NULL) {
1745 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1746 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1747 talloc_free(sites_container_dn);
1748 talloc_free(subnets_dn);
1752 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1754 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1756 } else if (ret != LDB_SUCCESS) {
1757 talloc_free(sites_container_dn);
1758 talloc_free(subnets_dn);
1764 for (i = 0; i < count; i++) {
1765 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1768 allow_list[0] = l_subnet_name;
1770 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1771 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1774 if (sites_dn == NULL) {
1775 /* No reference, maybe another subnet matches */
1779 /* "val" cannot be NULL here since "sites_dn" != NULL */
1780 val = ldb_dn_get_rdn_val(sites_dn);
1781 site_name = talloc_strdup(mem_ctx,
1782 (const char *) val->data);
1784 talloc_free(sites_dn);
1790 if (site_name == NULL) {
1791 /* This is the Windows Server fallback rule: when no subnet
1792 * exists and we have only one site available then use it (it
1793 * is for sure the same as our server site). If more sites do
1794 * exist then we don't know which one to use and set the site
1796 cnt = samdb_search_count(ldb, sites_container_dn,
1797 "(objectClass=site)");
1799 site_name = samdb_server_site_name(ldb, mem_ctx);
1801 site_name = talloc_strdup(mem_ctx, "");
1803 l_subnet_name = NULL;
1806 if (subnet_name != NULL) {
1807 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1810 talloc_free(sites_container_dn);
1811 talloc_free(subnets_dn);
1818 work out if we are the PDC for the domain of the current open ldb
1820 bool samdb_is_pdc(struct ldb_context *ldb)
1822 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1824 struct ldb_result *dom_res;
1825 TALLOC_CTX *tmp_ctx;
1829 tmp_ctx = talloc_new(ldb);
1830 if (tmp_ctx == NULL) {
1831 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1835 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1836 if (ret != LDB_SUCCESS) {
1837 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1838 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1839 ldb_errstring(ldb)));
1842 if (dom_res->count != 1) {
1846 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1848 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1854 talloc_free(tmp_ctx);
1859 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1860 talloc_free(tmp_ctx);
1865 work out if we are a Global Catalog server for the domain of the current open ldb
1867 bool samdb_is_gc(struct ldb_context *ldb)
1869 const char *attrs[] = { "options", NULL };
1871 struct ldb_result *res;
1872 TALLOC_CTX *tmp_ctx;
1874 tmp_ctx = talloc_new(ldb);
1875 if (tmp_ctx == NULL) {
1876 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1880 /* Query cn=ntds settings,.... */
1881 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1882 if (ret != LDB_SUCCESS) {
1883 talloc_free(tmp_ctx);
1886 if (res->count != 1) {
1887 talloc_free(tmp_ctx);
1891 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1892 talloc_free(tmp_ctx);
1894 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1895 if (options & 0x000000001) {
1901 /* Find a domain object in the parents of a particular DN. */
1902 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1903 struct ldb_dn **parent_dn, const char **errstring)
1905 TALLOC_CTX *local_ctx;
1906 struct ldb_dn *sdn = dn;
1907 struct ldb_result *res = NULL;
1908 int ret = LDB_SUCCESS;
1909 const char *attrs[] = { NULL };
1911 local_ctx = talloc_new(mem_ctx);
1912 if (local_ctx == NULL) return ldb_oom(ldb);
1914 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1915 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1916 "(|(objectClass=domain)(objectClass=builtinDomain))");
1917 if (ret == LDB_SUCCESS) {
1918 if (res->count == 1) {
1926 if (ret != LDB_SUCCESS) {
1927 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1928 ldb_dn_get_linearized(dn),
1929 ldb_dn_get_linearized(sdn),
1930 ldb_errstring(ldb));
1931 talloc_free(local_ctx);
1934 if (res->count != 1) {
1935 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1936 ldb_dn_get_linearized(dn));
1937 DEBUG(0,(__location__ ": %s\n", *errstring));
1938 talloc_free(local_ctx);
1939 return LDB_ERR_CONSTRAINT_VIOLATION;
1942 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1943 talloc_free(local_ctx);
1949 * Performs checks on a user password (plaintext UNIX format - attribute
1950 * "password"). The remaining parameters have to be extracted from the domain
1953 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1955 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1956 const uint32_t pwdProperties,
1957 const uint32_t minPwdLength)
1959 /* checks if the "minPwdLength" property is satisfied */
1960 if (minPwdLength > password->length)
1961 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1963 /* checks the password complexity */
1964 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1965 && (password->data != NULL)
1966 && (!check_password_quality((const char *) password->data)))
1967 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1969 return SAMR_VALIDATION_STATUS_SUCCESS;
1973 * Callback for "samdb_set_password" password change
1975 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
1980 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1983 if (ares->error != LDB_SUCCESS) {
1985 req->context = talloc_steal(req,
1986 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1988 return ldb_request_done(req, ret);
1991 if (ares->type != LDB_REPLY_DONE) {
1993 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1996 req->context = talloc_steal(req,
1997 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1999 return ldb_request_done(req, LDB_SUCCESS);
2003 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2004 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2005 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2006 * user change or not. The "rejectReason" gives some more informations if the
2009 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2010 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2012 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2013 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2014 const DATA_BLOB *new_password,
2015 const struct samr_Password *lmNewHash,
2016 const struct samr_Password *ntNewHash,
2017 const struct samr_Password *lmOldHash,
2018 const struct samr_Password *ntOldHash,
2019 enum samPwdChangeReason *reject_reason,
2020 struct samr_DomInfo1 **_dominfo)
2022 struct ldb_message *msg;
2023 struct ldb_message_element *el;
2024 struct ldb_request *req;
2025 struct dsdb_control_password_change_status *pwd_stat = NULL;
2027 NTSTATUS status = NT_STATUS_OK;
2029 #define CHECK_RET(x) \
2030 if (x != LDB_SUCCESS) { \
2032 return NT_STATUS_NO_MEMORY; \
2035 msg = ldb_msg_new(mem_ctx);
2037 return NT_STATUS_NO_MEMORY;
2040 if ((new_password != NULL)
2041 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2042 /* we have the password as plaintext UTF16 */
2043 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2044 "clearTextPassword", new_password));
2045 el = ldb_msg_find_element(msg, "clearTextPassword");
2046 el->flags = LDB_FLAG_MOD_REPLACE;
2047 } else if ((new_password == NULL)
2048 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2049 /* we have a password as LM and/or NT hash */
2050 if (lmNewHash != NULL) {
2051 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2052 "dBCSPwd", lmNewHash));
2053 el = ldb_msg_find_element(msg, "dBCSPwd");
2054 el->flags = LDB_FLAG_MOD_REPLACE;
2056 if (ntNewHash != NULL) {
2057 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2058 "unicodePwd", ntNewHash));
2059 el = ldb_msg_find_element(msg, "unicodePwd");
2060 el->flags = LDB_FLAG_MOD_REPLACE;
2063 /* the password wasn't specified correctly */
2065 return NT_STATUS_INVALID_PARAMETER;
2068 /* build modify request */
2069 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2070 samdb_set_password_callback, NULL);
2071 if (ret != LDB_SUCCESS) {
2073 return NT_STATUS_NO_MEMORY;
2076 /* A password change operation */
2077 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2078 struct dsdb_control_password_change *change;
2080 change = talloc(req, struct dsdb_control_password_change);
2081 if (change == NULL) {
2084 return NT_STATUS_NO_MEMORY;
2087 change->old_nt_pwd_hash = ntOldHash;
2088 change->old_lm_pwd_hash = lmOldHash;
2090 ret = ldb_request_add_control(req,
2091 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2093 if (ret != LDB_SUCCESS) {
2096 return NT_STATUS_NO_MEMORY;
2099 ret = ldb_request_add_control(req,
2100 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2102 if (ret != LDB_SUCCESS) {
2105 return NT_STATUS_NO_MEMORY;
2107 ret = ldb_request_add_control(req,
2108 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2110 if (ret != LDB_SUCCESS) {
2113 return NT_STATUS_NO_MEMORY;
2116 ret = dsdb_autotransaction_request(ldb, req);
2118 if (req->context != NULL) {
2119 pwd_stat = talloc_steal(mem_ctx,
2120 ((struct ldb_control *)req->context)->data);
2126 /* Sets the domain info (if requested) */
2127 if (_dominfo != NULL) {
2128 struct samr_DomInfo1 *dominfo;
2130 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2131 if (dominfo == NULL) {
2132 return NT_STATUS_NO_MEMORY;
2135 if (pwd_stat != NULL) {
2136 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2137 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2138 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2139 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2140 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2143 *_dominfo = dominfo;
2146 if (reject_reason != NULL) {
2147 if (pwd_stat != NULL) {
2148 *reject_reason = pwd_stat->reject_reason;
2150 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2154 if (pwd_stat != NULL) {
2155 talloc_free(pwd_stat);
2158 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2159 const char *errmsg = ldb_errstring(ldb);
2160 char *endptr = NULL;
2161 WERROR werr = WERR_GENERAL_FAILURE;
2162 status = NT_STATUS_UNSUCCESSFUL;
2163 if (errmsg != NULL) {
2164 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2166 if (endptr != errmsg) {
2167 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2168 status = NT_STATUS_WRONG_PASSWORD;
2170 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2171 status = NT_STATUS_PASSWORD_RESTRICTION;
2174 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2175 /* don't let the caller know if an account doesn't exist */
2176 status = NT_STATUS_WRONG_PASSWORD;
2177 } else if (ret != LDB_SUCCESS) {
2178 status = NT_STATUS_UNSUCCESSFUL;
2185 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2186 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2187 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2188 * user change or not. The "rejectReason" gives some more informations if the
2191 * This wrapper function for "samdb_set_password" takes a SID as input rather
2194 * This call encapsulates a new LDB transaction for changing the password;
2195 * therefore the user hasn't to start a new one.
2197 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2198 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2199 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2200 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2202 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2203 const struct dom_sid *user_sid,
2204 const DATA_BLOB *new_password,
2205 const struct samr_Password *lmNewHash,
2206 const struct samr_Password *ntNewHash,
2207 const struct samr_Password *lmOldHash,
2208 const struct samr_Password *ntOldHash,
2209 enum samPwdChangeReason *reject_reason,
2210 struct samr_DomInfo1 **_dominfo)
2213 struct ldb_dn *user_dn;
2216 ret = ldb_transaction_start(ldb);
2217 if (ret != LDB_SUCCESS) {
2218 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2219 return NT_STATUS_TRANSACTION_ABORTED;
2222 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2223 "(&(objectSid=%s)(objectClass=user))",
2224 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2226 ldb_transaction_cancel(ldb);
2227 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2228 dom_sid_string(mem_ctx, user_sid)));
2229 return NT_STATUS_NO_SUCH_USER;
2232 nt_status = samdb_set_password(ldb, mem_ctx,
2235 lmNewHash, ntNewHash,
2236 lmOldHash, ntOldHash,
2237 reject_reason, _dominfo);
2238 if (!NT_STATUS_IS_OK(nt_status)) {
2239 ldb_transaction_cancel(ldb);
2240 talloc_free(user_dn);
2244 ret = ldb_transaction_commit(ldb);
2245 if (ret != LDB_SUCCESS) {
2246 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2247 ldb_dn_get_linearized(user_dn),
2248 ldb_errstring(ldb)));
2249 talloc_free(user_dn);
2250 return NT_STATUS_TRANSACTION_ABORTED;
2253 talloc_free(user_dn);
2254 return NT_STATUS_OK;
2258 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2259 struct dom_sid *sid, struct ldb_dn **ret_dn)
2261 struct ldb_message *msg;
2262 struct ldb_dn *basedn;
2266 sidstr = dom_sid_string(mem_ctx, sid);
2267 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2269 /* We might have to create a ForeignSecurityPrincipal, even if this user
2270 * is in our own domain */
2272 msg = ldb_msg_new(sidstr);
2274 talloc_free(sidstr);
2275 return NT_STATUS_NO_MEMORY;
2278 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2279 ldb_get_default_basedn(sam_ctx),
2280 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2282 if (ret != LDB_SUCCESS) {
2283 DEBUG(0, ("Failed to find DN for "
2284 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2285 talloc_free(sidstr);
2286 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2289 /* add core elements to the ldb_message for the alias */
2291 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2292 talloc_free(sidstr);
2293 return NT_STATUS_NO_MEMORY;
2296 samdb_msg_add_string(sam_ctx, msg, msg,
2298 "foreignSecurityPrincipal");
2300 /* create the alias */
2301 ret = ldb_add(sam_ctx, msg);
2302 if (ret != LDB_SUCCESS) {
2303 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2305 ldb_dn_get_linearized(msg->dn),
2306 ldb_errstring(sam_ctx)));
2307 talloc_free(sidstr);
2308 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2311 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2312 talloc_free(sidstr);
2314 return NT_STATUS_OK;
2319 Find the DN of a domain, assuming it to be a dotted.dns name
2322 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2325 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2326 const char *binary_encoded;
2327 const char **split_realm;
2334 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2336 talloc_free(tmp_ctx);
2339 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2340 for (i=0; split_realm[i]; i++) {
2341 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2342 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2343 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2344 binary_encoded, ldb_dn_get_linearized(dn)));
2345 talloc_free(tmp_ctx);
2349 if (!ldb_dn_validate(dn)) {
2350 DEBUG(2, ("Failed to validated DN %s\n",
2351 ldb_dn_get_linearized(dn)));
2352 talloc_free(tmp_ctx);
2355 talloc_free(tmp_ctx);
2360 Find the DN of a domain, be it the netbios or DNS name
2362 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2363 const char *domain_name)
2365 const char * const domain_ref_attrs[] = {
2368 const char * const domain_ref2_attrs[] = {
2371 struct ldb_result *res_domain_ref;
2372 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2373 /* find the domain's DN */
2374 int ret_domain = ldb_search(ldb, mem_ctx,
2376 samdb_partitions_dn(ldb, mem_ctx),
2379 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2381 if (ret_domain != LDB_SUCCESS) {
2385 if (res_domain_ref->count == 0) {
2386 ret_domain = ldb_search(ldb, mem_ctx,
2388 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2391 "(objectclass=domain)");
2392 if (ret_domain != LDB_SUCCESS) {
2396 if (res_domain_ref->count == 1) {
2397 return res_domain_ref->msgs[0]->dn;
2402 if (res_domain_ref->count > 1) {
2403 DEBUG(0,("Found %d records matching domain [%s]\n",
2404 ret_domain, domain_name));
2408 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2414 use a GUID to find a DN
2416 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2417 TALLOC_CTX *mem_ctx,
2418 const struct GUID *guid, struct ldb_dn **dn)
2421 struct ldb_result *res;
2422 const char *attrs[] = { NULL };
2423 char *guid_str = GUID_string(mem_ctx, guid);
2426 return ldb_operr(ldb);
2429 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2430 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2431 DSDB_SEARCH_SHOW_EXTENDED_DN |
2432 DSDB_SEARCH_ONE_ONLY,
2433 "objectGUID=%s", guid_str);
2434 talloc_free(guid_str);
2435 if (ret != LDB_SUCCESS) {
2439 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2446 use a DN to find a GUID with a given attribute name
2448 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2449 struct ldb_dn *dn, const char *attribute,
2453 struct ldb_result *res;
2454 const char *attrs[2];
2455 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2457 attrs[0] = attribute;
2460 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2461 if (ret != LDB_SUCCESS) {
2462 talloc_free(tmp_ctx);
2465 if (res->count < 1) {
2466 talloc_free(tmp_ctx);
2467 return LDB_ERR_NO_SUCH_OBJECT;
2469 *guid = samdb_result_guid(res->msgs[0], attribute);
2470 talloc_free(tmp_ctx);
2475 use a DN to find a GUID
2477 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2478 struct ldb_dn *dn, struct GUID *guid)
2480 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2486 adds the given GUID to the given ldb_message. This value is added
2487 for the given attr_name (may be either "objectGUID" or "parentGUID").
2489 int dsdb_msg_add_guid(struct ldb_message *msg,
2491 const char *attr_name)
2496 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2498 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2499 if (!NT_STATUS_IS_OK(status)) {
2500 ret = LDB_ERR_OPERATIONS_ERROR;
2504 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2505 if (ret != LDB_SUCCESS) {
2506 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2514 talloc_free(tmp_ctx);
2521 use a DN to find a SID
2523 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2524 struct ldb_dn *dn, struct dom_sid *sid)
2527 struct ldb_result *res;
2528 const char *attrs[] = { "objectSid", NULL };
2529 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2534 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2535 if (ret != LDB_SUCCESS) {
2536 talloc_free(tmp_ctx);
2539 if (res->count < 1) {
2540 talloc_free(tmp_ctx);
2541 return LDB_ERR_NO_SUCH_OBJECT;
2543 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2545 talloc_free(tmp_ctx);
2546 return LDB_ERR_NO_SUCH_OBJECT;
2549 talloc_free(tmp_ctx);
2554 use a SID to find a DN
2556 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2557 TALLOC_CTX *mem_ctx,
2558 struct dom_sid *sid, struct ldb_dn **dn)
2561 struct ldb_result *res;
2562 const char *attrs[] = { NULL };
2563 char *sid_str = dom_sid_string(mem_ctx, sid);
2566 return ldb_operr(ldb);
2569 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2570 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2571 DSDB_SEARCH_SHOW_EXTENDED_DN |
2572 DSDB_SEARCH_ONE_ONLY,
2573 "objectSid=%s", sid_str);
2574 talloc_free(sid_str);
2575 if (ret != LDB_SUCCESS) {
2579 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2586 load a repsFromTo blob list for a given partition GUID
2587 attr must be "repsFrom" or "repsTo"
2589 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2590 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2592 const char *attrs[] = { attr, NULL };
2593 struct ldb_result *res = NULL;
2594 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2596 struct ldb_message_element *el;
2601 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2603 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2604 talloc_free(tmp_ctx);
2605 return WERR_DS_DRA_INTERNAL_ERROR;
2608 el = ldb_msg_find_element(res->msgs[0], attr);
2610 /* it's OK to be empty */
2611 talloc_free(tmp_ctx);
2615 *count = el->num_values;
2616 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2618 talloc_free(tmp_ctx);
2619 return WERR_DS_DRA_INTERNAL_ERROR;
2622 for (i=0; i<(*count); i++) {
2623 enum ndr_err_code ndr_err;
2624 ndr_err = ndr_pull_struct_blob(&el->values[i],
2627 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2628 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2629 talloc_free(tmp_ctx);
2630 return WERR_DS_DRA_INTERNAL_ERROR;
2634 talloc_free(tmp_ctx);
2640 save the repsFromTo blob list for a given partition GUID
2641 attr must be "repsFrom" or "repsTo"
2643 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2644 const char *attr, struct repsFromToBlob *r, uint32_t count)
2646 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2647 struct ldb_message *msg;
2648 struct ldb_message_element *el;
2651 msg = ldb_msg_new(tmp_ctx);
2653 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2657 el->values = talloc_array(msg, struct ldb_val, count);
2662 for (i=0; i<count; i++) {
2664 enum ndr_err_code ndr_err;
2666 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2668 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2669 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2677 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2678 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2682 talloc_free(tmp_ctx);
2687 talloc_free(tmp_ctx);
2688 return WERR_DS_DRA_INTERNAL_ERROR;
2693 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2694 object for a partition
2696 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2697 uint64_t *uSN, uint64_t *urgent_uSN)
2699 struct ldb_request *req;
2701 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2702 struct dsdb_control_current_partition *p_ctrl;
2703 struct ldb_result *res;
2705 res = talloc_zero(tmp_ctx, struct ldb_result);
2707 talloc_free(tmp_ctx);
2708 return ldb_oom(ldb);
2711 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2712 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2716 res, ldb_search_default_callback,
2718 if (ret != LDB_SUCCESS) {
2719 talloc_free(tmp_ctx);
2723 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2724 if (p_ctrl == NULL) {
2725 talloc_free(tmp_ctx);
2726 return ldb_oom(ldb);
2728 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2731 ret = ldb_request_add_control(req,
2732 DSDB_CONTROL_CURRENT_PARTITION_OID,
2734 if (ret != LDB_SUCCESS) {
2735 talloc_free(tmp_ctx);
2739 /* Run the new request */
2740 ret = ldb_request(ldb, req);
2742 if (ret == LDB_SUCCESS) {
2743 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2746 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2747 /* it hasn't been created yet, which means
2748 an implicit value of zero */
2750 talloc_free(tmp_ctx);
2754 if (ret != LDB_SUCCESS) {
2755 talloc_free(tmp_ctx);
2759 if (res->count < 1) {
2765 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2767 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2771 talloc_free(tmp_ctx);
2776 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2777 const struct drsuapi_DsReplicaCursor2 *c2)
2779 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2782 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2783 const struct drsuapi_DsReplicaCursor *c2)
2785 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2790 see if a computer identified by its invocationId is a RODC
2792 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2794 /* 1) find the DN for this servers NTDSDSA object
2795 2) search for the msDS-isRODC attribute
2796 3) if not present then not a RODC
2797 4) if present and TRUE then is a RODC
2799 struct ldb_dn *config_dn;
2800 const char *attrs[] = { "msDS-isRODC", NULL };
2802 struct ldb_result *res;
2803 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2805 config_dn = ldb_get_config_basedn(sam_ctx);
2807 talloc_free(tmp_ctx);
2808 return ldb_operr(sam_ctx);
2811 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2812 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2814 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2816 talloc_free(tmp_ctx);
2820 if (ret != LDB_SUCCESS) {
2821 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2822 GUID_string(tmp_ctx, objectGUID)));
2824 talloc_free(tmp_ctx);
2828 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2829 *is_rodc = (ret == 1);
2831 talloc_free(tmp_ctx);
2837 see if we are a RODC
2839 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2841 const struct GUID *objectGUID;
2845 /* see if we have a cached copy */
2846 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2852 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2854 return ldb_operr(sam_ctx);
2857 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2858 if (ret != LDB_SUCCESS) {
2862 cached = talloc(sam_ctx, bool);
2863 if (cached == NULL) {
2864 return ldb_oom(sam_ctx);
2868 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2869 if (ret != LDB_SUCCESS) {
2870 talloc_free(cached);
2871 return ldb_operr(sam_ctx);
2877 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2879 TALLOC_CTX *tmp_ctx;
2882 tmp_ctx = talloc_new(ldb);
2883 if (tmp_ctx == NULL) {
2887 cached = talloc(tmp_ctx, bool);
2893 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2897 talloc_steal(ldb, cached);
2898 talloc_free(tmp_ctx);
2902 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2903 talloc_free(tmp_ctx);
2909 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2911 flags are DS_NTDS_OPTION_*
2913 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2915 TALLOC_CTX *tmp_ctx;
2916 const char *attrs[] = { "options", NULL };
2918 struct ldb_result *res;
2920 tmp_ctx = talloc_new(ldb);
2921 if (tmp_ctx == NULL) {
2925 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2926 if (ret != LDB_SUCCESS) {
2930 if (res->count != 1) {
2934 *options = samdb_result_uint(res->msgs[0], "options", 0);
2936 talloc_free(tmp_ctx);
2941 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2942 talloc_free(tmp_ctx);
2943 return LDB_ERR_NO_SUCH_OBJECT;
2946 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
2948 const char *attrs[] = { "objectCategory", NULL };
2950 struct ldb_result *res;
2952 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2953 if (ret != LDB_SUCCESS) {
2957 if (res->count != 1) {
2961 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
2964 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
2969 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2970 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2972 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2974 char **tokens, *ret;
2977 tokens = str_list_make(mem_ctx, cn, " -_");
2981 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2982 tokens[0][0] = tolower(tokens[0][0]);
2983 for (i = 1; i < str_list_length((const char **)tokens); i++)
2984 tokens[i][0] = toupper(tokens[i][0]);
2986 ret = talloc_strdup(mem_ctx, tokens[0]);
2987 for (i = 1; i < str_list_length((const char **)tokens); i++)
2988 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2990 talloc_free(tokens);
2996 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
2998 int dsdb_functional_level(struct ldb_context *ldb)
3000 int *domainFunctionality =
3001 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3002 if (!domainFunctionality) {
3003 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
3004 return DS_DOMAIN_FUNCTION_2000;
3006 return *domainFunctionality;
3010 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3012 int dsdb_forest_functional_level(struct ldb_context *ldb)
3014 int *forestFunctionality =
3015 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3016 if (!forestFunctionality) {
3017 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3018 return DS_DOMAIN_FUNCTION_2000;
3020 return *forestFunctionality;
3024 set a GUID in an extended DN structure
3026 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3032 status = GUID_to_ndr_blob(guid, dn, &v);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3037 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3043 return a GUID from a extended DN structure
3045 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3047 const struct ldb_val *v;
3049 v = ldb_dn_get_extended_component(dn, component_name);
3051 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3054 return GUID_from_ndr_blob(v, guid);
3058 return a uint64_t from a extended DN structure
3060 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3062 const struct ldb_val *v;
3065 v = ldb_dn_get_extended_component(dn, component_name);
3067 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3069 s = talloc_strndup(dn, (const char *)v->data, v->length);
3070 NT_STATUS_HAVE_NO_MEMORY(s);
3072 *val = strtoull(s, NULL, 0);
3075 return NT_STATUS_OK;
3079 return a NTTIME from a extended DN structure
3081 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3083 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3087 return a uint32_t from a extended DN structure
3089 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3091 const struct ldb_val *v;
3094 v = ldb_dn_get_extended_component(dn, component_name);
3096 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3099 s = talloc_strndup(dn, (const char *)v->data, v->length);
3100 NT_STATUS_HAVE_NO_MEMORY(s);
3102 *val = strtoul(s, NULL, 0);
3105 return NT_STATUS_OK;
3109 return a dom_sid from a extended DN structure
3111 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3113 const struct ldb_val *sid_blob;
3114 struct TALLOC_CTX *tmp_ctx;
3115 enum ndr_err_code ndr_err;
3117 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3119 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3122 tmp_ctx = talloc_new(NULL);
3124 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3125 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3127 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3128 talloc_free(tmp_ctx);
3132 talloc_free(tmp_ctx);
3133 return NT_STATUS_OK;
3138 return RMD_FLAGS directly from a ldb_dn
3139 returns 0 if not found
3141 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3143 const struct ldb_val *v;
3145 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3146 if (!v || v->length > sizeof(buf)-1) return 0;
3147 strncpy(buf, (const char *)v->data, v->length);
3149 return strtoul(buf, NULL, 10);
3153 return RMD_FLAGS directly from a ldb_val for a DN
3154 returns 0 if RMD_FLAGS is not found
3156 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3162 if (val->length < 13) {
3165 p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
3169 flags = strtoul(p+11, &end, 10);
3170 if (!end || *end != '>') {
3171 /* it must end in a > */
3178 return true if a ldb_val containing a DN in storage form is deleted
3180 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3182 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3186 return true if a ldb_val containing a DN in storage form is
3187 in the upgraded w2k3 linked attribute format
3189 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3191 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3195 return a DN for a wellknown GUID
3197 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3198 struct ldb_dn *nc_root, const char *wk_guid,
3199 struct ldb_dn **wkguid_dn)
3201 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3202 const char *attrs[] = { NULL };
3205 struct ldb_result *res;
3207 /* construct the magic WKGUID DN */
3208 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3209 wk_guid, ldb_dn_get_linearized(nc_root));
3211 talloc_free(tmp_ctx);
3212 return ldb_operr(samdb);
3215 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3216 if (ret != LDB_SUCCESS) {
3217 talloc_free(tmp_ctx);
3221 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3222 talloc_free(tmp_ctx);
3227 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3229 return ldb_dn_compare(*dn1, *dn2);
3233 find a NC root given a DN within the NC
3235 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3236 struct ldb_dn **nc_root)
3238 const char *root_attrs[] = { "namingContexts", NULL };
3239 TALLOC_CTX *tmp_ctx;
3241 struct ldb_message_element *el;
3242 struct ldb_result *root_res;
3244 struct ldb_dn **nc_dns;
3246 tmp_ctx = talloc_new(samdb);
3247 if (tmp_ctx == NULL) {
3248 return ldb_oom(samdb);
3251 ret = ldb_search(samdb, tmp_ctx, &root_res,
3252 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3253 if (ret != LDB_SUCCESS) {
3254 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3255 talloc_free(tmp_ctx);
3259 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3261 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3262 ldb_errstring(samdb)));
3263 talloc_free(tmp_ctx);
3264 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3267 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3269 talloc_free(tmp_ctx);
3270 return ldb_oom(samdb);
3273 for (i=0; i<el->num_values; i++) {
3274 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3275 if (nc_dns[i] == NULL) {
3276 talloc_free(tmp_ctx);
3277 return ldb_operr(samdb);
3281 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3283 for (i=0; i<el->num_values; i++) {
3284 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3285 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3286 talloc_free(tmp_ctx);
3291 talloc_free(tmp_ctx);
3292 return LDB_ERR_NO_SUCH_OBJECT;
3297 find the deleted objects DN for any object, by looking for the NC
3298 root, then looking up the wellknown GUID
3300 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3301 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3302 struct ldb_dn **do_dn)
3304 struct ldb_dn *nc_root;
3307 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3308 if (ret != LDB_SUCCESS) {
3312 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3313 talloc_free(nc_root);
3318 return the tombstoneLifetime, in days
3320 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3323 dn = ldb_get_config_basedn(ldb);
3325 return LDB_ERR_NO_SUCH_OBJECT;
3327 dn = ldb_dn_copy(ldb, dn);
3329 return ldb_operr(ldb);
3331 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3332 be a wellknown GUID for this */
3333 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3335 return ldb_operr(ldb);
3338 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3344 compare a ldb_val to a string case insensitively
3346 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3348 size_t len = strlen(s);
3350 if (len > v->length) return 1;
3351 ret = strncasecmp(s, (const char *)v->data, v->length);
3352 if (ret != 0) return ret;
3353 if (v->length > len && v->data[len] != 0) {
3361 load the UDV for a partition in v2 format
3362 The list is returned sorted, and with our local cursor added
3364 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3365 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3367 static const char *attrs[] = { "replUpToDateVector", NULL };
3368 struct ldb_result *r;
3369 const struct ldb_val *ouv_value;
3372 uint64_t highest_usn;
3373 const struct GUID *our_invocation_id;
3374 struct timeval now = timeval_current();
3376 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3377 if (ret != LDB_SUCCESS) {
3381 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3383 enum ndr_err_code ndr_err;
3384 struct replUpToDateVectorBlob ouv;
3386 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3387 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3390 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3392 if (ouv.version != 2) {
3393 /* we always store as version 2, and
3394 * replUpToDateVector is not replicated
3396 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3399 *count = ouv.ctr.ctr2.count;
3400 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3408 our_invocation_id = samdb_ntds_invocation_id(samdb);
3409 if (!our_invocation_id) {
3410 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3411 talloc_free(*cursors);
3412 return ldb_operr(samdb);
3415 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3416 if (ret != LDB_SUCCESS) {
3417 /* nothing to add - this can happen after a vampire */
3418 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3422 for (i=0; i<*count; i++) {
3423 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3424 (*cursors)[i].highest_usn = highest_usn;
3425 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3426 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3431 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3433 return ldb_oom(samdb);
3436 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3437 (*cursors)[*count].highest_usn = highest_usn;
3438 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3441 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3447 load the UDV for a partition in version 1 format
3448 The list is returned sorted, and with our local cursor added
3450 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3451 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3453 struct drsuapi_DsReplicaCursor2 *v2;
3457 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3458 if (ret != LDB_SUCCESS) {
3468 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3469 if (*cursors == NULL) {
3471 return ldb_oom(samdb);
3474 for (i=0; i<*count; i++) {
3475 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3476 (*cursors)[i].highest_usn = v2[i].highest_usn;
3483 add a set of controls to a ldb_request structure based on a set of
3484 flags. See util.h for a list of available flags
3486 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3489 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3490 struct ldb_search_options_control *options;
3491 /* Using the phantom root control allows us to search all partitions */
3492 options = talloc(req, struct ldb_search_options_control);
3493 if (options == NULL) {
3494 return LDB_ERR_OPERATIONS_ERROR;
3496 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3498 ret = ldb_request_add_control(req,
3499 LDB_CONTROL_SEARCH_OPTIONS_OID,
3501 if (ret != LDB_SUCCESS) {
3506 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3507 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3508 if (ret != LDB_SUCCESS) {
3513 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3514 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3515 if (ret != LDB_SUCCESS) {
3520 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3521 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3522 if (!extended_ctrl) {
3523 return LDB_ERR_OPERATIONS_ERROR;
3525 extended_ctrl->type = 1;
3527 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3528 if (ret != LDB_SUCCESS) {
3533 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3534 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3535 if (ret != LDB_SUCCESS) {
3540 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3541 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3542 if (ret != LDB_SUCCESS) {
3547 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3548 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3549 if (ret != LDB_SUCCESS) {
3554 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3555 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3556 if (ret != LDB_SUCCESS) {
3561 if (dsdb_flags & DSDB_TREE_DELETE) {
3562 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3563 if (ret != LDB_SUCCESS) {
3572 an add with a set of controls
3574 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3575 uint32_t dsdb_flags)
3577 struct ldb_request *req;
3580 ret = ldb_build_add_req(&req, ldb, ldb,
3584 ldb_op_default_callback,
3587 if (ret != LDB_SUCCESS) return ret;
3589 ret = dsdb_request_add_controls(req, dsdb_flags);
3590 if (ret != LDB_SUCCESS) {
3595 ret = dsdb_autotransaction_request(ldb, req);
3602 a modify with a set of controls
3604 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3605 uint32_t dsdb_flags)
3607 struct ldb_request *req;
3610 ret = ldb_build_mod_req(&req, ldb, ldb,
3614 ldb_op_default_callback,
3617 if (ret != LDB_SUCCESS) return ret;
3619 ret = dsdb_request_add_controls(req, dsdb_flags);
3620 if (ret != LDB_SUCCESS) {
3625 ret = dsdb_autotransaction_request(ldb, req);
3632 like dsdb_modify() but set all the element flags to
3633 LDB_FLAG_MOD_REPLACE
3635 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3639 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3640 for (i=0;i<msg->num_elements;i++) {
3641 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3644 return dsdb_modify(ldb, msg, dsdb_flags);
3649 search for attrs on one DN, allowing for dsdb_flags controls
3651 int dsdb_search_dn(struct ldb_context *ldb,
3652 TALLOC_CTX *mem_ctx,
3653 struct ldb_result **_res,
3654 struct ldb_dn *basedn,
3655 const char * const *attrs,
3656 uint32_t dsdb_flags)
3659 struct ldb_request *req;
3660 struct ldb_result *res;
3662 res = talloc_zero(mem_ctx, struct ldb_result);
3664 return ldb_oom(ldb);
3667 ret = ldb_build_search_req(&req, ldb, res,
3674 ldb_search_default_callback,
3676 if (ret != LDB_SUCCESS) {
3681 ret = dsdb_request_add_controls(req, dsdb_flags);
3682 if (ret != LDB_SUCCESS) {
3687 ret = ldb_request(ldb, req);
3688 if (ret == LDB_SUCCESS) {
3689 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3693 if (ret != LDB_SUCCESS) {
3703 general search with dsdb_flags for controls
3705 int dsdb_search(struct ldb_context *ldb,
3706 TALLOC_CTX *mem_ctx,
3707 struct ldb_result **_res,
3708 struct ldb_dn *basedn,
3709 enum ldb_scope scope,
3710 const char * const *attrs,
3711 uint32_t dsdb_flags,
3712 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3715 struct ldb_request *req;
3716 struct ldb_result *res;
3718 char *expression = NULL;
3719 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3721 res = talloc_zero(tmp_ctx, struct ldb_result);
3723 talloc_free(tmp_ctx);
3724 return ldb_oom(ldb);
3728 va_start(ap, exp_fmt);
3729 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3733 talloc_free(tmp_ctx);
3734 return ldb_oom(ldb);
3738 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3745 ldb_search_default_callback,
3747 if (ret != LDB_SUCCESS) {
3748 talloc_free(tmp_ctx);
3752 ret = dsdb_request_add_controls(req, dsdb_flags);
3753 if (ret != LDB_SUCCESS) {
3754 talloc_free(tmp_ctx);
3758 ret = ldb_request(ldb, req);
3759 if (ret == LDB_SUCCESS) {
3760 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3763 if (ret != LDB_SUCCESS) {
3764 talloc_free(tmp_ctx);
3768 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3769 if (res->count == 0) {
3770 talloc_free(tmp_ctx);
3771 return LDB_ERR_NO_SUCH_OBJECT;
3773 if (res->count != 1) {
3774 talloc_free(tmp_ctx);
3775 return LDB_ERR_CONSTRAINT_VIOLATION;
3779 *_res = talloc_steal(mem_ctx, res);
3780 talloc_free(tmp_ctx);
3787 general search with dsdb_flags for controls
3788 returns exactly 1 record or an error
3790 int dsdb_search_one(struct ldb_context *ldb,
3791 TALLOC_CTX *mem_ctx,
3792 struct ldb_message **msg,
3793 struct ldb_dn *basedn,
3794 enum ldb_scope scope,
3795 const char * const *attrs,
3796 uint32_t dsdb_flags,
3797 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3800 struct ldb_result *res;
3802 char *expression = NULL;
3803 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3805 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3807 res = talloc_zero(tmp_ctx, struct ldb_result);
3809 talloc_free(tmp_ctx);
3810 return ldb_oom(ldb);
3814 va_start(ap, exp_fmt);
3815 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3819 talloc_free(tmp_ctx);
3820 return ldb_oom(ldb);
3822 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3823 dsdb_flags, "%s", expression);
3825 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3829 if (ret != LDB_SUCCESS) {
3830 talloc_free(tmp_ctx);
3834 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3835 talloc_free(tmp_ctx);
3840 /* returns back the forest DNS name */
3841 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3843 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3844 ldb_get_root_basedn(ldb));
3847 if (forest_name == NULL) {
3851 p = strchr(forest_name, '/');
3860 validate that an DSA GUID belongs to the specified user sid.
3861 The user SID must be a domain controller account (either RODC or
3864 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3865 const struct GUID *dsa_guid,
3866 const struct dom_sid *sid)
3869 - find DN of record with the DSA GUID in the
3870 configuration partition (objectGUID)
3871 - remove "NTDS Settings" component from DN
3872 - do a base search on that DN for serverReference with
3874 - extract objectSid from resulting serverReference
3876 - check this sid matches the sid argument
3878 struct ldb_dn *config_dn;
3879 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3880 struct ldb_message *msg;
3881 const char *attrs1[] = { NULL };
3882 const char *attrs2[] = { "serverReference", NULL };
3884 struct ldb_dn *dn, *account_dn;
3885 struct dom_sid sid2;
3888 config_dn = ldb_get_config_basedn(ldb);
3890 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3891 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3892 if (ret != LDB_SUCCESS) {
3893 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3894 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3895 talloc_free(tmp_ctx);
3896 return ldb_operr(ldb);
3900 if (!ldb_dn_remove_child_components(dn, 1)) {
3901 talloc_free(tmp_ctx);
3902 return ldb_operr(ldb);
3905 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3906 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3907 "(objectClass=server)");
3908 if (ret != LDB_SUCCESS) {
3909 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3910 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3911 talloc_free(tmp_ctx);
3912 return ldb_operr(ldb);
3915 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
3916 if (account_dn == NULL) {
3917 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
3918 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3919 talloc_free(tmp_ctx);
3920 return ldb_operr(ldb);
3923 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
3924 if (!NT_STATUS_IS_OK(status)) {
3925 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
3926 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3927 talloc_free(tmp_ctx);
3928 return ldb_operr(ldb);
3931 if (!dom_sid_equal(sid, &sid2)) {
3932 /* someone is trying to spoof another account */
3933 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
3934 GUID_string(tmp_ctx, dsa_guid),
3935 dom_sid_string(tmp_ctx, sid),
3936 dom_sid_string(tmp_ctx, &sid2)));
3937 talloc_free(tmp_ctx);
3938 return ldb_operr(ldb);
3941 talloc_free(tmp_ctx);
3945 static const char *secret_attributes[] = {
3948 "initialAuthIncoming",
3949 "initialAuthOutgoing",
3953 "supplementalCredentials",
3954 "trustAuthIncoming",
3955 "trustAuthOutgoing",
3961 check if the attribute belongs to the RODC filtered attribute set
3962 Note that attributes that are in the filtered attribute set are the
3963 ones that _are_ always sent to a RODC
3965 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
3967 /* they never get secret attributes */
3968 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
3972 /* they do get non-secret critical attributes */
3973 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
3977 /* they do get non-secret attributes marked as being in the FAS */
3978 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
3982 /* other attributes are denied */