2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "dsdb/samdb/ldb_modules/util.h"
46 #include "librpc/gen_ndr/irpc.h"
49 search the sam for the specified attributes in a specific domain, filter on
50 objectSid being in domain_sid.
52 int samdb_search_domain(struct ldb_context *sam_ldb,
54 struct ldb_dn *basedn,
55 struct ldb_message ***res,
56 const char * const *attrs,
57 const struct dom_sid *domain_sid,
58 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
64 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
65 res, attrs, format, ap);
71 struct dom_sid *entry_sid;
73 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
75 if ((entry_sid == NULL) ||
76 (!dom_sid_in_domain(domain_sid, entry_sid))) {
77 /* Delete that entry from the result set */
78 (*res)[i] = (*res)[count-1];
80 talloc_free(entry_sid);
83 talloc_free(entry_sid);
91 search the sam for a single string attribute in exactly 1 record
93 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
95 struct ldb_dn *basedn,
96 const char *attr_name,
97 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
100 const char *attrs[2] = { NULL, NULL };
101 struct ldb_message **res = NULL;
103 attrs[0] = attr_name;
105 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
107 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
108 attr_name, format, count));
115 return samdb_result_string(res[0], attr_name, NULL);
119 search the sam for a single string attribute in exactly 1 record
121 const char *samdb_search_string(struct ldb_context *sam_ldb,
123 struct ldb_dn *basedn,
124 const char *attr_name,
125 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
130 va_start(ap, format);
131 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
137 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
139 struct ldb_dn *basedn,
140 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
144 struct ldb_message **res = NULL;
147 va_start(ap, format);
148 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
151 if (count != 1) return NULL;
153 ret = talloc_steal(mem_ctx, res[0]->dn);
160 search the sam for a dom_sid attribute in exactly 1 record
162 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
164 struct ldb_dn *basedn,
165 const char *attr_name,
166 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
170 struct ldb_message **res;
171 const char *attrs[2] = { NULL, NULL };
174 attrs[0] = attr_name;
176 va_start(ap, format);
177 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
180 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
181 attr_name, format, count));
187 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
193 return the count of the number of records in the sam matching the query
195 int samdb_search_count(struct ldb_context *sam_ldb,
196 struct ldb_dn *basedn,
197 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
200 struct ldb_message **res;
201 const char *attrs[] = { NULL };
203 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
205 va_start(ap, format);
206 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
208 talloc_free(tmp_ctx);
215 search the sam for a single integer attribute in exactly 1 record
217 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
219 unsigned int default_value,
220 struct ldb_dn *basedn,
221 const char *attr_name,
222 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
226 struct ldb_message **res;
227 const char *attrs[2] = { NULL, NULL };
229 attrs[0] = attr_name;
231 va_start(ap, format);
232 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
236 return default_value;
239 return samdb_result_uint(res[0], attr_name, default_value);
243 search the sam for a single signed 64 bit integer attribute in exactly 1 record
245 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
247 int64_t default_value,
248 struct ldb_dn *basedn,
249 const char *attr_name,
250 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
254 struct ldb_message **res;
255 const char *attrs[2] = { NULL, NULL };
257 attrs[0] = attr_name;
259 va_start(ap, format);
260 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
264 return default_value;
267 return samdb_result_int64(res[0], attr_name, default_value);
271 search the sam for multipe records each giving a single string attribute
272 return the number of matches, or -1 on error
274 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
276 struct ldb_dn *basedn,
278 const char *attr_name,
279 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
283 const char *attrs[2] = { NULL, NULL };
284 struct ldb_message **res = NULL;
286 attrs[0] = attr_name;
288 va_start(ap, format);
289 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
296 /* make sure its single valued */
297 for (i=0;i<count;i++) {
298 if (res[i]->num_elements != 1) {
299 DEBUG(1,("samdb: search for %s %s not single valued\n",
306 *strs = talloc_array(mem_ctx, const char *, count+1);
312 for (i=0;i<count;i++) {
313 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
315 (*strs)[count] = NULL;
321 pull a uint from a result set.
323 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
325 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
329 pull a (signed) int64 from a result set.
331 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
333 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
337 pull a string from a result set.
339 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
340 const char *default_value)
342 return ldb_msg_find_attr_as_string(msg, attr, default_value);
345 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
346 const char *attr, struct ldb_dn *default_value)
348 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
350 return default_value;
356 pull a rid from a objectSid in a result set.
358 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
359 const char *attr, uint32_t default_value)
364 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
366 return default_value;
368 rid = sid->sub_auths[sid->num_auths-1];
374 pull a dom_sid structure from a objectSid in a result set.
376 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
379 const struct ldb_val *v;
381 enum ndr_err_code ndr_err;
382 v = ldb_msg_find_ldb_val(msg, attr);
386 sid = talloc(mem_ctx, struct dom_sid);
390 ndr_err = ndr_pull_struct_blob(v, sid, sid,
391 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
400 pull a guid structure from a objectGUID in a result set.
402 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
404 const struct ldb_val *v;
408 v = ldb_msg_find_ldb_val(msg, attr);
409 if (!v) return GUID_zero();
411 status = GUID_from_ndr_blob(v, &guid);
412 if (!NT_STATUS_IS_OK(status)) {
420 pull a sid prefix from a objectSid in a result set.
421 this is used to find the domain sid for a user
423 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
426 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
427 if (!sid || sid->num_auths < 1) return NULL;
433 pull a NTTIME in a result set.
435 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
436 NTTIME default_value)
438 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
442 * Windows stores 0 for lastLogoff.
443 * But when a MS DC return the lastLogoff (as Logoff Time)
444 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
445 * cause windows 2008 and newer version to fail for SMB requests
447 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
449 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
452 ret = 0x7FFFFFFFFFFFFFFFULL;
458 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
459 * indicate an account doesn't expire.
461 * When Windows initially creates an account, it sets
462 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
463 * when changing from an account having a specific expiration date to
464 * that account never expiring, it sets accountExpires = 0.
466 * Consolidate that logic here to allow clearer logic for account expiry in
467 * the rest of the code.
469 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
471 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
475 ret = 0x7FFFFFFFFFFFFFFFULL;
481 pull a uint64_t from a result set.
483 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
484 uint64_t default_value)
486 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
491 construct the allow_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
496 struct ldb_dn *domain_dn,
497 struct ldb_message *msg,
500 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
503 if (attr_time == 0) {
507 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
509 /* yes, this is a -= not a += as minPwdAge is stored as the negative
510 of the number of 100-nano-seconds */
511 attr_time -= minPwdAge;
517 construct the force_password_change field from the PwdLastSet
518 attribute, the userAccountControl and the domain password settings
520 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
522 struct ldb_dn *domain_dn,
523 struct ldb_message *msg)
525 int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
526 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
527 "userAccountControl",
531 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
532 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
533 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
534 return 0x7FFFFFFFFFFFFFFFULL;
537 if (attr_time == 0) {
540 if (attr_time == -1) {
541 return 0x7FFFFFFFFFFFFFFFULL;
544 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
546 if (maxPwdAge == 0) {
547 return 0x7FFFFFFFFFFFFFFFULL;
549 attr_time -= maxPwdAge;
556 pull a samr_Password structutre from a result set.
558 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
560 struct samr_Password *hash = NULL;
561 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
562 if (val && (val->length >= sizeof(hash->hash))) {
563 hash = talloc(mem_ctx, struct samr_Password);
564 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
570 pull an array of samr_Password structures from a result set.
572 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
573 const char *attr, struct samr_Password **hashes)
575 unsigned int count, i;
576 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
582 count = val->length / 16;
587 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
592 for (i=0;i<count;i++) {
593 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
599 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
600 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
602 struct samr_Password *lmPwdHash, *ntPwdHash;
605 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
608 } else if (num_nt > 1) {
609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
611 *nt_pwd = &ntPwdHash[0];
615 /* Ensure that if we have turned off LM
616 * authentication, that we never use the LM hash, even
618 if (lpcfg_lanman_auth(lp_ctx)) {
620 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
623 } else if (num_lm > 1) {
624 return NT_STATUS_INTERNAL_DB_CORRUPTION;
626 *lm_pwd = &lmPwdHash[0];
636 pull a samr_LogonHours structutre from a result set.
638 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
640 struct samr_LogonHours hours;
641 size_t units_per_week = 168;
642 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
647 units_per_week = val->length * 8;
650 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
654 hours.units_per_week = units_per_week;
655 memset(hours.bits, 0xFF, units_per_week/8);
657 memcpy(hours.bits, val->data, val->length);
664 pull a set of account_flags from a result set.
666 This requires that the attributes:
671 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
672 struct ldb_message *msg, struct ldb_dn *domain_dn)
674 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
675 uint32_t acct_flags = ds_uf2acb(userAccountControl);
676 NTTIME must_change_time;
679 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
682 /* Test account expire time */
683 unix_to_nt_time(&now, time(NULL));
684 /* check for expired password */
685 if (must_change_time < now) {
686 acct_flags |= ACB_PW_EXPIRED;
691 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
692 struct ldb_message *msg,
695 struct lsa_BinaryString s;
696 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
704 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
708 s.length = s.size = val->length;
709 memcpy(s.array, val->data, val->length);
714 /* Find an attribute, with a particular value */
716 /* The current callers of this function expect a very specific
717 * behaviour: In particular, objectClass subclass equivilance is not
718 * wanted. This means that we should not lookup the schema for the
719 * comparison function */
720 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
721 const struct ldb_message *msg,
722 const char *name, const char *value)
725 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
731 for (i=0;i<el->num_values;i++) {
732 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
741 * This is intended for use by the "password hash" module since there
742 * password changes can be specified through one message element with the
743 * new password (to set) and another one with the old password (to unset).
745 * The first which sets a password (new value) can have flags
746 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
747 * for entries). The latter (old value) has always specified
748 * LDB_FLAG_MOD_DELETE.
750 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
751 * doesn't contain only one value (this is the Windows Server behaviour)
752 * otherwise LDB_SUCCESS.
754 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
756 const struct ldb_val **new_val,
757 const struct ldb_val **old_val)
768 for (i = 0; i < msg->num_elements; i++) {
769 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
770 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
771 *old_val = &msg->elements[i].values[0];
773 *new_val = &msg->elements[i].values[0];
781 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
783 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
784 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
789 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
791 struct ldb_message_element *el;
793 el = ldb_msg_find_element(msg, name);
798 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
804 add a string element to a message
806 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
807 const char *attr_name, const char *str)
809 char *s = talloc_strdup(mem_ctx, str);
810 char *a = talloc_strdup(mem_ctx, attr_name);
811 if (s == NULL || a == NULL) {
812 return ldb_oom(sam_ldb);
814 return ldb_msg_add_string(msg, a, s);
818 add a dom_sid element to a message
820 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, struct dom_sid *sid)
824 enum ndr_err_code ndr_err;
826 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
828 (ndr_push_flags_fn_t)ndr_push_dom_sid);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 return ldb_operr(sam_ldb);
832 return ldb_msg_add_value(msg, attr_name, &v, NULL);
837 add a delete element operation to a message
839 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name)
842 /* we use an empty replace rather than a delete, as it allows for
843 dsdb_replace() to be used everywhere */
844 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
848 add an add attribute value to a message or enhance an existing attribute
849 which has the same name and the add flag set.
851 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
852 struct ldb_message *msg, const char *attr_name,
855 struct ldb_message_element *el;
856 struct ldb_val val, *vals;
862 v = talloc_strdup(mem_ctx, value);
864 return ldb_oom(sam_ldb);
867 val.data = (uint8_t *) v;
868 val.length = strlen(v);
870 if (val.length == 0) {
871 /* allow empty strings as non-existent attributes */
875 for (i = 0; i < msg->num_elements; i++) {
876 el = &msg->elements[i];
877 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
878 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
884 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
886 if (ret != LDB_SUCCESS) {
891 vals = talloc_realloc(msg, el->values, struct ldb_val,
894 return ldb_oom(sam_ldb);
897 el->values[el->num_values] = val;
904 add a delete attribute value to a message or enhance an existing attribute
905 which has the same name and the delete flag set.
907 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
908 struct ldb_message *msg, const char *attr_name,
911 struct ldb_message_element *el;
912 struct ldb_val val, *vals;
918 v = talloc_strdup(mem_ctx, value);
920 return ldb_oom(sam_ldb);
923 val.data = (uint8_t *) v;
924 val.length = strlen(v);
926 if (val.length == 0) {
927 /* allow empty strings as non-existent attributes */
931 for (i = 0; i < msg->num_elements; i++) {
932 el = &msg->elements[i];
933 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
934 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
940 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
942 if (ret != LDB_SUCCESS) {
947 vals = talloc_realloc(msg, el->values, struct ldb_val,
950 return ldb_oom(sam_ldb);
953 el->values[el->num_values] = val;
960 add a int element to a message
962 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, int v)
965 const char *s = talloc_asprintf(mem_ctx, "%d", v);
966 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
970 add a unsigned int element to a message
972 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
973 const char *attr_name, unsigned int v)
975 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
979 add a (signed) int64_t element to a message
981 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
982 const char *attr_name, int64_t v)
984 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
985 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
989 add a uint64_t element to a message
991 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992 const char *attr_name, uint64_t v)
994 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
998 add a samr_Password element to a message
1000 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001 const char *attr_name, const struct samr_Password *hash)
1004 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1006 return ldb_oom(sam_ldb);
1009 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1013 add a samr_Password array to a message
1015 int samdb_msg_add_hashes(struct ldb_context *ldb,
1016 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1017 const char *attr_name, struct samr_Password *hashes,
1022 val.data = talloc_array_size(mem_ctx, 16, count);
1023 val.length = count*16;
1025 return ldb_oom(ldb);
1027 for (i=0;i<count;i++) {
1028 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1030 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1034 add a acct_flags element to a message
1036 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037 const char *attr_name, uint32_t v)
1039 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1043 add a logon_hours element to a message
1045 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1046 const char *attr_name, struct samr_LogonHours *hours)
1049 val.length = hours->units_per_week / 8;
1050 val.data = hours->bits;
1051 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1055 add a parameters element to a message
1057 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1058 const char *attr_name, struct lsa_BinaryString *parameters)
1061 val.length = parameters->length;
1062 val.data = (uint8_t *)parameters->array;
1063 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1066 add a general value element to a message
1068 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1069 const char *attr_name, const struct ldb_val *val)
1071 return ldb_msg_add_value(msg, attr_name, val, NULL);
1075 sets a general value element to a message
1077 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1078 const char *attr_name, const struct ldb_val *val)
1080 struct ldb_message_element *el;
1082 el = ldb_msg_find_element(msg, attr_name);
1086 return ldb_msg_add_value(msg, attr_name, val, NULL);
1090 set a string element in a message
1092 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1093 const char *attr_name, const char *str)
1095 struct ldb_message_element *el;
1097 el = ldb_msg_find_element(msg, attr_name);
1101 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1105 * Handle ldb_request in transaction
1107 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1108 struct ldb_request *req)
1112 ret = ldb_transaction_start(sam_ldb);
1113 if (ret != LDB_SUCCESS) {
1117 ret = ldb_request(sam_ldb, req);
1118 if (ret == LDB_SUCCESS) {
1119 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1122 if (ret == LDB_SUCCESS) {
1123 return ldb_transaction_commit(sam_ldb);
1125 ldb_transaction_cancel(sam_ldb);
1131 return a default security descriptor
1133 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1135 struct security_descriptor *sd;
1137 sd = security_descriptor_initialise(mem_ctx);
1142 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1144 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1145 struct ldb_dn *aggregate_dn;
1150 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1151 if (!aggregate_dn) {
1154 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1157 return aggregate_dn;
1160 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1162 struct ldb_dn *new_dn;
1164 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1165 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1166 talloc_free(new_dn);
1172 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1174 struct ldb_dn *new_dn;
1176 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1177 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1178 talloc_free(new_dn);
1184 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1186 struct ldb_dn *new_dn;
1188 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1189 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1190 talloc_free(new_dn);
1197 work out the domain sid for the current open ldb
1199 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1201 TALLOC_CTX *tmp_ctx;
1202 const struct dom_sid *domain_sid;
1203 const char *attrs[] = {
1207 struct ldb_result *res;
1210 /* see if we have a cached copy */
1211 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1216 tmp_ctx = talloc_new(ldb);
1217 if (tmp_ctx == NULL) {
1221 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1223 if (ret != LDB_SUCCESS) {
1227 if (res->count != 1) {
1231 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1232 if (domain_sid == NULL) {
1236 /* cache the domain_sid in the ldb */
1237 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1241 talloc_steal(ldb, domain_sid);
1242 talloc_free(tmp_ctx);
1247 talloc_free(tmp_ctx);
1252 get domain sid from cache
1254 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1256 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1259 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1261 TALLOC_CTX *tmp_ctx;
1262 struct dom_sid *dom_sid_new;
1263 struct dom_sid *dom_sid_old;
1265 /* see if we have a cached copy */
1266 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1267 "cache.domain_sid"), struct dom_sid);
1269 tmp_ctx = talloc_new(ldb);
1270 if (tmp_ctx == NULL) {
1274 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1279 /* cache the domain_sid in the ldb */
1280 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1284 talloc_steal(ldb, dom_sid_new);
1285 talloc_free(tmp_ctx);
1286 talloc_free(dom_sid_old);
1291 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1292 talloc_free(tmp_ctx);
1296 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1298 TALLOC_CTX *tmp_ctx;
1299 struct ldb_dn *ntds_settings_dn_new;
1300 struct ldb_dn *ntds_settings_dn_old;
1302 /* see if we have a cached copy */
1303 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1304 "cache.ntds_settings_dn"), struct ldb_dn);
1306 tmp_ctx = talloc_new(ldb);
1307 if (tmp_ctx == NULL) {
1311 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1312 if (!ntds_settings_dn_new) {
1316 /* cache the domain_sid in the ldb */
1317 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1321 talloc_steal(ldb, ntds_settings_dn_new);
1322 talloc_free(tmp_ctx);
1323 talloc_free(ntds_settings_dn_old);
1328 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1329 talloc_free(tmp_ctx);
1333 /* Obtain the short name of the flexible single master operator
1334 * (FSMO), such as the PDC Emulator */
1335 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1338 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1339 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1340 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1341 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1343 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1344 /* Ensure this matches the format. This gives us a
1345 * bit more confidence that a 'cn' value will be a
1350 return (char *)val->data;
1356 work out the ntds settings dn for the current open ldb
1358 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1360 TALLOC_CTX *tmp_ctx;
1361 const char *root_attrs[] = { "dsServiceName", NULL };
1363 struct ldb_result *root_res;
1364 struct ldb_dn *settings_dn;
1366 /* see if we have a cached copy */
1367 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1372 tmp_ctx = talloc_new(ldb);
1373 if (tmp_ctx == NULL) {
1377 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1379 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1380 ldb_errstring(ldb)));
1384 if (root_res->count != 1) {
1388 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1390 /* cache the domain_sid in the ldb */
1391 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1395 talloc_steal(ldb, settings_dn);
1396 talloc_free(tmp_ctx);
1401 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1402 talloc_free(tmp_ctx);
1407 work out the ntds settings invocationId for the current open ldb
1409 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1411 TALLOC_CTX *tmp_ctx;
1412 const char *attrs[] = { "invocationId", NULL };
1414 struct ldb_result *res;
1415 struct GUID *invocation_id;
1417 /* see if we have a cached copy */
1418 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1419 if (invocation_id) {
1420 return invocation_id;
1423 tmp_ctx = talloc_new(ldb);
1424 if (tmp_ctx == NULL) {
1428 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1433 if (res->count != 1) {
1437 invocation_id = talloc(tmp_ctx, struct GUID);
1438 if (!invocation_id) {
1442 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1444 /* cache the domain_sid in the ldb */
1445 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1449 talloc_steal(ldb, invocation_id);
1450 talloc_free(tmp_ctx);
1452 return invocation_id;
1455 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1456 talloc_free(tmp_ctx);
1460 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1462 TALLOC_CTX *tmp_ctx;
1463 struct GUID *invocation_id_new;
1464 struct GUID *invocation_id_old;
1466 /* see if we have a cached copy */
1467 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1468 "cache.invocation_id");
1470 tmp_ctx = talloc_new(ldb);
1471 if (tmp_ctx == NULL) {
1475 invocation_id_new = talloc(tmp_ctx, struct GUID);
1476 if (!invocation_id_new) {
1480 *invocation_id_new = *invocation_id_in;
1482 /* cache the domain_sid in the ldb */
1483 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1487 talloc_steal(ldb, invocation_id_new);
1488 talloc_free(tmp_ctx);
1489 talloc_free(invocation_id_old);
1494 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1495 talloc_free(tmp_ctx);
1500 work out the ntds settings objectGUID for the current open ldb
1502 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1504 TALLOC_CTX *tmp_ctx;
1505 const char *attrs[] = { "objectGUID", NULL };
1507 struct ldb_result *res;
1508 struct GUID *ntds_guid;
1510 /* see if we have a cached copy */
1511 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1516 tmp_ctx = talloc_new(ldb);
1517 if (tmp_ctx == NULL) {
1521 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1526 if (res->count != 1) {
1530 ntds_guid = talloc(tmp_ctx, struct GUID);
1535 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1537 /* cache the domain_sid in the ldb */
1538 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1542 talloc_steal(ldb, ntds_guid);
1543 talloc_free(tmp_ctx);
1548 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1549 talloc_free(tmp_ctx);
1553 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1555 TALLOC_CTX *tmp_ctx;
1556 struct GUID *ntds_guid_new;
1557 struct GUID *ntds_guid_old;
1559 /* see if we have a cached copy */
1560 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1562 tmp_ctx = talloc_new(ldb);
1563 if (tmp_ctx == NULL) {
1567 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1568 if (!ntds_guid_new) {
1572 *ntds_guid_new = *ntds_guid_in;
1574 /* cache the domain_sid in the ldb */
1575 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1579 talloc_steal(ldb, ntds_guid_new);
1580 talloc_free(tmp_ctx);
1581 talloc_free(ntds_guid_old);
1586 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1587 talloc_free(tmp_ctx);
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1600 work out the server dn for the current open ldb
1602 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1604 struct ldb_dn *server_dn;
1605 struct ldb_dn *servers_dn;
1606 struct ldb_dn *server_site_dn;
1608 /* TODO: there must be a saner way to do this!! */
1609 server_dn = samdb_server_dn(ldb, mem_ctx);
1610 if (!server_dn) return NULL;
1612 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1613 talloc_free(server_dn);
1614 if (!servers_dn) return NULL;
1616 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1617 talloc_free(servers_dn);
1619 return server_site_dn;
1623 find a 'reference' DN that points at another object
1624 (eg. serverReference, rIDManagerReference etc)
1626 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1627 const char *attribute, struct ldb_dn **dn)
1629 const char *attrs[2];
1630 struct ldb_result *res;
1633 attrs[0] = attribute;
1636 ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
1637 if (ret != LDB_SUCCESS) {
1640 if (res->count != 1) {
1642 return LDB_ERR_NO_SUCH_OBJECT;
1645 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1648 ldb_asprintf_errstring(ldb, "Cannot find dn of attribute %s of %s", attribute,
1649 ldb_dn_get_linearized(base));
1650 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1658 find our machine account via the serverReference attribute in the
1661 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1663 struct ldb_dn *server_dn;
1666 server_dn = samdb_server_dn(ldb, mem_ctx);
1667 if (server_dn == NULL) {
1668 return LDB_ERR_NO_SUCH_OBJECT;
1671 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1672 talloc_free(server_dn);
1678 find the RID Manager$ DN via the rIDManagerReference attribute in the
1681 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1683 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1684 "rIDManagerReference", dn);
1688 find the RID Set DN via the rIDSetReferences attribute in our
1691 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1693 struct ldb_dn *server_ref_dn;
1696 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1697 if (ret != LDB_SUCCESS) {
1700 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1701 talloc_free(server_ref_dn);
1705 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1707 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1714 return (const char *) val->data;
1718 * Finds the client site by using the client's IP address.
1719 * The "subnet_name" returns the name of the subnet if parameter != NULL
1721 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1722 const char *ip_address, char **subnet_name)
1724 const char *attrs[] = { "cn", "siteObject", NULL };
1725 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1726 struct ldb_result *res;
1727 const struct ldb_val *val;
1728 const char *site_name = NULL, *l_subnet_name = NULL;
1729 const char *allow_list[2] = { NULL, NULL };
1730 unsigned int i, count;
1734 * if we don't have a client ip e.g. ncalrpc
1735 * the server site is the client site
1737 if (ip_address == NULL) {
1738 return samdb_server_site_name(ldb, mem_ctx);
1741 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1742 if (sites_container_dn == NULL) {
1746 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1747 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1748 talloc_free(sites_container_dn);
1749 talloc_free(subnets_dn);
1753 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1755 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1757 } else if (ret != LDB_SUCCESS) {
1758 talloc_free(sites_container_dn);
1759 talloc_free(subnets_dn);
1765 for (i = 0; i < count; i++) {
1766 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1769 allow_list[0] = l_subnet_name;
1771 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1772 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1775 if (sites_dn == NULL) {
1776 /* No reference, maybe another subnet matches */
1780 /* "val" cannot be NULL here since "sites_dn" != NULL */
1781 val = ldb_dn_get_rdn_val(sites_dn);
1782 site_name = talloc_strdup(mem_ctx,
1783 (const char *) val->data);
1785 talloc_free(sites_dn);
1791 if (site_name == NULL) {
1792 /* This is the Windows Server fallback rule: when no subnet
1793 * exists and we have only one site available then use it (it
1794 * is for sure the same as our server site). If more sites do
1795 * exist then we don't know which one to use and set the site
1797 cnt = samdb_search_count(ldb, sites_container_dn,
1798 "(objectClass=site)");
1800 site_name = samdb_server_site_name(ldb, mem_ctx);
1802 site_name = talloc_strdup(mem_ctx, "");
1804 l_subnet_name = NULL;
1807 if (subnet_name != NULL) {
1808 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1811 talloc_free(sites_container_dn);
1812 talloc_free(subnets_dn);
1819 work out if we are the PDC for the domain of the current open ldb
1821 bool samdb_is_pdc(struct ldb_context *ldb)
1823 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1825 struct ldb_result *dom_res;
1826 TALLOC_CTX *tmp_ctx;
1830 tmp_ctx = talloc_new(ldb);
1831 if (tmp_ctx == NULL) {
1832 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1836 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1837 if (ret != LDB_SUCCESS) {
1838 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1839 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1840 ldb_errstring(ldb)));
1843 if (dom_res->count != 1) {
1847 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1849 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1855 talloc_free(tmp_ctx);
1860 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1861 talloc_free(tmp_ctx);
1866 work out if we are a Global Catalog server for the domain of the current open ldb
1868 bool samdb_is_gc(struct ldb_context *ldb)
1870 const char *attrs[] = { "options", NULL };
1872 struct ldb_result *res;
1873 TALLOC_CTX *tmp_ctx;
1875 tmp_ctx = talloc_new(ldb);
1876 if (tmp_ctx == NULL) {
1877 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1881 /* Query cn=ntds settings,.... */
1882 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1883 if (ret != LDB_SUCCESS) {
1884 talloc_free(tmp_ctx);
1887 if (res->count != 1) {
1888 talloc_free(tmp_ctx);
1892 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1893 talloc_free(tmp_ctx);
1895 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1896 if (options & 0x000000001) {
1902 /* Find a domain object in the parents of a particular DN. */
1903 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1904 struct ldb_dn **parent_dn, const char **errstring)
1906 TALLOC_CTX *local_ctx;
1907 struct ldb_dn *sdn = dn;
1908 struct ldb_result *res = NULL;
1909 int ret = LDB_SUCCESS;
1910 const char *attrs[] = { NULL };
1912 local_ctx = talloc_new(mem_ctx);
1913 if (local_ctx == NULL) return ldb_oom(ldb);
1915 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1916 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1917 "(|(objectClass=domain)(objectClass=builtinDomain))");
1918 if (ret == LDB_SUCCESS) {
1919 if (res->count == 1) {
1927 if (ret != LDB_SUCCESS) {
1928 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1929 ldb_dn_get_linearized(dn),
1930 ldb_dn_get_linearized(sdn),
1931 ldb_errstring(ldb));
1932 talloc_free(local_ctx);
1935 if (res->count != 1) {
1936 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1937 ldb_dn_get_linearized(dn));
1938 DEBUG(0,(__location__ ": %s\n", *errstring));
1939 talloc_free(local_ctx);
1940 return LDB_ERR_CONSTRAINT_VIOLATION;
1943 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1944 talloc_free(local_ctx);
1950 * Performs checks on a user password (plaintext UNIX format - attribute
1951 * "password"). The remaining parameters have to be extracted from the domain
1954 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1956 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1957 const uint32_t pwdProperties,
1958 const uint32_t minPwdLength)
1960 /* checks if the "minPwdLength" property is satisfied */
1961 if (minPwdLength > password->length)
1962 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1964 /* checks the password complexity */
1965 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1966 && (password->data != NULL)
1967 && (!check_password_quality((const char *) password->data)))
1968 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1970 return SAMR_VALIDATION_STATUS_SUCCESS;
1974 * Callback for "samdb_set_password" password change
1976 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
1981 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1984 if (ares->error != LDB_SUCCESS) {
1986 req->context = talloc_steal(req,
1987 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
1989 return ldb_request_done(req, ret);
1992 if (ares->type != LDB_REPLY_DONE) {
1994 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1997 req->context = talloc_steal(req,
1998 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2000 return ldb_request_done(req, LDB_SUCCESS);
2004 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2005 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2006 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2007 * user change or not. The "rejectReason" gives some more informations if the
2010 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2011 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2013 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2014 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2015 const DATA_BLOB *new_password,
2016 const struct samr_Password *lmNewHash,
2017 const struct samr_Password *ntNewHash,
2018 const struct samr_Password *lmOldHash,
2019 const struct samr_Password *ntOldHash,
2020 enum samPwdChangeReason *reject_reason,
2021 struct samr_DomInfo1 **_dominfo)
2023 struct ldb_message *msg;
2024 struct ldb_message_element *el;
2025 struct ldb_request *req;
2026 struct dsdb_control_password_change_status *pwd_stat = NULL;
2028 NTSTATUS status = NT_STATUS_OK;
2030 #define CHECK_RET(x) \
2031 if (x != LDB_SUCCESS) { \
2033 return NT_STATUS_NO_MEMORY; \
2036 msg = ldb_msg_new(mem_ctx);
2038 return NT_STATUS_NO_MEMORY;
2041 if ((new_password != NULL)
2042 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2043 /* we have the password as plaintext UTF16 */
2044 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2045 "clearTextPassword", new_password));
2046 el = ldb_msg_find_element(msg, "clearTextPassword");
2047 el->flags = LDB_FLAG_MOD_REPLACE;
2048 } else if ((new_password == NULL)
2049 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2050 /* we have a password as LM and/or NT hash */
2051 if (lmNewHash != NULL) {
2052 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2053 "dBCSPwd", lmNewHash));
2054 el = ldb_msg_find_element(msg, "dBCSPwd");
2055 el->flags = LDB_FLAG_MOD_REPLACE;
2057 if (ntNewHash != NULL) {
2058 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2059 "unicodePwd", ntNewHash));
2060 el = ldb_msg_find_element(msg, "unicodePwd");
2061 el->flags = LDB_FLAG_MOD_REPLACE;
2064 /* the password wasn't specified correctly */
2066 return NT_STATUS_INVALID_PARAMETER;
2069 /* build modify request */
2070 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2071 samdb_set_password_callback, NULL);
2072 if (ret != LDB_SUCCESS) {
2074 return NT_STATUS_NO_MEMORY;
2077 /* A password change operation */
2078 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2079 struct dsdb_control_password_change *change;
2081 change = talloc(req, struct dsdb_control_password_change);
2082 if (change == NULL) {
2085 return NT_STATUS_NO_MEMORY;
2088 change->old_nt_pwd_hash = ntOldHash;
2089 change->old_lm_pwd_hash = lmOldHash;
2091 ret = ldb_request_add_control(req,
2092 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2094 if (ret != LDB_SUCCESS) {
2097 return NT_STATUS_NO_MEMORY;
2100 ret = ldb_request_add_control(req,
2101 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2103 if (ret != LDB_SUCCESS) {
2106 return NT_STATUS_NO_MEMORY;
2108 ret = ldb_request_add_control(req,
2109 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2111 if (ret != LDB_SUCCESS) {
2114 return NT_STATUS_NO_MEMORY;
2117 ret = dsdb_autotransaction_request(ldb, req);
2119 if (req->context != NULL) {
2120 pwd_stat = talloc_steal(mem_ctx,
2121 ((struct ldb_control *)req->context)->data);
2127 /* Sets the domain info (if requested) */
2128 if (_dominfo != NULL) {
2129 struct samr_DomInfo1 *dominfo;
2131 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2132 if (dominfo == NULL) {
2133 return NT_STATUS_NO_MEMORY;
2136 if (pwd_stat != NULL) {
2137 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2138 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2139 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2140 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2141 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2144 *_dominfo = dominfo;
2147 if (reject_reason != NULL) {
2148 if (pwd_stat != NULL) {
2149 *reject_reason = pwd_stat->reject_reason;
2151 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2155 if (pwd_stat != NULL) {
2156 talloc_free(pwd_stat);
2159 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2160 const char *errmsg = ldb_errstring(ldb);
2161 char *endptr = NULL;
2162 WERROR werr = WERR_GENERAL_FAILURE;
2163 status = NT_STATUS_UNSUCCESSFUL;
2164 if (errmsg != NULL) {
2165 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2167 if (endptr != errmsg) {
2168 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2169 status = NT_STATUS_WRONG_PASSWORD;
2171 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2172 status = NT_STATUS_PASSWORD_RESTRICTION;
2175 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2176 /* don't let the caller know if an account doesn't exist */
2177 status = NT_STATUS_WRONG_PASSWORD;
2178 } else if (ret != LDB_SUCCESS) {
2179 status = NT_STATUS_UNSUCCESSFUL;
2186 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2187 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2188 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2189 * user change or not. The "rejectReason" gives some more informations if the
2192 * This wrapper function for "samdb_set_password" takes a SID as input rather
2195 * This call encapsulates a new LDB transaction for changing the password;
2196 * therefore the user hasn't to start a new one.
2198 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2199 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2200 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2201 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2203 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2204 const struct dom_sid *user_sid,
2205 const DATA_BLOB *new_password,
2206 const struct samr_Password *lmNewHash,
2207 const struct samr_Password *ntNewHash,
2208 const struct samr_Password *lmOldHash,
2209 const struct samr_Password *ntOldHash,
2210 enum samPwdChangeReason *reject_reason,
2211 struct samr_DomInfo1 **_dominfo)
2214 struct ldb_dn *user_dn;
2217 ret = ldb_transaction_start(ldb);
2218 if (ret != LDB_SUCCESS) {
2219 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2220 return NT_STATUS_TRANSACTION_ABORTED;
2223 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2224 "(&(objectSid=%s)(objectClass=user))",
2225 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2227 ldb_transaction_cancel(ldb);
2228 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2229 dom_sid_string(mem_ctx, user_sid)));
2230 return NT_STATUS_NO_SUCH_USER;
2233 nt_status = samdb_set_password(ldb, mem_ctx,
2236 lmNewHash, ntNewHash,
2237 lmOldHash, ntOldHash,
2238 reject_reason, _dominfo);
2239 if (!NT_STATUS_IS_OK(nt_status)) {
2240 ldb_transaction_cancel(ldb);
2241 talloc_free(user_dn);
2245 ret = ldb_transaction_commit(ldb);
2246 if (ret != LDB_SUCCESS) {
2247 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2248 ldb_dn_get_linearized(user_dn),
2249 ldb_errstring(ldb)));
2250 talloc_free(user_dn);
2251 return NT_STATUS_TRANSACTION_ABORTED;
2254 talloc_free(user_dn);
2255 return NT_STATUS_OK;
2259 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2260 struct dom_sid *sid, struct ldb_dn **ret_dn)
2262 struct ldb_message *msg;
2263 struct ldb_dn *basedn;
2267 sidstr = dom_sid_string(mem_ctx, sid);
2268 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2270 /* We might have to create a ForeignSecurityPrincipal, even if this user
2271 * is in our own domain */
2273 msg = ldb_msg_new(sidstr);
2275 talloc_free(sidstr);
2276 return NT_STATUS_NO_MEMORY;
2279 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2280 ldb_get_default_basedn(sam_ctx),
2281 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2283 if (ret != LDB_SUCCESS) {
2284 DEBUG(0, ("Failed to find DN for "
2285 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2286 talloc_free(sidstr);
2287 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2290 /* add core elements to the ldb_message for the alias */
2292 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2293 talloc_free(sidstr);
2294 return NT_STATUS_NO_MEMORY;
2297 samdb_msg_add_string(sam_ctx, msg, msg,
2299 "foreignSecurityPrincipal");
2301 /* create the alias */
2302 ret = ldb_add(sam_ctx, msg);
2303 if (ret != LDB_SUCCESS) {
2304 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2306 ldb_dn_get_linearized(msg->dn),
2307 ldb_errstring(sam_ctx)));
2308 talloc_free(sidstr);
2309 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2312 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2313 talloc_free(sidstr);
2315 return NT_STATUS_OK;
2320 Find the DN of a domain, assuming it to be a dotted.dns name
2323 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2326 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2327 const char *binary_encoded;
2328 const char **split_realm;
2335 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2337 talloc_free(tmp_ctx);
2340 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2341 for (i=0; split_realm[i]; i++) {
2342 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2343 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2344 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2345 binary_encoded, ldb_dn_get_linearized(dn)));
2346 talloc_free(tmp_ctx);
2350 if (!ldb_dn_validate(dn)) {
2351 DEBUG(2, ("Failed to validated DN %s\n",
2352 ldb_dn_get_linearized(dn)));
2353 talloc_free(tmp_ctx);
2356 talloc_free(tmp_ctx);
2361 Find the DN of a domain, be it the netbios or DNS name
2363 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2364 const char *domain_name)
2366 const char * const domain_ref_attrs[] = {
2369 const char * const domain_ref2_attrs[] = {
2372 struct ldb_result *res_domain_ref;
2373 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2374 /* find the domain's DN */
2375 int ret_domain = ldb_search(ldb, mem_ctx,
2377 samdb_partitions_dn(ldb, mem_ctx),
2380 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2382 if (ret_domain != LDB_SUCCESS) {
2386 if (res_domain_ref->count == 0) {
2387 ret_domain = ldb_search(ldb, mem_ctx,
2389 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2392 "(objectclass=domain)");
2393 if (ret_domain != LDB_SUCCESS) {
2397 if (res_domain_ref->count == 1) {
2398 return res_domain_ref->msgs[0]->dn;
2403 if (res_domain_ref->count > 1) {
2404 DEBUG(0,("Found %d records matching domain [%s]\n",
2405 ret_domain, domain_name));
2409 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2415 use a GUID to find a DN
2417 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2418 TALLOC_CTX *mem_ctx,
2419 const struct GUID *guid, struct ldb_dn **dn)
2422 struct ldb_result *res;
2423 const char *attrs[] = { NULL };
2424 char *guid_str = GUID_string(mem_ctx, guid);
2427 return ldb_operr(ldb);
2430 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2431 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2432 DSDB_SEARCH_SHOW_EXTENDED_DN |
2433 DSDB_SEARCH_ONE_ONLY,
2434 "objectGUID=%s", guid_str);
2435 talloc_free(guid_str);
2436 if (ret != LDB_SUCCESS) {
2440 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2447 use a DN to find a GUID with a given attribute name
2449 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2450 struct ldb_dn *dn, const char *attribute,
2454 struct ldb_result *res;
2455 const char *attrs[2];
2456 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2458 attrs[0] = attribute;
2461 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2462 if (ret != LDB_SUCCESS) {
2463 talloc_free(tmp_ctx);
2466 if (res->count < 1) {
2467 talloc_free(tmp_ctx);
2468 return LDB_ERR_NO_SUCH_OBJECT;
2470 *guid = samdb_result_guid(res->msgs[0], attribute);
2471 talloc_free(tmp_ctx);
2476 use a DN to find a GUID
2478 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2479 struct ldb_dn *dn, struct GUID *guid)
2481 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2487 adds the given GUID to the given ldb_message. This value is added
2488 for the given attr_name (may be either "objectGUID" or "parentGUID").
2490 int dsdb_msg_add_guid(struct ldb_message *msg,
2492 const char *attr_name)
2497 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2499 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2500 if (!NT_STATUS_IS_OK(status)) {
2501 ret = LDB_ERR_OPERATIONS_ERROR;
2505 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2506 if (ret != LDB_SUCCESS) {
2507 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2515 talloc_free(tmp_ctx);
2522 use a DN to find a SID
2524 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2525 struct ldb_dn *dn, struct dom_sid *sid)
2528 struct ldb_result *res;
2529 const char *attrs[] = { "objectSid", NULL };
2530 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2535 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2536 if (ret != LDB_SUCCESS) {
2537 talloc_free(tmp_ctx);
2540 if (res->count < 1) {
2541 talloc_free(tmp_ctx);
2542 return LDB_ERR_NO_SUCH_OBJECT;
2544 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2546 talloc_free(tmp_ctx);
2547 return LDB_ERR_NO_SUCH_OBJECT;
2550 talloc_free(tmp_ctx);
2555 use a SID to find a DN
2557 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2558 TALLOC_CTX *mem_ctx,
2559 struct dom_sid *sid, struct ldb_dn **dn)
2562 struct ldb_result *res;
2563 const char *attrs[] = { NULL };
2564 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2567 return ldb_operr(ldb);
2570 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2571 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2572 DSDB_SEARCH_SHOW_EXTENDED_DN |
2573 DSDB_SEARCH_ONE_ONLY,
2574 "objectSid=%s", sid_str);
2575 talloc_free(sid_str);
2576 if (ret != LDB_SUCCESS) {
2580 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2587 load a repsFromTo blob list for a given partition GUID
2588 attr must be "repsFrom" or "repsTo"
2590 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2591 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2593 const char *attrs[] = { attr, NULL };
2594 struct ldb_result *res = NULL;
2595 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2597 struct ldb_message_element *el;
2602 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2604 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2605 talloc_free(tmp_ctx);
2606 return WERR_DS_DRA_INTERNAL_ERROR;
2609 el = ldb_msg_find_element(res->msgs[0], attr);
2611 /* it's OK to be empty */
2612 talloc_free(tmp_ctx);
2616 *count = el->num_values;
2617 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2619 talloc_free(tmp_ctx);
2620 return WERR_DS_DRA_INTERNAL_ERROR;
2623 for (i=0; i<(*count); i++) {
2624 enum ndr_err_code ndr_err;
2625 ndr_err = ndr_pull_struct_blob(&el->values[i],
2628 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2629 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2630 talloc_free(tmp_ctx);
2631 return WERR_DS_DRA_INTERNAL_ERROR;
2635 talloc_free(tmp_ctx);
2641 save the repsFromTo blob list for a given partition GUID
2642 attr must be "repsFrom" or "repsTo"
2644 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2645 const char *attr, struct repsFromToBlob *r, uint32_t count)
2647 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2648 struct ldb_message *msg;
2649 struct ldb_message_element *el;
2652 msg = ldb_msg_new(tmp_ctx);
2654 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2658 el->values = talloc_array(msg, struct ldb_val, count);
2663 for (i=0; i<count; i++) {
2665 enum ndr_err_code ndr_err;
2667 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2669 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2670 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2678 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2679 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2683 talloc_free(tmp_ctx);
2688 talloc_free(tmp_ctx);
2689 return WERR_DS_DRA_INTERNAL_ERROR;
2694 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2695 object for a partition
2697 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2698 uint64_t *uSN, uint64_t *urgent_uSN)
2700 struct ldb_request *req;
2702 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2703 struct dsdb_control_current_partition *p_ctrl;
2704 struct ldb_result *res;
2706 res = talloc_zero(tmp_ctx, struct ldb_result);
2708 talloc_free(tmp_ctx);
2709 return ldb_oom(ldb);
2712 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2713 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2717 res, ldb_search_default_callback,
2719 if (ret != LDB_SUCCESS) {
2720 talloc_free(tmp_ctx);
2724 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2725 if (p_ctrl == NULL) {
2726 talloc_free(tmp_ctx);
2727 return ldb_oom(ldb);
2729 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2732 ret = ldb_request_add_control(req,
2733 DSDB_CONTROL_CURRENT_PARTITION_OID,
2735 if (ret != LDB_SUCCESS) {
2736 talloc_free(tmp_ctx);
2740 /* Run the new request */
2741 ret = ldb_request(ldb, req);
2743 if (ret == LDB_SUCCESS) {
2744 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2747 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2748 /* it hasn't been created yet, which means
2749 an implicit value of zero */
2751 talloc_free(tmp_ctx);
2755 if (ret != LDB_SUCCESS) {
2756 talloc_free(tmp_ctx);
2760 if (res->count < 1) {
2766 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2768 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2772 talloc_free(tmp_ctx);
2777 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2778 const struct drsuapi_DsReplicaCursor2 *c2)
2780 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2783 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2784 const struct drsuapi_DsReplicaCursor *c2)
2786 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2791 see if a computer identified by its invocationId is a RODC
2793 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2795 /* 1) find the DN for this servers NTDSDSA object
2796 2) search for the msDS-isRODC attribute
2797 3) if not present then not a RODC
2798 4) if present and TRUE then is a RODC
2800 struct ldb_dn *config_dn;
2801 const char *attrs[] = { "msDS-isRODC", NULL };
2803 struct ldb_result *res;
2804 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2806 config_dn = ldb_get_config_basedn(sam_ctx);
2808 talloc_free(tmp_ctx);
2809 return ldb_operr(sam_ctx);
2812 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2813 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2815 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2817 talloc_free(tmp_ctx);
2821 if (ret != LDB_SUCCESS) {
2822 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2823 GUID_string(tmp_ctx, objectGUID)));
2825 talloc_free(tmp_ctx);
2829 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2830 *is_rodc = (ret == 1);
2832 talloc_free(tmp_ctx);
2838 see if we are a RODC
2840 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2842 const struct GUID *objectGUID;
2846 /* see if we have a cached copy */
2847 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2853 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2855 return ldb_operr(sam_ctx);
2858 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2859 if (ret != LDB_SUCCESS) {
2863 cached = talloc(sam_ctx, bool);
2864 if (cached == NULL) {
2865 return ldb_oom(sam_ctx);
2869 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2870 if (ret != LDB_SUCCESS) {
2871 talloc_free(cached);
2872 return ldb_operr(sam_ctx);
2878 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2880 TALLOC_CTX *tmp_ctx;
2883 tmp_ctx = talloc_new(ldb);
2884 if (tmp_ctx == NULL) {
2888 cached = talloc(tmp_ctx, bool);
2894 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2898 talloc_steal(ldb, cached);
2899 talloc_free(tmp_ctx);
2903 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2904 talloc_free(tmp_ctx);
2910 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2912 flags are DS_NTDS_OPTION_*
2914 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2916 TALLOC_CTX *tmp_ctx;
2917 const char *attrs[] = { "options", NULL };
2919 struct ldb_result *res;
2921 tmp_ctx = talloc_new(ldb);
2922 if (tmp_ctx == NULL) {
2926 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2927 if (ret != LDB_SUCCESS) {
2931 if (res->count != 1) {
2935 *options = samdb_result_uint(res->msgs[0], "options", 0);
2937 talloc_free(tmp_ctx);
2942 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
2943 talloc_free(tmp_ctx);
2944 return LDB_ERR_NO_SUCH_OBJECT;
2947 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
2949 const char *attrs[] = { "objectCategory", NULL };
2951 struct ldb_result *res;
2953 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2954 if (ret != LDB_SUCCESS) {
2958 if (res->count != 1) {
2962 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
2965 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
2970 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2971 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2973 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2975 char **tokens, *ret;
2978 tokens = str_list_make(mem_ctx, cn, " -_");
2982 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2983 tokens[0][0] = tolower(tokens[0][0]);
2984 for (i = 1; i < str_list_length((const char **)tokens); i++)
2985 tokens[i][0] = toupper(tokens[i][0]);
2987 ret = talloc_strdup(mem_ctx, tokens[0]);
2988 for (i = 1; i < str_list_length((const char **)tokens); i++)
2989 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2991 talloc_free(tokens);
2997 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
2999 int dsdb_functional_level(struct ldb_context *ldb)
3001 int *domainFunctionality =
3002 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3003 if (!domainFunctionality) {
3004 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
3005 return DS_DOMAIN_FUNCTION_2000;
3007 return *domainFunctionality;
3011 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3013 int dsdb_forest_functional_level(struct ldb_context *ldb)
3015 int *forestFunctionality =
3016 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3017 if (!forestFunctionality) {
3018 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3019 return DS_DOMAIN_FUNCTION_2000;
3021 return *forestFunctionality;
3025 set a GUID in an extended DN structure
3027 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3033 status = GUID_to_ndr_blob(guid, dn, &v);
3034 if (!NT_STATUS_IS_OK(status)) {
3035 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3038 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3044 return a GUID from a extended DN structure
3046 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3048 const struct ldb_val *v;
3050 v = ldb_dn_get_extended_component(dn, component_name);
3052 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3055 return GUID_from_ndr_blob(v, guid);
3059 return a uint64_t from a extended DN structure
3061 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3063 const struct ldb_val *v;
3066 v = ldb_dn_get_extended_component(dn, component_name);
3068 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3070 s = talloc_strndup(dn, (const char *)v->data, v->length);
3071 NT_STATUS_HAVE_NO_MEMORY(s);
3073 *val = strtoull(s, NULL, 0);
3076 return NT_STATUS_OK;
3080 return a NTTIME from a extended DN structure
3082 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3084 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3088 return a uint32_t from a extended DN structure
3090 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3092 const struct ldb_val *v;
3095 v = ldb_dn_get_extended_component(dn, component_name);
3097 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3100 s = talloc_strndup(dn, (const char *)v->data, v->length);
3101 NT_STATUS_HAVE_NO_MEMORY(s);
3103 *val = strtoul(s, NULL, 0);
3106 return NT_STATUS_OK;
3110 return a dom_sid from a extended DN structure
3112 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3114 const struct ldb_val *sid_blob;
3115 struct TALLOC_CTX *tmp_ctx;
3116 enum ndr_err_code ndr_err;
3118 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3120 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3123 tmp_ctx = talloc_new(NULL);
3125 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3126 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3127 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3128 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3129 talloc_free(tmp_ctx);
3133 talloc_free(tmp_ctx);
3134 return NT_STATUS_OK;
3139 return RMD_FLAGS directly from a ldb_dn
3140 returns 0 if not found
3142 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3144 const struct ldb_val *v;
3146 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3147 if (!v || v->length > sizeof(buf)-1) return 0;
3148 strncpy(buf, (const char *)v->data, v->length);
3150 return strtoul(buf, NULL, 10);
3154 return RMD_FLAGS directly from a ldb_val for a DN
3155 returns 0 if RMD_FLAGS is not found
3157 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3163 if (val->length < 13) {
3166 p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
3170 flags = strtoul(p+11, &end, 10);
3171 if (!end || *end != '>') {
3172 /* it must end in a > */
3179 return true if a ldb_val containing a DN in storage form is deleted
3181 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3183 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3187 return true if a ldb_val containing a DN in storage form is
3188 in the upgraded w2k3 linked attribute format
3190 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3192 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3196 return a DN for a wellknown GUID
3198 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3199 struct ldb_dn *nc_root, const char *wk_guid,
3200 struct ldb_dn **wkguid_dn)
3202 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3203 const char *attrs[] = { NULL };
3206 struct ldb_result *res;
3208 /* construct the magic WKGUID DN */
3209 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3210 wk_guid, ldb_dn_get_linearized(nc_root));
3212 talloc_free(tmp_ctx);
3213 return ldb_operr(samdb);
3216 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3217 if (ret != LDB_SUCCESS) {
3218 talloc_free(tmp_ctx);
3222 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3223 talloc_free(tmp_ctx);
3228 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3230 return ldb_dn_compare(*dn1, *dn2);
3234 find a NC root given a DN within the NC
3236 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3237 struct ldb_dn **nc_root)
3239 const char *root_attrs[] = { "namingContexts", NULL };
3240 TALLOC_CTX *tmp_ctx;
3242 struct ldb_message_element *el;
3243 struct ldb_result *root_res;
3245 struct ldb_dn **nc_dns;
3247 tmp_ctx = talloc_new(samdb);
3248 if (tmp_ctx == NULL) {
3249 return ldb_oom(samdb);
3252 ret = ldb_search(samdb, tmp_ctx, &root_res,
3253 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3254 if (ret != LDB_SUCCESS) {
3255 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3256 talloc_free(tmp_ctx);
3260 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3262 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3263 ldb_errstring(samdb)));
3264 talloc_free(tmp_ctx);
3265 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3268 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3270 talloc_free(tmp_ctx);
3271 return ldb_oom(samdb);
3274 for (i=0; i<el->num_values; i++) {
3275 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3276 if (nc_dns[i] == NULL) {
3277 talloc_free(tmp_ctx);
3278 return ldb_operr(samdb);
3282 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3284 for (i=0; i<el->num_values; i++) {
3285 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3286 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3287 talloc_free(tmp_ctx);
3292 talloc_free(tmp_ctx);
3293 return LDB_ERR_NO_SUCH_OBJECT;
3298 find the deleted objects DN for any object, by looking for the NC
3299 root, then looking up the wellknown GUID
3301 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3302 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3303 struct ldb_dn **do_dn)
3305 struct ldb_dn *nc_root;
3308 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3309 if (ret != LDB_SUCCESS) {
3313 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3314 talloc_free(nc_root);
3319 return the tombstoneLifetime, in days
3321 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3324 dn = ldb_get_config_basedn(ldb);
3326 return LDB_ERR_NO_SUCH_OBJECT;
3328 dn = ldb_dn_copy(ldb, dn);
3330 return ldb_operr(ldb);
3332 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3333 be a wellknown GUID for this */
3334 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3336 return ldb_operr(ldb);
3339 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3345 compare a ldb_val to a string case insensitively
3347 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3349 size_t len = strlen(s);
3351 if (len > v->length) return 1;
3352 ret = strncasecmp(s, (const char *)v->data, v->length);
3353 if (ret != 0) return ret;
3354 if (v->length > len && v->data[len] != 0) {
3362 load the UDV for a partition in v2 format
3363 The list is returned sorted, and with our local cursor added
3365 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3366 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3368 static const char *attrs[] = { "replUpToDateVector", NULL };
3369 struct ldb_result *r;
3370 const struct ldb_val *ouv_value;
3373 uint64_t highest_usn;
3374 const struct GUID *our_invocation_id;
3375 struct timeval now = timeval_current();
3377 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3378 if (ret != LDB_SUCCESS) {
3382 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3384 enum ndr_err_code ndr_err;
3385 struct replUpToDateVectorBlob ouv;
3387 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3388 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3389 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3391 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3393 if (ouv.version != 2) {
3394 /* we always store as version 2, and
3395 * replUpToDateVector is not replicated
3397 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3400 *count = ouv.ctr.ctr2.count;
3401 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3409 our_invocation_id = samdb_ntds_invocation_id(samdb);
3410 if (!our_invocation_id) {
3411 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3412 talloc_free(*cursors);
3413 return ldb_operr(samdb);
3416 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3417 if (ret != LDB_SUCCESS) {
3418 /* nothing to add - this can happen after a vampire */
3419 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3423 for (i=0; i<*count; i++) {
3424 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3425 (*cursors)[i].highest_usn = highest_usn;
3426 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3427 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3432 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3434 return ldb_oom(samdb);
3437 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3438 (*cursors)[*count].highest_usn = highest_usn;
3439 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3442 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3448 load the UDV for a partition in version 1 format
3449 The list is returned sorted, and with our local cursor added
3451 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3452 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3454 struct drsuapi_DsReplicaCursor2 *v2;
3458 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3459 if (ret != LDB_SUCCESS) {
3469 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3470 if (*cursors == NULL) {
3472 return ldb_oom(samdb);
3475 for (i=0; i<*count; i++) {
3476 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3477 (*cursors)[i].highest_usn = v2[i].highest_usn;
3484 add a set of controls to a ldb_request structure based on a set of
3485 flags. See util.h for a list of available flags
3487 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3490 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3491 struct ldb_search_options_control *options;
3492 /* Using the phantom root control allows us to search all partitions */
3493 options = talloc(req, struct ldb_search_options_control);
3494 if (options == NULL) {
3495 return LDB_ERR_OPERATIONS_ERROR;
3497 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3499 ret = ldb_request_add_control(req,
3500 LDB_CONTROL_SEARCH_OPTIONS_OID,
3502 if (ret != LDB_SUCCESS) {
3507 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3508 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3509 if (ret != LDB_SUCCESS) {
3514 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3515 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3516 if (ret != LDB_SUCCESS) {
3521 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3522 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3523 if (!extended_ctrl) {
3524 return LDB_ERR_OPERATIONS_ERROR;
3526 extended_ctrl->type = 1;
3528 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3529 if (ret != LDB_SUCCESS) {
3534 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3535 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3536 if (ret != LDB_SUCCESS) {
3541 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3542 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3543 if (ret != LDB_SUCCESS) {
3548 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3549 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3550 if (ret != LDB_SUCCESS) {
3555 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3556 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3557 if (ret != LDB_SUCCESS) {
3562 if (dsdb_flags & DSDB_TREE_DELETE) {
3563 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3564 if (ret != LDB_SUCCESS) {
3573 an add with a set of controls
3575 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3576 uint32_t dsdb_flags)
3578 struct ldb_request *req;
3581 ret = ldb_build_add_req(&req, ldb, ldb,
3585 ldb_op_default_callback,
3588 if (ret != LDB_SUCCESS) return ret;
3590 ret = dsdb_request_add_controls(req, dsdb_flags);
3591 if (ret != LDB_SUCCESS) {
3596 ret = dsdb_autotransaction_request(ldb, req);
3603 a modify with a set of controls
3605 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3606 uint32_t dsdb_flags)
3608 struct ldb_request *req;
3611 ret = ldb_build_mod_req(&req, ldb, ldb,
3615 ldb_op_default_callback,
3618 if (ret != LDB_SUCCESS) return ret;
3620 ret = dsdb_request_add_controls(req, dsdb_flags);
3621 if (ret != LDB_SUCCESS) {
3626 ret = dsdb_autotransaction_request(ldb, req);
3633 like dsdb_modify() but set all the element flags to
3634 LDB_FLAG_MOD_REPLACE
3636 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3640 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3641 for (i=0;i<msg->num_elements;i++) {
3642 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3645 return dsdb_modify(ldb, msg, dsdb_flags);
3650 search for attrs on one DN, allowing for dsdb_flags controls
3652 int dsdb_search_dn(struct ldb_context *ldb,
3653 TALLOC_CTX *mem_ctx,
3654 struct ldb_result **_res,
3655 struct ldb_dn *basedn,
3656 const char * const *attrs,
3657 uint32_t dsdb_flags)
3660 struct ldb_request *req;
3661 struct ldb_result *res;
3663 res = talloc_zero(mem_ctx, struct ldb_result);
3665 return ldb_oom(ldb);
3668 ret = ldb_build_search_req(&req, ldb, res,
3675 ldb_search_default_callback,
3677 if (ret != LDB_SUCCESS) {
3682 ret = dsdb_request_add_controls(req, dsdb_flags);
3683 if (ret != LDB_SUCCESS) {
3688 ret = ldb_request(ldb, req);
3689 if (ret == LDB_SUCCESS) {
3690 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3694 if (ret != LDB_SUCCESS) {
3704 general search with dsdb_flags for controls
3706 int dsdb_search(struct ldb_context *ldb,
3707 TALLOC_CTX *mem_ctx,
3708 struct ldb_result **_res,
3709 struct ldb_dn *basedn,
3710 enum ldb_scope scope,
3711 const char * const *attrs,
3712 uint32_t dsdb_flags,
3713 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3716 struct ldb_request *req;
3717 struct ldb_result *res;
3719 char *expression = NULL;
3720 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3722 res = talloc_zero(tmp_ctx, struct ldb_result);
3724 talloc_free(tmp_ctx);
3725 return ldb_oom(ldb);
3729 va_start(ap, exp_fmt);
3730 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3734 talloc_free(tmp_ctx);
3735 return ldb_oom(ldb);
3739 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3746 ldb_search_default_callback,
3748 if (ret != LDB_SUCCESS) {
3749 talloc_free(tmp_ctx);
3753 ret = dsdb_request_add_controls(req, dsdb_flags);
3754 if (ret != LDB_SUCCESS) {
3755 talloc_free(tmp_ctx);
3759 ret = ldb_request(ldb, req);
3760 if (ret == LDB_SUCCESS) {
3761 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3764 if (ret != LDB_SUCCESS) {
3765 talloc_free(tmp_ctx);
3769 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3770 if (res->count == 0) {
3771 talloc_free(tmp_ctx);
3772 return LDB_ERR_NO_SUCH_OBJECT;
3774 if (res->count != 1) {
3775 talloc_free(tmp_ctx);
3776 return LDB_ERR_CONSTRAINT_VIOLATION;
3780 *_res = talloc_steal(mem_ctx, res);
3781 talloc_free(tmp_ctx);
3788 general search with dsdb_flags for controls
3789 returns exactly 1 record or an error
3791 int dsdb_search_one(struct ldb_context *ldb,
3792 TALLOC_CTX *mem_ctx,
3793 struct ldb_message **msg,
3794 struct ldb_dn *basedn,
3795 enum ldb_scope scope,
3796 const char * const *attrs,
3797 uint32_t dsdb_flags,
3798 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3801 struct ldb_result *res;
3803 char *expression = NULL;
3804 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3806 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3808 res = talloc_zero(tmp_ctx, struct ldb_result);
3810 talloc_free(tmp_ctx);
3811 return ldb_oom(ldb);
3815 va_start(ap, exp_fmt);
3816 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3820 talloc_free(tmp_ctx);
3821 return ldb_oom(ldb);
3823 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3824 dsdb_flags, "%s", expression);
3826 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3830 if (ret != LDB_SUCCESS) {
3831 talloc_free(tmp_ctx);
3835 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3836 talloc_free(tmp_ctx);
3841 /* returns back the forest DNS name */
3842 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3844 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3845 ldb_get_root_basedn(ldb));
3848 if (forest_name == NULL) {
3852 p = strchr(forest_name, '/');
3861 validate that an DSA GUID belongs to the specified user sid.
3862 The user SID must be a domain controller account (either RODC or
3865 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3866 const struct GUID *dsa_guid,
3867 const struct dom_sid *sid)
3870 - find DN of record with the DSA GUID in the
3871 configuration partition (objectGUID)
3872 - remove "NTDS Settings" component from DN
3873 - do a base search on that DN for serverReference with
3875 - extract objectSid from resulting serverReference
3877 - check this sid matches the sid argument
3879 struct ldb_dn *config_dn;
3880 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3881 struct ldb_message *msg;
3882 const char *attrs1[] = { NULL };
3883 const char *attrs2[] = { "serverReference", NULL };
3885 struct ldb_dn *dn, *account_dn;
3886 struct dom_sid sid2;
3889 config_dn = ldb_get_config_basedn(ldb);
3891 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3892 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3893 if (ret != LDB_SUCCESS) {
3894 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3895 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3896 talloc_free(tmp_ctx);
3897 return ldb_operr(ldb);
3901 if (!ldb_dn_remove_child_components(dn, 1)) {
3902 talloc_free(tmp_ctx);
3903 return ldb_operr(ldb);
3906 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3907 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3908 "(objectClass=server)");
3909 if (ret != LDB_SUCCESS) {
3910 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3911 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3912 talloc_free(tmp_ctx);
3913 return ldb_operr(ldb);
3916 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
3917 if (account_dn == NULL) {
3918 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
3919 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3920 talloc_free(tmp_ctx);
3921 return ldb_operr(ldb);
3924 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
3925 if (!NT_STATUS_IS_OK(status)) {
3926 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
3927 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3928 talloc_free(tmp_ctx);
3929 return ldb_operr(ldb);
3932 if (!dom_sid_equal(sid, &sid2)) {
3933 /* someone is trying to spoof another account */
3934 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
3935 GUID_string(tmp_ctx, dsa_guid),
3936 dom_sid_string(tmp_ctx, sid),
3937 dom_sid_string(tmp_ctx, &sid2)));
3938 talloc_free(tmp_ctx);
3939 return ldb_operr(ldb);
3942 talloc_free(tmp_ctx);
3946 static const char *secret_attributes[] = {
3949 "initialAuthIncoming",
3950 "initialAuthOutgoing",
3954 "supplementalCredentials",
3955 "trustAuthIncoming",
3956 "trustAuthOutgoing",
3962 check if the attribute belongs to the RODC filtered attribute set
3963 Note that attributes that are in the filtered attribute set are the
3964 ones that _are_ always sent to a RODC
3966 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
3968 /* they never get secret attributes */
3969 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
3973 /* they do get non-secret critical attributes */
3974 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
3978 /* they do get non-secret attributes marked as being in the FAS */
3979 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
3983 /* other attributes are denied */
3987 /* return fsmo role dn and role owner dn for a particular role*/
3988 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
3989 struct ldb_context *ldb,
3991 struct ldb_dn **fsmo_role_dn,
3992 struct ldb_dn **role_owner_dn)
3996 case DREPL_NAMING_MASTER:
3997 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
3998 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
3999 if (ret != LDB_SUCCESS) {
4000 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4001 ldb_errstring(ldb)));
4002 talloc_free(tmp_ctx);
4003 return WERR_DS_DRA_INTERNAL_ERROR;
4006 case DREPL_INFRASTRUCTURE_MASTER:
4007 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4008 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4009 if (ret != LDB_SUCCESS) {
4010 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4011 ldb_errstring(ldb)));
4012 talloc_free(tmp_ctx);
4013 return WERR_DS_DRA_INTERNAL_ERROR;
4016 case DREPL_RID_MASTER:
4017 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4018 if (ret != LDB_SUCCESS) {
4019 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4020 talloc_free(tmp_ctx);
4021 return WERR_DS_DRA_INTERNAL_ERROR;
4024 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4025 if (ret != LDB_SUCCESS) {
4026 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4027 ldb_errstring(ldb)));
4028 talloc_free(tmp_ctx);
4029 return WERR_DS_DRA_INTERNAL_ERROR;
4032 case DREPL_SCHEMA_MASTER:
4033 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4034 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4035 if (ret != LDB_SUCCESS) {
4036 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4037 ldb_errstring(ldb)));
4038 talloc_free(tmp_ctx);
4039 return WERR_DS_DRA_INTERNAL_ERROR;
4042 case DREPL_PDC_MASTER:
4043 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4044 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4045 if (ret != LDB_SUCCESS) {
4046 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4047 ldb_errstring(ldb)));
4048 talloc_free(tmp_ctx);
4049 return WERR_DS_DRA_INTERNAL_ERROR;
4053 return WERR_DS_DRA_INTERNAL_ERROR;