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 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1655 find our machine account via the serverReference attribute in the
1658 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1660 struct ldb_dn *server_dn;
1663 server_dn = samdb_server_dn(ldb, mem_ctx);
1664 if (server_dn == NULL) {
1665 return LDB_ERR_NO_SUCH_OBJECT;
1668 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1669 talloc_free(server_dn);
1675 find the RID Manager$ DN via the rIDManagerReference attribute in the
1678 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1680 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1681 "rIDManagerReference", dn);
1685 find the RID Set DN via the rIDSetReferences attribute in our
1688 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1690 struct ldb_dn *server_ref_dn;
1693 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1694 if (ret != LDB_SUCCESS) {
1697 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1698 talloc_free(server_ref_dn);
1702 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1704 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1711 return (const char *) val->data;
1715 * Finds the client site by using the client's IP address.
1716 * The "subnet_name" returns the name of the subnet if parameter != NULL
1718 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1719 const char *ip_address, char **subnet_name)
1721 const char *attrs[] = { "cn", "siteObject", NULL };
1722 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1723 struct ldb_result *res;
1724 const struct ldb_val *val;
1725 const char *site_name = NULL, *l_subnet_name = NULL;
1726 const char *allow_list[2] = { NULL, NULL };
1727 unsigned int i, count;
1731 * if we don't have a client ip e.g. ncalrpc
1732 * the server site is the client site
1734 if (ip_address == NULL) {
1735 return samdb_server_site_name(ldb, mem_ctx);
1738 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1739 if (sites_container_dn == NULL) {
1743 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1744 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1745 talloc_free(sites_container_dn);
1746 talloc_free(subnets_dn);
1750 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1752 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1754 } else if (ret != LDB_SUCCESS) {
1755 talloc_free(sites_container_dn);
1756 talloc_free(subnets_dn);
1762 for (i = 0; i < count; i++) {
1763 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1766 allow_list[0] = l_subnet_name;
1768 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1769 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1772 if (sites_dn == NULL) {
1773 /* No reference, maybe another subnet matches */
1777 /* "val" cannot be NULL here since "sites_dn" != NULL */
1778 val = ldb_dn_get_rdn_val(sites_dn);
1779 site_name = talloc_strdup(mem_ctx,
1780 (const char *) val->data);
1782 talloc_free(sites_dn);
1788 if (site_name == NULL) {
1789 /* This is the Windows Server fallback rule: when no subnet
1790 * exists and we have only one site available then use it (it
1791 * is for sure the same as our server site). If more sites do
1792 * exist then we don't know which one to use and set the site
1794 cnt = samdb_search_count(ldb, sites_container_dn,
1795 "(objectClass=site)");
1797 site_name = samdb_server_site_name(ldb, mem_ctx);
1799 site_name = talloc_strdup(mem_ctx, "");
1801 l_subnet_name = NULL;
1804 if (subnet_name != NULL) {
1805 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1808 talloc_free(sites_container_dn);
1809 talloc_free(subnets_dn);
1816 work out if we are the PDC for the domain of the current open ldb
1818 bool samdb_is_pdc(struct ldb_context *ldb)
1820 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1822 struct ldb_result *dom_res;
1823 TALLOC_CTX *tmp_ctx;
1827 tmp_ctx = talloc_new(ldb);
1828 if (tmp_ctx == NULL) {
1829 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1833 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1834 if (ret != LDB_SUCCESS) {
1835 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1836 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1837 ldb_errstring(ldb)));
1840 if (dom_res->count != 1) {
1844 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1846 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1852 talloc_free(tmp_ctx);
1857 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1858 talloc_free(tmp_ctx);
1863 work out if we are a Global Catalog server for the domain of the current open ldb
1865 bool samdb_is_gc(struct ldb_context *ldb)
1867 const char *attrs[] = { "options", NULL };
1869 struct ldb_result *res;
1870 TALLOC_CTX *tmp_ctx;
1872 tmp_ctx = talloc_new(ldb);
1873 if (tmp_ctx == NULL) {
1874 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1878 /* Query cn=ntds settings,.... */
1879 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1880 if (ret != LDB_SUCCESS) {
1881 talloc_free(tmp_ctx);
1884 if (res->count != 1) {
1885 talloc_free(tmp_ctx);
1889 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1890 talloc_free(tmp_ctx);
1892 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1893 if (options & 0x000000001) {
1899 /* Find a domain object in the parents of a particular DN. */
1900 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1901 struct ldb_dn **parent_dn, const char **errstring)
1903 TALLOC_CTX *local_ctx;
1904 struct ldb_dn *sdn = dn;
1905 struct ldb_result *res = NULL;
1906 int ret = LDB_SUCCESS;
1907 const char *attrs[] = { NULL };
1909 local_ctx = talloc_new(mem_ctx);
1910 if (local_ctx == NULL) return ldb_oom(ldb);
1912 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1913 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1914 "(|(objectClass=domain)(objectClass=builtinDomain))");
1915 if (ret == LDB_SUCCESS) {
1916 if (res->count == 1) {
1924 if (ret != LDB_SUCCESS) {
1925 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1926 ldb_dn_get_linearized(dn),
1927 ldb_dn_get_linearized(sdn),
1928 ldb_errstring(ldb));
1929 talloc_free(local_ctx);
1932 if (res->count != 1) {
1933 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1934 ldb_dn_get_linearized(dn));
1935 DEBUG(0,(__location__ ": %s\n", *errstring));
1936 talloc_free(local_ctx);
1937 return LDB_ERR_CONSTRAINT_VIOLATION;
1940 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1941 talloc_free(local_ctx);
1947 * Performs checks on a user password (plaintext UNIX format - attribute
1948 * "password"). The remaining parameters have to be extracted from the domain
1951 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1953 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1954 const uint32_t pwdProperties,
1955 const uint32_t minPwdLength)
1957 /* checks if the "minPwdLength" property is satisfied */
1958 if (minPwdLength > password->length)
1959 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1961 /* checks the password complexity */
1962 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1963 && (password->data != NULL)
1964 && (!check_password_quality((const char *) password->data)))
1965 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1967 return SAMR_VALIDATION_STATUS_SUCCESS;
1971 * Callback for "samdb_set_password" password change
1973 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
1978 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1981 if (ares->error != LDB_SUCCESS) {
1983 req->context = talloc_steal(req,
1984 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1986 return ldb_request_done(req, ret);
1989 if (ares->type != LDB_REPLY_DONE) {
1991 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1994 req->context = talloc_steal(req,
1995 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1997 return ldb_request_done(req, LDB_SUCCESS);
2001 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2002 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2003 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2004 * user change or not. The "rejectReason" gives some more informations if the
2007 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2008 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2010 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2011 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2012 const DATA_BLOB *new_password,
2013 const struct samr_Password *lmNewHash,
2014 const struct samr_Password *ntNewHash,
2015 const struct samr_Password *lmOldHash,
2016 const struct samr_Password *ntOldHash,
2017 enum samPwdChangeReason *reject_reason,
2018 struct samr_DomInfo1 **_dominfo)
2020 struct ldb_message *msg;
2021 struct ldb_message_element *el;
2022 struct ldb_request *req;
2023 struct dsdb_control_password_change_status *pwd_stat = NULL;
2025 NTSTATUS status = NT_STATUS_OK;
2027 #define CHECK_RET(x) \
2028 if (x != LDB_SUCCESS) { \
2030 return NT_STATUS_NO_MEMORY; \
2033 msg = ldb_msg_new(mem_ctx);
2035 return NT_STATUS_NO_MEMORY;
2038 if ((new_password != NULL)
2039 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2040 /* we have the password as plaintext UTF16 */
2041 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2042 "clearTextPassword", new_password));
2043 el = ldb_msg_find_element(msg, "clearTextPassword");
2044 el->flags = LDB_FLAG_MOD_REPLACE;
2045 } else if ((new_password == NULL)
2046 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2047 /* we have a password as LM and/or NT hash */
2048 if (lmNewHash != NULL) {
2049 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2050 "dBCSPwd", lmNewHash));
2051 el = ldb_msg_find_element(msg, "dBCSPwd");
2052 el->flags = LDB_FLAG_MOD_REPLACE;
2054 if (ntNewHash != NULL) {
2055 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2056 "unicodePwd", ntNewHash));
2057 el = ldb_msg_find_element(msg, "unicodePwd");
2058 el->flags = LDB_FLAG_MOD_REPLACE;
2061 /* the password wasn't specified correctly */
2063 return NT_STATUS_INVALID_PARAMETER;
2066 /* build modify request */
2067 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2068 samdb_set_password_callback, NULL);
2069 if (ret != LDB_SUCCESS) {
2071 return NT_STATUS_NO_MEMORY;
2074 /* A password change operation */
2075 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2076 struct dsdb_control_password_change *change;
2078 change = talloc(req, struct dsdb_control_password_change);
2079 if (change == NULL) {
2082 return NT_STATUS_NO_MEMORY;
2085 change->old_nt_pwd_hash = ntOldHash;
2086 change->old_lm_pwd_hash = lmOldHash;
2088 ret = ldb_request_add_control(req,
2089 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2091 if (ret != LDB_SUCCESS) {
2094 return NT_STATUS_NO_MEMORY;
2097 ret = ldb_request_add_control(req,
2098 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2100 if (ret != LDB_SUCCESS) {
2103 return NT_STATUS_NO_MEMORY;
2105 ret = ldb_request_add_control(req,
2106 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2108 if (ret != LDB_SUCCESS) {
2111 return NT_STATUS_NO_MEMORY;
2114 ret = dsdb_autotransaction_request(ldb, req);
2116 if (req->context != NULL) {
2117 pwd_stat = talloc_steal(mem_ctx,
2118 ((struct ldb_control *)req->context)->data);
2124 /* Sets the domain info (if requested) */
2125 if (_dominfo != NULL) {
2126 struct samr_DomInfo1 *dominfo;
2128 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2129 if (dominfo == NULL) {
2130 return NT_STATUS_NO_MEMORY;
2133 if (pwd_stat != NULL) {
2134 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2135 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2136 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2137 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2138 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2141 *_dominfo = dominfo;
2144 if (reject_reason != NULL) {
2145 if (pwd_stat != NULL) {
2146 *reject_reason = pwd_stat->reject_reason;
2148 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2152 if (pwd_stat != NULL) {
2153 talloc_free(pwd_stat);
2156 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2157 const char *errmsg = ldb_errstring(ldb);
2158 char *endptr = NULL;
2159 WERROR werr = WERR_GENERAL_FAILURE;
2160 status = NT_STATUS_UNSUCCESSFUL;
2161 if (errmsg != NULL) {
2162 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2164 if (endptr != errmsg) {
2165 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2166 status = NT_STATUS_WRONG_PASSWORD;
2168 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2169 status = NT_STATUS_PASSWORD_RESTRICTION;
2172 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2173 /* don't let the caller know if an account doesn't exist */
2174 status = NT_STATUS_WRONG_PASSWORD;
2175 } else if (ret != LDB_SUCCESS) {
2176 status = NT_STATUS_UNSUCCESSFUL;
2183 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2184 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2185 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2186 * user change or not. The "rejectReason" gives some more informations if the
2189 * This wrapper function for "samdb_set_password" takes a SID as input rather
2192 * This call encapsulates a new LDB transaction for changing the password;
2193 * therefore the user hasn't to start a new one.
2195 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2196 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2197 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2198 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2200 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2201 const struct dom_sid *user_sid,
2202 const DATA_BLOB *new_password,
2203 const struct samr_Password *lmNewHash,
2204 const struct samr_Password *ntNewHash,
2205 const struct samr_Password *lmOldHash,
2206 const struct samr_Password *ntOldHash,
2207 enum samPwdChangeReason *reject_reason,
2208 struct samr_DomInfo1 **_dominfo)
2211 struct ldb_dn *user_dn;
2214 ret = ldb_transaction_start(ldb);
2215 if (ret != LDB_SUCCESS) {
2216 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2217 return NT_STATUS_TRANSACTION_ABORTED;
2220 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2221 "(&(objectSid=%s)(objectClass=user))",
2222 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2224 ldb_transaction_cancel(ldb);
2225 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2226 dom_sid_string(mem_ctx, user_sid)));
2227 return NT_STATUS_NO_SUCH_USER;
2230 nt_status = samdb_set_password(ldb, mem_ctx,
2233 lmNewHash, ntNewHash,
2234 lmOldHash, ntOldHash,
2235 reject_reason, _dominfo);
2236 if (!NT_STATUS_IS_OK(nt_status)) {
2237 ldb_transaction_cancel(ldb);
2238 talloc_free(user_dn);
2242 ret = ldb_transaction_commit(ldb);
2243 if (ret != LDB_SUCCESS) {
2244 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2245 ldb_dn_get_linearized(user_dn),
2246 ldb_errstring(ldb)));
2247 talloc_free(user_dn);
2248 return NT_STATUS_TRANSACTION_ABORTED;
2251 talloc_free(user_dn);
2252 return NT_STATUS_OK;
2256 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2257 struct dom_sid *sid, struct ldb_dn **ret_dn)
2259 struct ldb_message *msg;
2260 struct ldb_dn *basedn;
2264 sidstr = dom_sid_string(mem_ctx, sid);
2265 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2267 /* We might have to create a ForeignSecurityPrincipal, even if this user
2268 * is in our own domain */
2270 msg = ldb_msg_new(sidstr);
2272 talloc_free(sidstr);
2273 return NT_STATUS_NO_MEMORY;
2276 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2277 ldb_get_default_basedn(sam_ctx),
2278 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2280 if (ret != LDB_SUCCESS) {
2281 DEBUG(0, ("Failed to find DN for "
2282 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2283 talloc_free(sidstr);
2284 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2287 /* add core elements to the ldb_message for the alias */
2289 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2290 talloc_free(sidstr);
2291 return NT_STATUS_NO_MEMORY;
2294 samdb_msg_add_string(sam_ctx, msg, msg,
2296 "foreignSecurityPrincipal");
2298 /* create the alias */
2299 ret = ldb_add(sam_ctx, msg);
2300 if (ret != LDB_SUCCESS) {
2301 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2303 ldb_dn_get_linearized(msg->dn),
2304 ldb_errstring(sam_ctx)));
2305 talloc_free(sidstr);
2306 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2309 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2310 talloc_free(sidstr);
2312 return NT_STATUS_OK;
2317 Find the DN of a domain, assuming it to be a dotted.dns name
2320 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2323 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2324 const char *binary_encoded;
2325 const char **split_realm;
2332 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2334 talloc_free(tmp_ctx);
2337 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2338 for (i=0; split_realm[i]; i++) {
2339 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2340 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2341 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2342 binary_encoded, ldb_dn_get_linearized(dn)));
2343 talloc_free(tmp_ctx);
2347 if (!ldb_dn_validate(dn)) {
2348 DEBUG(2, ("Failed to validated DN %s\n",
2349 ldb_dn_get_linearized(dn)));
2350 talloc_free(tmp_ctx);
2353 talloc_free(tmp_ctx);
2358 Find the DN of a domain, be it the netbios or DNS name
2360 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2361 const char *domain_name)
2363 const char * const domain_ref_attrs[] = {
2366 const char * const domain_ref2_attrs[] = {
2369 struct ldb_result *res_domain_ref;
2370 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2371 /* find the domain's DN */
2372 int ret_domain = ldb_search(ldb, mem_ctx,
2374 samdb_partitions_dn(ldb, mem_ctx),
2377 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2379 if (ret_domain != LDB_SUCCESS) {
2383 if (res_domain_ref->count == 0) {
2384 ret_domain = ldb_search(ldb, mem_ctx,
2386 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2389 "(objectclass=domain)");
2390 if (ret_domain != LDB_SUCCESS) {
2394 if (res_domain_ref->count == 1) {
2395 return res_domain_ref->msgs[0]->dn;
2400 if (res_domain_ref->count > 1) {
2401 DEBUG(0,("Found %d records matching domain [%s]\n",
2402 ret_domain, domain_name));
2406 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2412 use a GUID to find a DN
2414 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2415 TALLOC_CTX *mem_ctx,
2416 const struct GUID *guid, struct ldb_dn **dn)
2419 struct ldb_result *res;
2420 const char *attrs[] = { NULL };
2421 char *guid_str = GUID_string(mem_ctx, guid);
2424 return ldb_operr(ldb);
2427 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2428 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2429 DSDB_SEARCH_SHOW_EXTENDED_DN |
2430 DSDB_SEARCH_ONE_ONLY,
2431 "objectGUID=%s", guid_str);
2432 talloc_free(guid_str);
2433 if (ret != LDB_SUCCESS) {
2437 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2444 use a DN to find a GUID with a given attribute name
2446 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2447 struct ldb_dn *dn, const char *attribute,
2451 struct ldb_result *res;
2452 const char *attrs[2];
2453 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2455 attrs[0] = attribute;
2458 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2459 if (ret != LDB_SUCCESS) {
2460 talloc_free(tmp_ctx);
2463 if (res->count < 1) {
2464 talloc_free(tmp_ctx);
2465 return LDB_ERR_NO_SUCH_OBJECT;
2467 *guid = samdb_result_guid(res->msgs[0], attribute);
2468 talloc_free(tmp_ctx);
2473 use a DN to find a GUID
2475 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2476 struct ldb_dn *dn, struct GUID *guid)
2478 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2484 adds the given GUID to the given ldb_message. This value is added
2485 for the given attr_name (may be either "objectGUID" or "parentGUID").
2487 int dsdb_msg_add_guid(struct ldb_message *msg,
2489 const char *attr_name)
2494 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2496 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2497 if (!NT_STATUS_IS_OK(status)) {
2498 ret = LDB_ERR_OPERATIONS_ERROR;
2502 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2503 if (ret != LDB_SUCCESS) {
2504 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2512 talloc_free(tmp_ctx);
2519 use a DN to find a SID
2521 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2522 struct ldb_dn *dn, struct dom_sid *sid)
2525 struct ldb_result *res;
2526 const char *attrs[] = { "objectSID", NULL };
2527 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2532 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(tmp_ctx);
2537 if (res->count < 1) {
2538 talloc_free(tmp_ctx);
2539 return LDB_ERR_NO_SUCH_OBJECT;
2541 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2543 talloc_free(tmp_ctx);
2544 return LDB_ERR_NO_SUCH_OBJECT;
2547 talloc_free(tmp_ctx);
2552 use a SID to find a DN
2554 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2555 TALLOC_CTX *mem_ctx,
2556 struct dom_sid *sid, struct ldb_dn **dn)
2559 struct ldb_result *res;
2560 const char *attrs[] = { NULL };
2561 char *sid_str = dom_sid_string(mem_ctx, sid);
2564 return ldb_operr(ldb);
2567 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2568 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2569 DSDB_SEARCH_SHOW_EXTENDED_DN |
2570 DSDB_SEARCH_ONE_ONLY,
2571 "objectSID=%s", sid_str);
2572 talloc_free(sid_str);
2573 if (ret != LDB_SUCCESS) {
2577 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2584 load a repsFromTo blob list for a given partition GUID
2585 attr must be "repsFrom" or "repsTo"
2587 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2588 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2590 const char *attrs[] = { attr, NULL };
2591 struct ldb_result *res = NULL;
2592 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2594 struct ldb_message_element *el;
2599 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2601 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2602 talloc_free(tmp_ctx);
2603 return WERR_DS_DRA_INTERNAL_ERROR;
2606 el = ldb_msg_find_element(res->msgs[0], attr);
2608 /* it's OK to be empty */
2609 talloc_free(tmp_ctx);
2613 *count = el->num_values;
2614 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2616 talloc_free(tmp_ctx);
2617 return WERR_DS_DRA_INTERNAL_ERROR;
2620 for (i=0; i<(*count); i++) {
2621 enum ndr_err_code ndr_err;
2622 ndr_err = ndr_pull_struct_blob(&el->values[i],
2625 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2626 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2627 talloc_free(tmp_ctx);
2628 return WERR_DS_DRA_INTERNAL_ERROR;
2632 talloc_free(tmp_ctx);
2638 save the repsFromTo blob list for a given partition GUID
2639 attr must be "repsFrom" or "repsTo"
2641 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2642 const char *attr, struct repsFromToBlob *r, uint32_t count)
2644 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2645 struct ldb_message *msg;
2646 struct ldb_message_element *el;
2649 msg = ldb_msg_new(tmp_ctx);
2651 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2655 el->values = talloc_array(msg, struct ldb_val, count);
2660 for (i=0; i<count; i++) {
2662 enum ndr_err_code ndr_err;
2664 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2666 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2667 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2675 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2676 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2680 talloc_free(tmp_ctx);
2685 talloc_free(tmp_ctx);
2686 return WERR_DS_DRA_INTERNAL_ERROR;
2691 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2692 object for a partition
2694 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2695 uint64_t *uSN, uint64_t *urgent_uSN)
2697 struct ldb_request *req;
2699 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2700 struct dsdb_control_current_partition *p_ctrl;
2701 struct ldb_result *res;
2703 res = talloc_zero(tmp_ctx, struct ldb_result);
2705 talloc_free(tmp_ctx);
2706 return ldb_oom(ldb);
2709 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2710 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2714 res, ldb_search_default_callback,
2716 if (ret != LDB_SUCCESS) {
2717 talloc_free(tmp_ctx);
2721 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2722 if (p_ctrl == NULL) {
2723 talloc_free(tmp_ctx);
2724 return ldb_oom(ldb);
2726 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2729 ret = ldb_request_add_control(req,
2730 DSDB_CONTROL_CURRENT_PARTITION_OID,
2732 if (ret != LDB_SUCCESS) {
2733 talloc_free(tmp_ctx);
2737 /* Run the new request */
2738 ret = ldb_request(ldb, req);
2740 if (ret == LDB_SUCCESS) {
2741 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2744 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2745 /* it hasn't been created yet, which means
2746 an implicit value of zero */
2748 talloc_free(tmp_ctx);
2752 if (ret != LDB_SUCCESS) {
2753 talloc_free(tmp_ctx);
2757 if (res->count < 1) {
2763 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2765 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2769 talloc_free(tmp_ctx);
2774 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2775 const struct drsuapi_DsReplicaCursor2 *c2)
2777 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2780 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2781 const struct drsuapi_DsReplicaCursor *c2)
2783 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2788 see if a computer identified by its invocationId is a RODC
2790 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2792 /* 1) find the DN for this servers NTDSDSA object
2793 2) search for the msDS-isRODC attribute
2794 3) if not present then not a RODC
2795 4) if present and TRUE then is a RODC
2797 struct ldb_dn *config_dn;
2798 const char *attrs[] = { "msDS-isRODC", NULL };
2800 struct ldb_result *res;
2801 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2803 config_dn = ldb_get_config_basedn(sam_ctx);
2805 talloc_free(tmp_ctx);
2806 return ldb_operr(sam_ctx);
2809 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2810 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2812 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2814 talloc_free(tmp_ctx);
2818 if (ret != LDB_SUCCESS) {
2819 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2820 GUID_string(tmp_ctx, objectGUID)));
2822 talloc_free(tmp_ctx);
2826 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2827 *is_rodc = (ret == 1);
2829 talloc_free(tmp_ctx);
2835 see if we are a RODC
2837 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2839 const struct GUID *objectGUID;
2843 /* see if we have a cached copy */
2844 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2850 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2852 return ldb_operr(sam_ctx);
2855 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2856 if (ret != LDB_SUCCESS) {
2860 cached = talloc(sam_ctx, bool);
2861 if (cached == NULL) {
2862 return ldb_oom(sam_ctx);
2866 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2867 if (ret != LDB_SUCCESS) {
2868 talloc_free(cached);
2869 return ldb_operr(sam_ctx);
2875 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2877 TALLOC_CTX *tmp_ctx;
2880 tmp_ctx = talloc_new(ldb);
2881 if (tmp_ctx == NULL) {
2885 cached = talloc(tmp_ctx, bool);
2891 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2895 talloc_steal(ldb, cached);
2896 talloc_free(tmp_ctx);
2900 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2901 talloc_free(tmp_ctx);
2907 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2909 flags are DS_NTDS_OPTION_*
2911 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2913 TALLOC_CTX *tmp_ctx;
2914 const char *attrs[] = { "options", NULL };
2916 struct ldb_result *res;
2918 tmp_ctx = talloc_new(ldb);
2919 if (tmp_ctx == NULL) {
2923 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2924 if (ret != LDB_SUCCESS) {
2928 if (res->count != 1) {
2932 *options = samdb_result_uint(res->msgs[0], "options", 0);
2934 talloc_free(tmp_ctx);
2939 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2940 talloc_free(tmp_ctx);
2941 return LDB_ERR_NO_SUCH_OBJECT;
2944 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
2946 const char *attrs[] = { "objectCategory", NULL };
2948 struct ldb_result *res;
2950 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2951 if (ret != LDB_SUCCESS) {
2955 if (res->count != 1) {
2959 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
2962 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
2967 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2968 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2970 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2972 char **tokens, *ret;
2975 tokens = str_list_make(mem_ctx, cn, " -_");
2979 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2980 tokens[0][0] = tolower(tokens[0][0]);
2981 for (i = 1; i < str_list_length((const char **)tokens); i++)
2982 tokens[i][0] = toupper(tokens[i][0]);
2984 ret = talloc_strdup(mem_ctx, tokens[0]);
2985 for (i = 1; i < str_list_length((const char **)tokens); i++)
2986 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2988 talloc_free(tokens);
2994 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
2996 int dsdb_functional_level(struct ldb_context *ldb)
2998 int *domainFunctionality =
2999 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3000 if (!domainFunctionality) {
3001 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
3002 return DS_DOMAIN_FUNCTION_2000;
3004 return *domainFunctionality;
3008 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3010 int dsdb_forest_functional_level(struct ldb_context *ldb)
3012 int *forestFunctionality =
3013 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3014 if (!forestFunctionality) {
3015 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3016 return DS_DOMAIN_FUNCTION_2000;
3018 return *forestFunctionality;
3022 set a GUID in an extended DN structure
3024 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3030 status = GUID_to_ndr_blob(guid, dn, &v);
3031 if (!NT_STATUS_IS_OK(status)) {
3032 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3035 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3041 return a GUID from a extended DN structure
3043 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3045 const struct ldb_val *v;
3047 v = ldb_dn_get_extended_component(dn, component_name);
3049 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3052 return GUID_from_ndr_blob(v, guid);
3056 return a uint64_t from a extended DN structure
3058 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3060 const struct ldb_val *v;
3063 v = ldb_dn_get_extended_component(dn, component_name);
3065 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3067 s = talloc_strndup(dn, (const char *)v->data, v->length);
3068 NT_STATUS_HAVE_NO_MEMORY(s);
3070 *val = strtoull(s, NULL, 0);
3073 return NT_STATUS_OK;
3077 return a NTTIME from a extended DN structure
3079 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3081 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3085 return a uint32_t from a extended DN structure
3087 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3089 const struct ldb_val *v;
3092 v = ldb_dn_get_extended_component(dn, component_name);
3094 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3097 s = talloc_strndup(dn, (const char *)v->data, v->length);
3098 NT_STATUS_HAVE_NO_MEMORY(s);
3100 *val = strtoul(s, NULL, 0);
3103 return NT_STATUS_OK;
3107 return a dom_sid from a extended DN structure
3109 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3111 const struct ldb_val *sid_blob;
3112 struct TALLOC_CTX *tmp_ctx;
3113 enum ndr_err_code ndr_err;
3115 sid_blob = ldb_dn_get_extended_component(dn, "SID");
3117 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3120 tmp_ctx = talloc_new(NULL);
3122 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3123 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3124 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3125 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3126 talloc_free(tmp_ctx);
3130 talloc_free(tmp_ctx);
3131 return NT_STATUS_OK;
3136 return RMD_FLAGS directly from a ldb_dn
3137 returns 0 if not found
3139 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3141 const struct ldb_val *v;
3143 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3144 if (!v || v->length > sizeof(buf)-1) return 0;
3145 strncpy(buf, (const char *)v->data, v->length);
3147 return strtoul(buf, NULL, 10);
3151 return RMD_FLAGS directly from a ldb_val for a DN
3152 returns 0 if RMD_FLAGS is not found
3154 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3160 if (val->length < 13) {
3163 p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
3167 flags = strtoul(p+11, &end, 10);
3168 if (!end || *end != '>') {
3169 /* it must end in a > */
3176 return true if a ldb_val containing a DN in storage form is deleted
3178 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3180 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3184 return true if a ldb_val containing a DN in storage form is
3185 in the upgraded w2k3 linked attribute format
3187 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3189 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3193 return a DN for a wellknown GUID
3195 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3196 struct ldb_dn *nc_root, const char *wk_guid,
3197 struct ldb_dn **wkguid_dn)
3199 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3200 const char *attrs[] = { NULL };
3203 struct ldb_result *res;
3205 /* construct the magic WKGUID DN */
3206 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3207 wk_guid, ldb_dn_get_linearized(nc_root));
3209 talloc_free(tmp_ctx);
3210 return ldb_operr(samdb);
3213 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3214 if (ret != LDB_SUCCESS) {
3215 talloc_free(tmp_ctx);
3219 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3220 talloc_free(tmp_ctx);
3225 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3227 return ldb_dn_compare(*dn1, *dn2);
3231 find a NC root given a DN within the NC
3233 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3234 struct ldb_dn **nc_root)
3236 const char *root_attrs[] = { "namingContexts", NULL };
3237 TALLOC_CTX *tmp_ctx;
3239 struct ldb_message_element *el;
3240 struct ldb_result *root_res;
3242 struct ldb_dn **nc_dns;
3244 tmp_ctx = talloc_new(samdb);
3245 if (tmp_ctx == NULL) {
3246 return ldb_oom(samdb);
3249 ret = ldb_search(samdb, tmp_ctx, &root_res,
3250 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3251 if (ret != LDB_SUCCESS) {
3252 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3253 talloc_free(tmp_ctx);
3257 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3259 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3260 ldb_errstring(samdb)));
3261 talloc_free(tmp_ctx);
3262 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3265 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3267 talloc_free(tmp_ctx);
3268 return ldb_oom(samdb);
3271 for (i=0; i<el->num_values; i++) {
3272 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3273 if (nc_dns[i] == NULL) {
3274 talloc_free(tmp_ctx);
3275 return ldb_operr(samdb);
3279 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3281 for (i=0; i<el->num_values; i++) {
3282 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3283 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3284 talloc_free(tmp_ctx);
3289 talloc_free(tmp_ctx);
3290 return LDB_ERR_NO_SUCH_OBJECT;
3295 find the deleted objects DN for any object, by looking for the NC
3296 root, then looking up the wellknown GUID
3298 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3299 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3300 struct ldb_dn **do_dn)
3302 struct ldb_dn *nc_root;
3305 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3306 if (ret != LDB_SUCCESS) {
3310 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3311 talloc_free(nc_root);
3316 return the tombstoneLifetime, in days
3318 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3321 dn = ldb_get_config_basedn(ldb);
3323 return LDB_ERR_NO_SUCH_OBJECT;
3325 dn = ldb_dn_copy(ldb, dn);
3327 return ldb_operr(ldb);
3329 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3330 be a wellknown GUID for this */
3331 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3333 return ldb_operr(ldb);
3336 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3342 compare a ldb_val to a string case insensitively
3344 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3346 size_t len = strlen(s);
3348 if (len > v->length) return 1;
3349 ret = strncasecmp(s, (const char *)v->data, v->length);
3350 if (ret != 0) return ret;
3351 if (v->length > len && v->data[len] != 0) {
3359 load the UDV for a partition in v2 format
3360 The list is returned sorted, and with our local cursor added
3362 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3363 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3365 static const char *attrs[] = { "replUpToDateVector", NULL };
3366 struct ldb_result *r;
3367 const struct ldb_val *ouv_value;
3370 uint64_t highest_usn;
3371 const struct GUID *our_invocation_id;
3372 struct timeval now = timeval_current();
3374 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3375 if (ret != LDB_SUCCESS) {
3379 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3381 enum ndr_err_code ndr_err;
3382 struct replUpToDateVectorBlob ouv;
3384 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3385 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3386 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3388 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3390 if (ouv.version != 2) {
3391 /* we always store as version 2, and
3392 * replUpToDateVector is not replicated
3394 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3397 *count = ouv.ctr.ctr2.count;
3398 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3406 our_invocation_id = samdb_ntds_invocation_id(samdb);
3407 if (!our_invocation_id) {
3408 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3409 talloc_free(*cursors);
3410 return ldb_operr(samdb);
3413 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3414 if (ret != LDB_SUCCESS) {
3415 /* nothing to add - this can happen after a vampire */
3416 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3420 for (i=0; i<*count; i++) {
3421 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3422 (*cursors)[i].highest_usn = highest_usn;
3423 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3424 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3429 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3431 return ldb_oom(samdb);
3434 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3435 (*cursors)[*count].highest_usn = highest_usn;
3436 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3439 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3445 load the UDV for a partition in version 1 format
3446 The list is returned sorted, and with our local cursor added
3448 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3449 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3451 struct drsuapi_DsReplicaCursor2 *v2;
3455 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3456 if (ret != LDB_SUCCESS) {
3466 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3467 if (*cursors == NULL) {
3469 return ldb_oom(samdb);
3472 for (i=0; i<*count; i++) {
3473 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3474 (*cursors)[i].highest_usn = v2[i].highest_usn;
3481 add a set of controls to a ldb_request structure based on a set of
3482 flags. See util.h for a list of available flags
3484 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3487 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3488 struct ldb_search_options_control *options;
3489 /* Using the phantom root control allows us to search all partitions */
3490 options = talloc(req, struct ldb_search_options_control);
3491 if (options == NULL) {
3492 return LDB_ERR_OPERATIONS_ERROR;
3494 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3496 ret = ldb_request_add_control(req,
3497 LDB_CONTROL_SEARCH_OPTIONS_OID,
3499 if (ret != LDB_SUCCESS) {
3504 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3505 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3506 if (ret != LDB_SUCCESS) {
3511 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3512 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3513 if (ret != LDB_SUCCESS) {
3518 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3519 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3520 if (!extended_ctrl) {
3521 return LDB_ERR_OPERATIONS_ERROR;
3523 extended_ctrl->type = 1;
3525 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3526 if (ret != LDB_SUCCESS) {
3531 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3532 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3533 if (ret != LDB_SUCCESS) {
3538 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3539 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3540 if (ret != LDB_SUCCESS) {
3545 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3546 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3547 if (ret != LDB_SUCCESS) {
3552 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3553 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3554 if (ret != LDB_SUCCESS) {
3559 if (dsdb_flags & DSDB_TREE_DELETE) {
3560 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3561 if (ret != LDB_SUCCESS) {
3570 an add with a set of controls
3572 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3573 uint32_t dsdb_flags)
3575 struct ldb_request *req;
3578 ret = ldb_build_add_req(&req, ldb, ldb,
3582 ldb_op_default_callback,
3585 if (ret != LDB_SUCCESS) return ret;
3587 ret = dsdb_request_add_controls(req, dsdb_flags);
3588 if (ret != LDB_SUCCESS) {
3593 ret = dsdb_autotransaction_request(ldb, req);
3600 a modify with a set of controls
3602 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3603 uint32_t dsdb_flags)
3605 struct ldb_request *req;
3608 ret = ldb_build_mod_req(&req, ldb, ldb,
3612 ldb_op_default_callback,
3615 if (ret != LDB_SUCCESS) return ret;
3617 ret = dsdb_request_add_controls(req, dsdb_flags);
3618 if (ret != LDB_SUCCESS) {
3623 ret = dsdb_autotransaction_request(ldb, req);
3630 like dsdb_modify() but set all the element flags to
3631 LDB_FLAG_MOD_REPLACE
3633 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3637 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3638 for (i=0;i<msg->num_elements;i++) {
3639 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3642 return dsdb_modify(ldb, msg, dsdb_flags);
3647 search for attrs on one DN, allowing for dsdb_flags controls
3649 int dsdb_search_dn(struct ldb_context *ldb,
3650 TALLOC_CTX *mem_ctx,
3651 struct ldb_result **_res,
3652 struct ldb_dn *basedn,
3653 const char * const *attrs,
3654 uint32_t dsdb_flags)
3657 struct ldb_request *req;
3658 struct ldb_result *res;
3660 res = talloc_zero(mem_ctx, struct ldb_result);
3662 return ldb_oom(ldb);
3665 ret = ldb_build_search_req(&req, ldb, res,
3672 ldb_search_default_callback,
3674 if (ret != LDB_SUCCESS) {
3679 ret = dsdb_request_add_controls(req, dsdb_flags);
3680 if (ret != LDB_SUCCESS) {
3685 ret = ldb_request(ldb, req);
3686 if (ret == LDB_SUCCESS) {
3687 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3691 if (ret != LDB_SUCCESS) {
3701 general search with dsdb_flags for controls
3703 int dsdb_search(struct ldb_context *ldb,
3704 TALLOC_CTX *mem_ctx,
3705 struct ldb_result **_res,
3706 struct ldb_dn *basedn,
3707 enum ldb_scope scope,
3708 const char * const *attrs,
3709 uint32_t dsdb_flags,
3710 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3713 struct ldb_request *req;
3714 struct ldb_result *res;
3716 char *expression = NULL;
3717 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3719 res = talloc_zero(tmp_ctx, struct ldb_result);
3721 talloc_free(tmp_ctx);
3722 return ldb_oom(ldb);
3726 va_start(ap, exp_fmt);
3727 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3731 talloc_free(tmp_ctx);
3732 return ldb_oom(ldb);
3736 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3743 ldb_search_default_callback,
3745 if (ret != LDB_SUCCESS) {
3746 talloc_free(tmp_ctx);
3750 ret = dsdb_request_add_controls(req, dsdb_flags);
3751 if (ret != LDB_SUCCESS) {
3752 talloc_free(tmp_ctx);
3756 ret = ldb_request(ldb, req);
3757 if (ret == LDB_SUCCESS) {
3758 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3761 if (ret != LDB_SUCCESS) {
3762 talloc_free(tmp_ctx);
3766 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3767 if (res->count == 0) {
3768 talloc_free(tmp_ctx);
3769 return LDB_ERR_NO_SUCH_OBJECT;
3771 if (res->count != 1) {
3772 talloc_free(tmp_ctx);
3773 return LDB_ERR_CONSTRAINT_VIOLATION;
3777 *_res = talloc_steal(mem_ctx, res);
3778 talloc_free(tmp_ctx);
3785 general search with dsdb_flags for controls
3786 returns exactly 1 record or an error
3788 int dsdb_search_one(struct ldb_context *ldb,
3789 TALLOC_CTX *mem_ctx,
3790 struct ldb_message **msg,
3791 struct ldb_dn *basedn,
3792 enum ldb_scope scope,
3793 const char * const *attrs,
3794 uint32_t dsdb_flags,
3795 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3798 struct ldb_result *res;
3800 char *expression = NULL;
3801 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3803 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3805 res = talloc_zero(tmp_ctx, struct ldb_result);
3807 talloc_free(tmp_ctx);
3808 return ldb_oom(ldb);
3812 va_start(ap, exp_fmt);
3813 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3817 talloc_free(tmp_ctx);
3818 return ldb_oom(ldb);
3820 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3821 dsdb_flags, "%s", expression);
3823 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3827 if (ret != LDB_SUCCESS) {
3828 talloc_free(tmp_ctx);
3832 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3833 talloc_free(tmp_ctx);
3838 /* returns back the forest DNS name */
3839 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3841 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3842 ldb_get_root_basedn(ldb));
3845 if (forest_name == NULL) {
3849 p = strchr(forest_name, '/');
3858 validate that an DSA GUID belongs to the specified user sid.
3859 The user SID must be a domain controller account (either RODC or
3862 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3863 const struct GUID *dsa_guid,
3864 const struct dom_sid *sid)
3867 - find DN of record with the DSA GUID in the
3868 configuration partition (objectGUID)
3869 - remove "NTDS Settings" component from DN
3870 - do a base search on that DN for serverReference with
3872 - extract objectSID from resulting serverReference
3874 - check this sid matches the sid argument
3876 struct ldb_dn *config_dn;
3877 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3878 struct ldb_message *msg;
3879 const char *attrs1[] = { NULL };
3880 const char *attrs2[] = { "serverReference", NULL };
3882 struct ldb_dn *dn, *account_dn;
3883 struct dom_sid sid2;
3886 config_dn = ldb_get_config_basedn(ldb);
3888 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3889 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3890 if (ret != LDB_SUCCESS) {
3891 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3892 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3893 talloc_free(tmp_ctx);
3894 return ldb_operr(ldb);
3898 if (!ldb_dn_remove_child_components(dn, 1)) {
3899 talloc_free(tmp_ctx);
3900 return ldb_operr(ldb);
3903 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3904 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3905 "(objectClass=server)");
3906 if (ret != LDB_SUCCESS) {
3907 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3908 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3909 talloc_free(tmp_ctx);
3910 return ldb_operr(ldb);
3913 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
3914 if (account_dn == NULL) {
3915 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
3916 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3917 talloc_free(tmp_ctx);
3918 return ldb_operr(ldb);
3921 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
3922 if (!NT_STATUS_IS_OK(status)) {
3923 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
3924 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3925 talloc_free(tmp_ctx);
3926 return ldb_operr(ldb);
3929 if (!dom_sid_equal(sid, &sid2)) {
3930 /* someone is trying to spoof another account */
3931 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
3932 GUID_string(tmp_ctx, dsa_guid),
3933 dom_sid_string(tmp_ctx, sid),
3934 dom_sid_string(tmp_ctx, &sid2)));
3935 talloc_free(tmp_ctx);
3936 return ldb_operr(ldb);
3939 talloc_free(tmp_ctx);
3943 static const char *secret_attributes[] = {
3946 "initialAuthIncoming",
3947 "initialAuthOutgoing",
3951 "supplementalCredentials",
3952 "trustAuthIncoming",
3953 "trustAuthOutgoing",
3959 check if the attribute belongs to the RODC filtered attribute set
3960 Note that attributes that are in the filtered attribute set are the
3961 ones that _are_ always sent to a RODC
3963 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
3965 /* they never get secret attributes */
3966 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
3970 /* they do get non-secret critical attributes */
3971 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
3975 /* they do get non-secret attributes marked as being in the FAS */
3976 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
3980 /* other attributes are denied */