2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "events/events.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "lib/util/tsort.h"
43 #include "dsdb/common/util.h"
44 #include "lib/socket/socket.h"
45 #include "dsdb/samdb/ldb_modules/util.h"
46 #include "librpc/gen_ndr/irpc.h"
49 search the sam for the specified attributes in a specific domain, filter on
50 objectSid being in domain_sid.
52 int samdb_search_domain(struct ldb_context *sam_ldb,
54 struct ldb_dn *basedn,
55 struct ldb_message ***res,
56 const char * const *attrs,
57 const struct dom_sid *domain_sid,
58 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
64 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
65 res, attrs, format, ap);
71 struct dom_sid *entry_sid;
73 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
75 if ((entry_sid == NULL) ||
76 (!dom_sid_in_domain(domain_sid, entry_sid))) {
77 /* Delete that entry from the result set */
78 (*res)[i] = (*res)[count-1];
80 talloc_free(entry_sid);
83 talloc_free(entry_sid);
91 search the sam for a single string attribute in exactly 1 record
93 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
95 struct ldb_dn *basedn,
96 const char *attr_name,
97 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
100 const char *attrs[2] = { NULL, NULL };
101 struct ldb_message **res = NULL;
103 attrs[0] = attr_name;
105 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
107 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
108 attr_name, format, count));
115 return samdb_result_string(res[0], attr_name, NULL);
119 search the sam for a single string attribute in exactly 1 record
121 const char *samdb_search_string(struct ldb_context *sam_ldb,
123 struct ldb_dn *basedn,
124 const char *attr_name,
125 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
130 va_start(ap, format);
131 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
137 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
139 struct ldb_dn *basedn,
140 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
144 struct ldb_message **res = NULL;
147 va_start(ap, format);
148 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
151 if (count != 1) return NULL;
153 ret = talloc_steal(mem_ctx, res[0]->dn);
160 search the sam for a dom_sid attribute in exactly 1 record
162 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
164 struct ldb_dn *basedn,
165 const char *attr_name,
166 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
170 struct ldb_message **res;
171 const char *attrs[2] = { NULL, NULL };
174 attrs[0] = attr_name;
176 va_start(ap, format);
177 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
180 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
181 attr_name, format, count));
187 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
193 return the count of the number of records in the sam matching the query
195 int samdb_search_count(struct ldb_context *sam_ldb,
196 struct ldb_dn *basedn,
197 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
200 struct ldb_message **res;
201 const char *attrs[] = { NULL };
203 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
205 va_start(ap, format);
206 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
208 talloc_free(tmp_ctx);
215 search the sam for a single integer attribute in exactly 1 record
217 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
219 unsigned int default_value,
220 struct ldb_dn *basedn,
221 const char *attr_name,
222 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
226 struct ldb_message **res;
227 const char *attrs[2] = { NULL, NULL };
229 attrs[0] = attr_name;
231 va_start(ap, format);
232 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
236 return default_value;
239 return samdb_result_uint(res[0], attr_name, default_value);
243 search the sam for a single signed 64 bit integer attribute in exactly 1 record
245 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
247 int64_t default_value,
248 struct ldb_dn *basedn,
249 const char *attr_name,
250 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
254 struct ldb_message **res;
255 const char *attrs[2] = { NULL, NULL };
257 attrs[0] = attr_name;
259 va_start(ap, format);
260 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
264 return default_value;
267 return samdb_result_int64(res[0], attr_name, default_value);
271 search the sam for multipe records each giving a single string attribute
272 return the number of matches, or -1 on error
274 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
276 struct ldb_dn *basedn,
278 const char *attr_name,
279 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
283 const char *attrs[2] = { NULL, NULL };
284 struct ldb_message **res = NULL;
286 attrs[0] = attr_name;
288 va_start(ap, format);
289 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
296 /* make sure its single valued */
297 for (i=0;i<count;i++) {
298 if (res[i]->num_elements != 1) {
299 DEBUG(1,("samdb: search for %s %s not single valued\n",
306 *strs = talloc_array(mem_ctx, const char *, count+1);
312 for (i=0;i<count;i++) {
313 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
315 (*strs)[count] = NULL;
321 pull a uint from a result set.
323 unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
325 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
329 pull a (signed) int64 from a result set.
331 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
333 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
337 pull a string from a result set.
339 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
340 const char *default_value)
342 return ldb_msg_find_attr_as_string(msg, attr, default_value);
345 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
346 const char *attr, struct ldb_dn *default_value)
348 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
350 return default_value;
356 pull a rid from a objectSid in a result set.
358 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
359 const char *attr, uint32_t default_value)
364 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
366 return default_value;
368 rid = sid->sub_auths[sid->num_auths-1];
374 pull a dom_sid structure from a objectSid in a result set.
376 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
379 const struct ldb_val *v;
381 enum ndr_err_code ndr_err;
382 v = ldb_msg_find_ldb_val(msg, attr);
386 sid = talloc(mem_ctx, struct dom_sid);
390 ndr_err = ndr_pull_struct_blob(v, sid, sid,
391 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
400 pull a guid structure from a objectGUID in a result set.
402 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
404 const struct ldb_val *v;
408 v = ldb_msg_find_ldb_val(msg, attr);
409 if (!v) return GUID_zero();
411 status = GUID_from_ndr_blob(v, &guid);
412 if (!NT_STATUS_IS_OK(status)) {
420 pull a sid prefix from a objectSid in a result set.
421 this is used to find the domain sid for a user
423 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
426 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
427 if (!sid || sid->num_auths < 1) return NULL;
433 pull a NTTIME in a result set.
435 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
436 NTTIME default_value)
438 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
442 * Windows stores 0 for lastLogoff.
443 * But when a MS DC return the lastLogoff (as Logoff Time)
444 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
445 * cause windows 2008 and newer version to fail for SMB requests
447 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
449 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
452 ret = 0x7FFFFFFFFFFFFFFFULL;
458 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
459 * indicate an account doesn't expire.
461 * When Windows initially creates an account, it sets
462 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
463 * when changing from an account having a specific expiration date to
464 * that account never expiring, it sets accountExpires = 0.
466 * Consolidate that logic here to allow clearer logic for account expiry in
467 * the rest of the code.
469 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
471 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
475 ret = 0x7FFFFFFFFFFFFFFFULL;
481 pull a uint64_t from a result set.
483 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
484 uint64_t default_value)
486 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
491 construct the allow_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
496 struct ldb_dn *domain_dn,
497 struct ldb_message *msg,
500 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
503 if (attr_time == 0) {
507 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
509 /* yes, this is a -= not a += as minPwdAge is stored as the negative
510 of the number of 100-nano-seconds */
511 attr_time -= minPwdAge;
517 construct the force_password_change field from the PwdLastSet
518 attribute, the userAccountControl and the domain password settings
520 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
522 struct ldb_dn *domain_dn,
523 struct ldb_message *msg)
525 int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
526 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
527 "userAccountControl",
531 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
532 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
533 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
534 return 0x7FFFFFFFFFFFFFFFULL;
537 if (attr_time == 0) {
540 if (attr_time == -1) {
541 return 0x7FFFFFFFFFFFFFFFULL;
544 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
546 if (maxPwdAge == 0) {
547 return 0x7FFFFFFFFFFFFFFFULL;
549 attr_time -= maxPwdAge;
556 pull a samr_Password structutre from a result set.
558 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
560 struct samr_Password *hash = NULL;
561 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
562 if (val && (val->length >= sizeof(hash->hash))) {
563 hash = talloc(mem_ctx, struct samr_Password);
564 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
570 pull an array of samr_Password structures from a result set.
572 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
573 const char *attr, struct samr_Password **hashes)
575 unsigned int count, i;
576 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
582 count = val->length / 16;
587 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
592 for (i=0;i<count;i++) {
593 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
599 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
600 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
602 struct samr_Password *lmPwdHash, *ntPwdHash;
605 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
608 } else if (num_nt > 1) {
609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
611 *nt_pwd = &ntPwdHash[0];
615 /* Ensure that if we have turned off LM
616 * authentication, that we never use the LM hash, even
618 if (lpcfg_lanman_auth(lp_ctx)) {
620 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
623 } else if (num_lm > 1) {
624 return NT_STATUS_INTERNAL_DB_CORRUPTION;
626 *lm_pwd = &lmPwdHash[0];
636 pull a samr_LogonHours structutre from a result set.
638 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
640 struct samr_LogonHours hours;
641 size_t units_per_week = 168;
642 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
647 units_per_week = val->length * 8;
650 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
654 hours.units_per_week = units_per_week;
655 memset(hours.bits, 0xFF, units_per_week/8);
657 memcpy(hours.bits, val->data, val->length);
664 pull a set of account_flags from a result set.
666 This requires that the attributes:
671 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
672 struct ldb_message *msg, struct ldb_dn *domain_dn)
674 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
675 uint32_t acct_flags = ds_uf2acb(userAccountControl);
676 NTTIME must_change_time;
679 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
682 /* Test account expire time */
683 unix_to_nt_time(&now, time(NULL));
684 /* check for expired password */
685 if (must_change_time < now) {
686 acct_flags |= ACB_PW_EXPIRED;
691 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
692 struct ldb_message *msg,
695 struct lsa_BinaryString s;
696 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
704 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
708 s.length = s.size = val->length;
709 memcpy(s.array, val->data, val->length);
714 /* Find an attribute, with a particular value */
716 /* The current callers of this function expect a very specific
717 * behaviour: In particular, objectClass subclass equivilance is not
718 * wanted. This means that we should not lookup the schema for the
719 * comparison function */
720 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
721 const struct ldb_message *msg,
722 const char *name, const char *value)
725 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
731 for (i=0;i<el->num_values;i++) {
732 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
741 * This is intended for use by the "password hash" module since there
742 * password changes can be specified through one message element with the
743 * new password (to set) and another one with the old password (to unset).
745 * The first which sets a password (new value) can have flags
746 * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
747 * for entries). The latter (old value) has always specified
748 * LDB_FLAG_MOD_DELETE.
750 * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
751 * doesn't contain only one value (this is the Windows Server behaviour)
752 * otherwise LDB_SUCCESS.
754 int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg,
756 const struct ldb_val **new_val,
757 const struct ldb_val **old_val)
768 for (i = 0; i < msg->num_elements; i++) {
769 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
770 if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) {
771 *old_val = &msg->elements[i].values[0];
773 *new_val = &msg->elements[i].values[0];
781 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
783 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
784 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
789 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
791 struct ldb_message_element *el;
793 el = ldb_msg_find_element(msg, name);
798 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
804 add a string element to a message
806 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
807 const char *attr_name, const char *str)
809 char *s = talloc_strdup(mem_ctx, str);
810 char *a = talloc_strdup(mem_ctx, attr_name);
811 if (s == NULL || a == NULL) {
812 return ldb_oom(sam_ldb);
814 return ldb_msg_add_string(msg, a, s);
818 add a dom_sid element to a message
820 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, struct dom_sid *sid)
824 enum ndr_err_code ndr_err;
826 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
828 (ndr_push_flags_fn_t)ndr_push_dom_sid);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 return ldb_operr(sam_ldb);
832 return ldb_msg_add_value(msg, attr_name, &v, NULL);
837 add a delete element operation to a message
839 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name)
842 /* we use an empty replace rather than a delete, as it allows for
843 dsdb_replace() to be used everywhere */
844 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
848 add an add attribute value to a message or enhance an existing attribute
849 which has the same name and the add flag set.
851 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
852 struct ldb_message *msg, const char *attr_name,
855 struct ldb_message_element *el;
856 struct ldb_val val, *vals;
862 v = talloc_strdup(mem_ctx, value);
864 return ldb_oom(sam_ldb);
867 val.data = (uint8_t *) v;
868 val.length = strlen(v);
870 if (val.length == 0) {
871 /* allow empty strings as non-existent attributes */
875 for (i = 0; i < msg->num_elements; i++) {
876 el = &msg->elements[i];
877 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
878 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
884 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
886 if (ret != LDB_SUCCESS) {
891 vals = talloc_realloc(msg, el->values, struct ldb_val,
894 return ldb_oom(sam_ldb);
897 el->values[el->num_values] = val;
904 add a delete attribute value to a message or enhance an existing attribute
905 which has the same name and the delete flag set.
907 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
908 struct ldb_message *msg, const char *attr_name,
911 struct ldb_message_element *el;
912 struct ldb_val val, *vals;
918 v = talloc_strdup(mem_ctx, value);
920 return ldb_oom(sam_ldb);
923 val.data = (uint8_t *) v;
924 val.length = strlen(v);
926 if (val.length == 0) {
927 /* allow empty strings as non-existent attributes */
931 for (i = 0; i < msg->num_elements; i++) {
932 el = &msg->elements[i];
933 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
934 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
940 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
942 if (ret != LDB_SUCCESS) {
947 vals = talloc_realloc(msg, el->values, struct ldb_val,
950 return ldb_oom(sam_ldb);
953 el->values[el->num_values] = val;
960 add a int element to a message
962 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, int v)
965 const char *s = talloc_asprintf(mem_ctx, "%d", v);
966 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
970 add a unsigned int element to a message
972 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
973 const char *attr_name, unsigned int v)
975 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
979 add a (signed) int64_t element to a message
981 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
982 const char *attr_name, int64_t v)
984 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
985 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
989 add a uint64_t element to a message
991 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992 const char *attr_name, uint64_t v)
994 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
998 add a samr_Password element to a message
1000 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001 const char *attr_name, const struct samr_Password *hash)
1004 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1006 return ldb_oom(sam_ldb);
1009 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1013 add a samr_Password array to a message
1015 int samdb_msg_add_hashes(struct ldb_context *ldb,
1016 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1017 const char *attr_name, struct samr_Password *hashes,
1022 val.data = talloc_array_size(mem_ctx, 16, count);
1023 val.length = count*16;
1025 return ldb_oom(ldb);
1027 for (i=0;i<count;i++) {
1028 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1030 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1034 add a acct_flags element to a message
1036 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037 const char *attr_name, uint32_t v)
1039 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1043 add a logon_hours element to a message
1045 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1046 const char *attr_name, struct samr_LogonHours *hours)
1049 val.length = hours->units_per_week / 8;
1050 val.data = hours->bits;
1051 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1055 add a parameters element to a message
1057 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1058 const char *attr_name, struct lsa_BinaryString *parameters)
1061 val.length = parameters->length;
1062 val.data = (uint8_t *)parameters->array;
1063 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1066 add a general value element to a message
1068 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1069 const char *attr_name, const struct ldb_val *val)
1071 return ldb_msg_add_value(msg, attr_name, val, NULL);
1075 sets a general value element to a message
1077 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1078 const char *attr_name, const struct ldb_val *val)
1080 struct ldb_message_element *el;
1082 el = ldb_msg_find_element(msg, attr_name);
1086 return ldb_msg_add_value(msg, attr_name, val, NULL);
1090 set a string element in a message
1092 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1093 const char *attr_name, const char *str)
1095 struct ldb_message_element *el;
1097 el = ldb_msg_find_element(msg, attr_name);
1101 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1105 * Handle ldb_request in transaction
1107 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1108 struct ldb_request *req)
1112 ret = ldb_transaction_start(sam_ldb);
1113 if (ret != LDB_SUCCESS) {
1117 ret = ldb_request(sam_ldb, req);
1118 if (ret == LDB_SUCCESS) {
1119 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1122 if (ret == LDB_SUCCESS) {
1123 return ldb_transaction_commit(sam_ldb);
1125 ldb_transaction_cancel(sam_ldb);
1131 return a default security descriptor
1133 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1135 struct security_descriptor *sd;
1137 sd = security_descriptor_initialise(mem_ctx);
1142 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1144 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1145 struct ldb_dn *aggregate_dn;
1150 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1151 if (!aggregate_dn) {
1154 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1157 return aggregate_dn;
1160 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1162 struct ldb_dn *new_dn;
1164 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1165 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1166 talloc_free(new_dn);
1172 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1174 struct ldb_dn *new_dn;
1176 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1177 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1178 talloc_free(new_dn);
1184 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1186 struct ldb_dn *new_dn;
1188 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1189 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1190 talloc_free(new_dn);
1197 work out the domain sid for the current open ldb
1199 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1201 TALLOC_CTX *tmp_ctx;
1202 const struct dom_sid *domain_sid;
1203 const char *attrs[] = {
1207 struct ldb_result *res;
1210 /* see if we have a cached copy */
1211 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1216 tmp_ctx = talloc_new(ldb);
1217 if (tmp_ctx == NULL) {
1221 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1223 if (ret != LDB_SUCCESS) {
1227 if (res->count != 1) {
1231 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1232 if (domain_sid == NULL) {
1236 /* cache the domain_sid in the ldb */
1237 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1241 talloc_steal(ldb, domain_sid);
1242 talloc_free(tmp_ctx);
1247 talloc_free(tmp_ctx);
1252 get domain sid from cache
1254 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1256 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1259 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1261 TALLOC_CTX *tmp_ctx;
1262 struct dom_sid *dom_sid_new;
1263 struct dom_sid *dom_sid_old;
1265 /* see if we have a cached copy */
1266 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1267 "cache.domain_sid"), struct dom_sid);
1269 tmp_ctx = talloc_new(ldb);
1270 if (tmp_ctx == NULL) {
1274 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1279 /* cache the domain_sid in the ldb */
1280 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1284 talloc_steal(ldb, dom_sid_new);
1285 talloc_free(tmp_ctx);
1286 talloc_free(dom_sid_old);
1291 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1292 talloc_free(tmp_ctx);
1296 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1298 TALLOC_CTX *tmp_ctx;
1299 struct ldb_dn *ntds_settings_dn_new;
1300 struct ldb_dn *ntds_settings_dn_old;
1302 /* see if we have a cached copy */
1303 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1304 "cache.ntds_settings_dn"), struct ldb_dn);
1306 tmp_ctx = talloc_new(ldb);
1307 if (tmp_ctx == NULL) {
1311 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1312 if (!ntds_settings_dn_new) {
1316 /* cache the domain_sid in the ldb */
1317 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1321 talloc_steal(ldb, ntds_settings_dn_new);
1322 talloc_free(tmp_ctx);
1323 talloc_free(ntds_settings_dn_old);
1328 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1329 talloc_free(tmp_ctx);
1333 /* Obtain the short name of the flexible single master operator
1334 * (FSMO), such as the PDC Emulator */
1335 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1338 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1339 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1340 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1341 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1343 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1344 /* Ensure this matches the format. This gives us a
1345 * bit more confidence that a 'cn' value will be a
1350 return (char *)val->data;
1356 work out the ntds settings dn for the current open ldb
1358 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1360 TALLOC_CTX *tmp_ctx;
1361 const char *root_attrs[] = { "dsServiceName", NULL };
1363 struct ldb_result *root_res;
1364 struct ldb_dn *settings_dn;
1366 /* see if we have a cached copy */
1367 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
1372 tmp_ctx = talloc_new(ldb);
1373 if (tmp_ctx == NULL) {
1377 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1379 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1380 ldb_errstring(ldb)));
1384 if (root_res->count != 1) {
1388 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1390 /* cache the domain_sid in the ldb */
1391 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1395 talloc_steal(ldb, settings_dn);
1396 talloc_free(tmp_ctx);
1401 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1402 talloc_free(tmp_ctx);
1407 work out the ntds settings invocationId for the current open ldb
1409 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1411 TALLOC_CTX *tmp_ctx;
1412 const char *attrs[] = { "invocationId", NULL };
1414 struct ldb_result *res;
1415 struct GUID *invocation_id;
1417 /* see if we have a cached copy */
1418 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1419 if (invocation_id) {
1420 return invocation_id;
1423 tmp_ctx = talloc_new(ldb);
1424 if (tmp_ctx == NULL) {
1428 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1433 if (res->count != 1) {
1437 invocation_id = talloc(tmp_ctx, struct GUID);
1438 if (!invocation_id) {
1442 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1444 /* cache the domain_sid in the ldb */
1445 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1449 talloc_steal(ldb, invocation_id);
1450 talloc_free(tmp_ctx);
1452 return invocation_id;
1455 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1456 talloc_free(tmp_ctx);
1460 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1462 TALLOC_CTX *tmp_ctx;
1463 struct GUID *invocation_id_new;
1464 struct GUID *invocation_id_old;
1466 /* see if we have a cached copy */
1467 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1468 "cache.invocation_id");
1470 tmp_ctx = talloc_new(ldb);
1471 if (tmp_ctx == NULL) {
1475 invocation_id_new = talloc(tmp_ctx, struct GUID);
1476 if (!invocation_id_new) {
1480 *invocation_id_new = *invocation_id_in;
1482 /* cache the domain_sid in the ldb */
1483 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1487 talloc_steal(ldb, invocation_id_new);
1488 talloc_free(tmp_ctx);
1489 talloc_free(invocation_id_old);
1494 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1495 talloc_free(tmp_ctx);
1500 work out the ntds settings objectGUID for the current open ldb
1502 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1504 TALLOC_CTX *tmp_ctx;
1505 const char *attrs[] = { "objectGUID", NULL };
1507 struct ldb_result *res;
1508 struct GUID *ntds_guid;
1510 /* see if we have a cached copy */
1511 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1516 tmp_ctx = talloc_new(ldb);
1517 if (tmp_ctx == NULL) {
1521 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1526 if (res->count != 1) {
1530 ntds_guid = talloc(tmp_ctx, struct GUID);
1535 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1537 /* cache the domain_sid in the ldb */
1538 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1542 talloc_steal(ldb, ntds_guid);
1543 talloc_free(tmp_ctx);
1548 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1549 talloc_free(tmp_ctx);
1553 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1555 TALLOC_CTX *tmp_ctx;
1556 struct GUID *ntds_guid_new;
1557 struct GUID *ntds_guid_old;
1559 /* see if we have a cached copy */
1560 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1562 tmp_ctx = talloc_new(ldb);
1563 if (tmp_ctx == NULL) {
1567 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1568 if (!ntds_guid_new) {
1572 *ntds_guid_new = *ntds_guid_in;
1574 /* cache the domain_sid in the ldb */
1575 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1579 talloc_steal(ldb, ntds_guid_new);
1580 talloc_free(tmp_ctx);
1581 talloc_free(ntds_guid_old);
1586 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1587 talloc_free(tmp_ctx);
1592 work out the server dn for the current open ldb
1594 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1596 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1600 work out the server dn for the current open ldb
1602 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1604 struct ldb_dn *server_dn;
1605 struct ldb_dn *servers_dn;
1606 struct ldb_dn *server_site_dn;
1608 /* TODO: there must be a saner way to do this!! */
1609 server_dn = samdb_server_dn(ldb, mem_ctx);
1610 if (!server_dn) return NULL;
1612 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1613 talloc_free(server_dn);
1614 if (!servers_dn) return NULL;
1616 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1617 talloc_free(servers_dn);
1619 return server_site_dn;
1623 find the site name from a computers DN record
1625 int samdb_find_site_for_computer(struct ldb_context *ldb,
1626 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1627 const char **site_name)
1631 const struct ldb_val *rdn_val;
1635 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1636 if (ret != LDB_SUCCESS) {
1640 if (!ldb_dn_remove_child_components(dn, 2)) {
1642 return LDB_ERR_INVALID_DN_SYNTAX;
1644 rdn_val = ldb_dn_get_rdn_val(dn);
1645 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1648 return LDB_ERR_OPERATIONS_ERROR;
1654 find the NTDS GUID from a computers DN record
1656 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1657 struct GUID *ntds_guid)
1662 *ntds_guid = GUID_zero();
1664 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1665 if (ret != LDB_SUCCESS) {
1669 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1671 return LDB_ERR_OPERATIONS_ERROR;
1674 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1680 find a 'reference' DN that points at another object
1681 (eg. serverReference, rIDManagerReference etc)
1683 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1684 const char *attribute, struct ldb_dn **dn)
1686 const char *attrs[2];
1687 struct ldb_result *res;
1690 attrs[0] = attribute;
1693 ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
1694 if (ret != LDB_SUCCESS) {
1697 if (res->count != 1) {
1699 return LDB_ERR_NO_SUCH_OBJECT;
1702 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1705 ldb_asprintf_errstring(ldb, "Cannot find dn of attribute %s of %s", attribute,
1706 ldb_dn_get_linearized(base));
1707 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1715 find our machine account via the serverReference attribute in the
1718 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1720 struct ldb_dn *server_dn;
1723 server_dn = samdb_server_dn(ldb, mem_ctx);
1724 if (server_dn == NULL) {
1725 return LDB_ERR_NO_SUCH_OBJECT;
1728 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1729 talloc_free(server_dn);
1735 find the RID Manager$ DN via the rIDManagerReference attribute in the
1738 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1740 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1741 "rIDManagerReference", dn);
1745 find the RID Set DN via the rIDSetReferences attribute in our
1748 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1750 struct ldb_dn *server_ref_dn;
1753 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1754 if (ret != LDB_SUCCESS) {
1757 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1758 talloc_free(server_ref_dn);
1762 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1764 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1771 return (const char *) val->data;
1775 * Finds the client site by using the client's IP address.
1776 * The "subnet_name" returns the name of the subnet if parameter != NULL
1778 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1779 const char *ip_address, char **subnet_name)
1781 const char *attrs[] = { "cn", "siteObject", NULL };
1782 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1783 struct ldb_result *res;
1784 const struct ldb_val *val;
1785 const char *site_name = NULL, *l_subnet_name = NULL;
1786 const char *allow_list[2] = { NULL, NULL };
1787 unsigned int i, count;
1791 * if we don't have a client ip e.g. ncalrpc
1792 * the server site is the client site
1794 if (ip_address == NULL) {
1795 return samdb_server_site_name(ldb, mem_ctx);
1798 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1799 if (sites_container_dn == NULL) {
1803 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1804 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1805 talloc_free(sites_container_dn);
1806 talloc_free(subnets_dn);
1810 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1812 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1814 } else if (ret != LDB_SUCCESS) {
1815 talloc_free(sites_container_dn);
1816 talloc_free(subnets_dn);
1822 for (i = 0; i < count; i++) {
1823 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1826 allow_list[0] = l_subnet_name;
1828 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
1829 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1832 if (sites_dn == NULL) {
1833 /* No reference, maybe another subnet matches */
1837 /* "val" cannot be NULL here since "sites_dn" != NULL */
1838 val = ldb_dn_get_rdn_val(sites_dn);
1839 site_name = talloc_strdup(mem_ctx,
1840 (const char *) val->data);
1842 talloc_free(sites_dn);
1848 if (site_name == NULL) {
1849 /* This is the Windows Server fallback rule: when no subnet
1850 * exists and we have only one site available then use it (it
1851 * is for sure the same as our server site). If more sites do
1852 * exist then we don't know which one to use and set the site
1854 cnt = samdb_search_count(ldb, sites_container_dn,
1855 "(objectClass=site)");
1857 site_name = samdb_server_site_name(ldb, mem_ctx);
1859 site_name = talloc_strdup(mem_ctx, "");
1861 l_subnet_name = NULL;
1864 if (subnet_name != NULL) {
1865 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1868 talloc_free(sites_container_dn);
1869 talloc_free(subnets_dn);
1876 work out if we are the PDC for the domain of the current open ldb
1878 bool samdb_is_pdc(struct ldb_context *ldb)
1880 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1882 struct ldb_result *dom_res;
1883 TALLOC_CTX *tmp_ctx;
1887 tmp_ctx = talloc_new(ldb);
1888 if (tmp_ctx == NULL) {
1889 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1893 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1894 if (ret != LDB_SUCCESS) {
1895 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1896 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1897 ldb_errstring(ldb)));
1900 if (dom_res->count != 1) {
1904 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1906 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1912 talloc_free(tmp_ctx);
1917 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1918 talloc_free(tmp_ctx);
1923 work out if we are a Global Catalog server for the domain of the current open ldb
1925 bool samdb_is_gc(struct ldb_context *ldb)
1927 const char *attrs[] = { "options", NULL };
1929 struct ldb_result *res;
1930 TALLOC_CTX *tmp_ctx;
1932 tmp_ctx = talloc_new(ldb);
1933 if (tmp_ctx == NULL) {
1934 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1938 /* Query cn=ntds settings,.... */
1939 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1940 if (ret != LDB_SUCCESS) {
1941 talloc_free(tmp_ctx);
1944 if (res->count != 1) {
1945 talloc_free(tmp_ctx);
1949 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1950 talloc_free(tmp_ctx);
1952 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1953 if (options & 0x000000001) {
1959 /* Find a domain object in the parents of a particular DN. */
1960 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1961 struct ldb_dn **parent_dn, const char **errstring)
1963 TALLOC_CTX *local_ctx;
1964 struct ldb_dn *sdn = dn;
1965 struct ldb_result *res = NULL;
1966 int ret = LDB_SUCCESS;
1967 const char *attrs[] = { NULL };
1969 local_ctx = talloc_new(mem_ctx);
1970 if (local_ctx == NULL) return ldb_oom(ldb);
1972 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1973 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1974 "(|(objectClass=domain)(objectClass=builtinDomain))");
1975 if (ret == LDB_SUCCESS) {
1976 if (res->count == 1) {
1984 if (ret != LDB_SUCCESS) {
1985 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1986 ldb_dn_get_linearized(dn),
1987 ldb_dn_get_linearized(sdn),
1988 ldb_errstring(ldb));
1989 talloc_free(local_ctx);
1992 if (res->count != 1) {
1993 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1994 ldb_dn_get_linearized(dn));
1995 DEBUG(0,(__location__ ": %s\n", *errstring));
1996 talloc_free(local_ctx);
1997 return LDB_ERR_CONSTRAINT_VIOLATION;
2000 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2001 talloc_free(local_ctx);
2007 * Performs checks on a user password (plaintext UNIX format - attribute
2008 * "password"). The remaining parameters have to be extracted from the domain
2011 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2013 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
2014 const uint32_t pwdProperties,
2015 const uint32_t minPwdLength)
2017 /* checks if the "minPwdLength" property is satisfied */
2018 if (minPwdLength > password->length)
2019 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2021 /* checks the password complexity */
2022 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
2023 && (password->data != NULL)
2024 && (!check_password_quality((const char *) password->data)))
2025 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2027 return SAMR_VALIDATION_STATUS_SUCCESS;
2031 * Callback for "samdb_set_password" password change
2033 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2038 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2041 if (ares->error != LDB_SUCCESS) {
2043 req->context = talloc_steal(req,
2044 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2046 return ldb_request_done(req, ret);
2049 if (ares->type != LDB_REPLY_DONE) {
2051 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2054 req->context = talloc_steal(req,
2055 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2057 return ldb_request_done(req, LDB_SUCCESS);
2061 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2062 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2063 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2064 * user change or not. The "rejectReason" gives some more informations if the
2067 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2068 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2070 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2071 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2072 const DATA_BLOB *new_password,
2073 const struct samr_Password *lmNewHash,
2074 const struct samr_Password *ntNewHash,
2075 const struct samr_Password *lmOldHash,
2076 const struct samr_Password *ntOldHash,
2077 enum samPwdChangeReason *reject_reason,
2078 struct samr_DomInfo1 **_dominfo)
2080 struct ldb_message *msg;
2081 struct ldb_message_element *el;
2082 struct ldb_request *req;
2083 struct dsdb_control_password_change_status *pwd_stat = NULL;
2085 NTSTATUS status = NT_STATUS_OK;
2087 #define CHECK_RET(x) \
2088 if (x != LDB_SUCCESS) { \
2090 return NT_STATUS_NO_MEMORY; \
2093 msg = ldb_msg_new(mem_ctx);
2095 return NT_STATUS_NO_MEMORY;
2098 if ((new_password != NULL)
2099 && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2100 /* we have the password as plaintext UTF16 */
2101 CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
2102 "clearTextPassword", new_password));
2103 el = ldb_msg_find_element(msg, "clearTextPassword");
2104 el->flags = LDB_FLAG_MOD_REPLACE;
2105 } else if ((new_password == NULL)
2106 && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2107 /* we have a password as LM and/or NT hash */
2108 if (lmNewHash != NULL) {
2109 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2110 "dBCSPwd", lmNewHash));
2111 el = ldb_msg_find_element(msg, "dBCSPwd");
2112 el->flags = LDB_FLAG_MOD_REPLACE;
2114 if (ntNewHash != NULL) {
2115 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2116 "unicodePwd", ntNewHash));
2117 el = ldb_msg_find_element(msg, "unicodePwd");
2118 el->flags = LDB_FLAG_MOD_REPLACE;
2121 /* the password wasn't specified correctly */
2123 return NT_STATUS_INVALID_PARAMETER;
2126 /* build modify request */
2127 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2128 samdb_set_password_callback, NULL);
2129 if (ret != LDB_SUCCESS) {
2131 return NT_STATUS_NO_MEMORY;
2134 /* A password change operation */
2135 if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2136 struct dsdb_control_password_change *change;
2138 change = talloc(req, struct dsdb_control_password_change);
2139 if (change == NULL) {
2142 return NT_STATUS_NO_MEMORY;
2145 change->old_nt_pwd_hash = ntOldHash;
2146 change->old_lm_pwd_hash = lmOldHash;
2148 ret = ldb_request_add_control(req,
2149 DSDB_CONTROL_PASSWORD_CHANGE_OID,
2151 if (ret != LDB_SUCCESS) {
2154 return NT_STATUS_NO_MEMORY;
2157 ret = ldb_request_add_control(req,
2158 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2160 if (ret != LDB_SUCCESS) {
2163 return NT_STATUS_NO_MEMORY;
2165 ret = ldb_request_add_control(req,
2166 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2168 if (ret != LDB_SUCCESS) {
2171 return NT_STATUS_NO_MEMORY;
2174 ret = dsdb_autotransaction_request(ldb, req);
2176 if (req->context != NULL) {
2177 pwd_stat = talloc_steal(mem_ctx,
2178 ((struct ldb_control *)req->context)->data);
2184 /* Sets the domain info (if requested) */
2185 if (_dominfo != NULL) {
2186 struct samr_DomInfo1 *dominfo;
2188 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2189 if (dominfo == NULL) {
2190 return NT_STATUS_NO_MEMORY;
2193 if (pwd_stat != NULL) {
2194 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2195 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2196 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2197 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2198 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2201 *_dominfo = dominfo;
2204 if (reject_reason != NULL) {
2205 if (pwd_stat != NULL) {
2206 *reject_reason = pwd_stat->reject_reason;
2208 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2212 if (pwd_stat != NULL) {
2213 talloc_free(pwd_stat);
2216 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2217 const char *errmsg = ldb_errstring(ldb);
2218 char *endptr = NULL;
2219 WERROR werr = WERR_GENERAL_FAILURE;
2220 status = NT_STATUS_UNSUCCESSFUL;
2221 if (errmsg != NULL) {
2222 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2224 if (endptr != errmsg) {
2225 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2226 status = NT_STATUS_WRONG_PASSWORD;
2228 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2229 status = NT_STATUS_PASSWORD_RESTRICTION;
2232 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2233 /* don't let the caller know if an account doesn't exist */
2234 status = NT_STATUS_WRONG_PASSWORD;
2235 } else if (ret != LDB_SUCCESS) {
2236 status = NT_STATUS_UNSUCCESSFUL;
2243 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2244 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2245 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2246 * user change or not. The "rejectReason" gives some more informations if the
2249 * This wrapper function for "samdb_set_password" takes a SID as input rather
2252 * This call encapsulates a new LDB transaction for changing the password;
2253 * therefore the user hasn't to start a new one.
2255 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2256 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2257 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2258 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2260 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2261 const struct dom_sid *user_sid,
2262 const DATA_BLOB *new_password,
2263 const struct samr_Password *lmNewHash,
2264 const struct samr_Password *ntNewHash,
2265 const struct samr_Password *lmOldHash,
2266 const struct samr_Password *ntOldHash,
2267 enum samPwdChangeReason *reject_reason,
2268 struct samr_DomInfo1 **_dominfo)
2271 struct ldb_dn *user_dn;
2274 ret = ldb_transaction_start(ldb);
2275 if (ret != LDB_SUCCESS) {
2276 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2277 return NT_STATUS_TRANSACTION_ABORTED;
2280 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2281 "(&(objectSid=%s)(objectClass=user))",
2282 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2284 ldb_transaction_cancel(ldb);
2285 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2286 dom_sid_string(mem_ctx, user_sid)));
2287 return NT_STATUS_NO_SUCH_USER;
2290 nt_status = samdb_set_password(ldb, mem_ctx,
2293 lmNewHash, ntNewHash,
2294 lmOldHash, ntOldHash,
2295 reject_reason, _dominfo);
2296 if (!NT_STATUS_IS_OK(nt_status)) {
2297 ldb_transaction_cancel(ldb);
2298 talloc_free(user_dn);
2302 ret = ldb_transaction_commit(ldb);
2303 if (ret != LDB_SUCCESS) {
2304 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2305 ldb_dn_get_linearized(user_dn),
2306 ldb_errstring(ldb)));
2307 talloc_free(user_dn);
2308 return NT_STATUS_TRANSACTION_ABORTED;
2311 talloc_free(user_dn);
2312 return NT_STATUS_OK;
2316 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2317 struct dom_sid *sid, struct ldb_dn **ret_dn)
2319 struct ldb_message *msg;
2320 struct ldb_dn *basedn;
2324 sidstr = dom_sid_string(mem_ctx, sid);
2325 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2327 /* We might have to create a ForeignSecurityPrincipal, even if this user
2328 * is in our own domain */
2330 msg = ldb_msg_new(sidstr);
2332 talloc_free(sidstr);
2333 return NT_STATUS_NO_MEMORY;
2336 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2337 ldb_get_default_basedn(sam_ctx),
2338 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2340 if (ret != LDB_SUCCESS) {
2341 DEBUG(0, ("Failed to find DN for "
2342 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2343 talloc_free(sidstr);
2344 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2347 /* add core elements to the ldb_message for the alias */
2349 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2350 talloc_free(sidstr);
2351 return NT_STATUS_NO_MEMORY;
2354 samdb_msg_add_string(sam_ctx, msg, msg,
2356 "foreignSecurityPrincipal");
2358 /* create the alias */
2359 ret = ldb_add(sam_ctx, msg);
2360 if (ret != LDB_SUCCESS) {
2361 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2363 ldb_dn_get_linearized(msg->dn),
2364 ldb_errstring(sam_ctx)));
2365 talloc_free(sidstr);
2366 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2369 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2370 talloc_free(sidstr);
2372 return NT_STATUS_OK;
2377 Find the DN of a domain, assuming it to be a dotted.dns name
2380 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2383 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2384 const char *binary_encoded;
2385 const char **split_realm;
2392 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2394 talloc_free(tmp_ctx);
2397 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2398 for (i=0; split_realm[i]; i++) {
2399 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2400 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2401 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2402 binary_encoded, ldb_dn_get_linearized(dn)));
2403 talloc_free(tmp_ctx);
2407 if (!ldb_dn_validate(dn)) {
2408 DEBUG(2, ("Failed to validated DN %s\n",
2409 ldb_dn_get_linearized(dn)));
2410 talloc_free(tmp_ctx);
2413 talloc_free(tmp_ctx);
2418 Find the DN of a domain, be it the netbios or DNS name
2420 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2421 const char *domain_name)
2423 const char * const domain_ref_attrs[] = {
2426 const char * const domain_ref2_attrs[] = {
2429 struct ldb_result *res_domain_ref;
2430 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2431 /* find the domain's DN */
2432 int ret_domain = ldb_search(ldb, mem_ctx,
2434 samdb_partitions_dn(ldb, mem_ctx),
2437 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2439 if (ret_domain != LDB_SUCCESS) {
2443 if (res_domain_ref->count == 0) {
2444 ret_domain = ldb_search(ldb, mem_ctx,
2446 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2449 "(objectclass=domain)");
2450 if (ret_domain != LDB_SUCCESS) {
2454 if (res_domain_ref->count == 1) {
2455 return res_domain_ref->msgs[0]->dn;
2460 if (res_domain_ref->count > 1) {
2461 DEBUG(0,("Found %d records matching domain [%s]\n",
2462 ret_domain, domain_name));
2466 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2472 use a GUID to find a DN
2474 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2475 TALLOC_CTX *mem_ctx,
2476 const struct GUID *guid, struct ldb_dn **dn)
2479 struct ldb_result *res;
2480 const char *attrs[] = { NULL };
2481 char *guid_str = GUID_string(mem_ctx, guid);
2484 return ldb_operr(ldb);
2487 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2488 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2489 DSDB_SEARCH_SHOW_EXTENDED_DN |
2490 DSDB_SEARCH_ONE_ONLY,
2491 "objectGUID=%s", guid_str);
2492 talloc_free(guid_str);
2493 if (ret != LDB_SUCCESS) {
2497 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2504 use a DN to find a GUID with a given attribute name
2506 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2507 struct ldb_dn *dn, const char *attribute,
2511 struct ldb_result *res;
2512 const char *attrs[2];
2513 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2515 attrs[0] = attribute;
2518 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2519 if (ret != LDB_SUCCESS) {
2520 talloc_free(tmp_ctx);
2523 if (res->count < 1) {
2524 talloc_free(tmp_ctx);
2525 return LDB_ERR_NO_SUCH_OBJECT;
2527 *guid = samdb_result_guid(res->msgs[0], attribute);
2528 talloc_free(tmp_ctx);
2533 use a DN to find a GUID
2535 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2536 struct ldb_dn *dn, struct GUID *guid)
2538 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2544 adds the given GUID to the given ldb_message. This value is added
2545 for the given attr_name (may be either "objectGUID" or "parentGUID").
2547 int dsdb_msg_add_guid(struct ldb_message *msg,
2549 const char *attr_name)
2554 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2556 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 ret = LDB_ERR_OPERATIONS_ERROR;
2562 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2563 if (ret != LDB_SUCCESS) {
2564 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2572 talloc_free(tmp_ctx);
2579 use a DN to find a SID
2581 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2582 struct ldb_dn *dn, struct dom_sid *sid)
2585 struct ldb_result *res;
2586 const char *attrs[] = { "objectSid", NULL };
2587 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2592 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
2593 if (ret != LDB_SUCCESS) {
2594 talloc_free(tmp_ctx);
2597 if (res->count < 1) {
2598 talloc_free(tmp_ctx);
2599 return LDB_ERR_NO_SUCH_OBJECT;
2601 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
2603 talloc_free(tmp_ctx);
2604 return LDB_ERR_NO_SUCH_OBJECT;
2607 talloc_free(tmp_ctx);
2612 use a SID to find a DN
2614 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
2615 TALLOC_CTX *mem_ctx,
2616 struct dom_sid *sid, struct ldb_dn **dn)
2619 struct ldb_result *res;
2620 const char *attrs[] = { NULL };
2621 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
2624 return ldb_operr(ldb);
2627 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
2628 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2629 DSDB_SEARCH_SHOW_EXTENDED_DN |
2630 DSDB_SEARCH_ONE_ONLY,
2631 "objectSid=%s", sid_str);
2632 talloc_free(sid_str);
2633 if (ret != LDB_SUCCESS) {
2637 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2644 load a repsFromTo blob list for a given partition GUID
2645 attr must be "repsFrom" or "repsTo"
2647 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2648 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2650 const char *attrs[] = { attr, NULL };
2651 struct ldb_result *res = NULL;
2652 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2654 struct ldb_message_element *el;
2659 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2661 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2662 talloc_free(tmp_ctx);
2663 return WERR_DS_DRA_INTERNAL_ERROR;
2666 el = ldb_msg_find_element(res->msgs[0], attr);
2668 /* it's OK to be empty */
2669 talloc_free(tmp_ctx);
2673 *count = el->num_values;
2674 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2676 talloc_free(tmp_ctx);
2677 return WERR_DS_DRA_INTERNAL_ERROR;
2680 for (i=0; i<(*count); i++) {
2681 enum ndr_err_code ndr_err;
2682 ndr_err = ndr_pull_struct_blob(&el->values[i],
2685 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2686 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2687 talloc_free(tmp_ctx);
2688 return WERR_DS_DRA_INTERNAL_ERROR;
2692 talloc_free(tmp_ctx);
2698 save the repsFromTo blob list for a given partition GUID
2699 attr must be "repsFrom" or "repsTo"
2701 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2702 const char *attr, struct repsFromToBlob *r, uint32_t count)
2704 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2705 struct ldb_message *msg;
2706 struct ldb_message_element *el;
2709 msg = ldb_msg_new(tmp_ctx);
2711 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2715 el->values = talloc_array(msg, struct ldb_val, count);
2720 for (i=0; i<count; i++) {
2722 enum ndr_err_code ndr_err;
2724 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
2726 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2735 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2736 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2740 talloc_free(tmp_ctx);
2745 talloc_free(tmp_ctx);
2746 return WERR_DS_DRA_INTERNAL_ERROR;
2751 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
2752 object for a partition
2754 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
2755 uint64_t *uSN, uint64_t *urgent_uSN)
2757 struct ldb_request *req;
2759 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2760 struct dsdb_control_current_partition *p_ctrl;
2761 struct ldb_result *res;
2763 res = talloc_zero(tmp_ctx, struct ldb_result);
2765 talloc_free(tmp_ctx);
2766 return ldb_oom(ldb);
2769 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2770 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2774 res, ldb_search_default_callback,
2776 if (ret != LDB_SUCCESS) {
2777 talloc_free(tmp_ctx);
2781 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2782 if (p_ctrl == NULL) {
2783 talloc_free(tmp_ctx);
2784 return ldb_oom(ldb);
2786 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2789 ret = ldb_request_add_control(req,
2790 DSDB_CONTROL_CURRENT_PARTITION_OID,
2792 if (ret != LDB_SUCCESS) {
2793 talloc_free(tmp_ctx);
2797 /* Run the new request */
2798 ret = ldb_request(ldb, req);
2800 if (ret == LDB_SUCCESS) {
2801 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2804 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2805 /* it hasn't been created yet, which means
2806 an implicit value of zero */
2808 talloc_free(tmp_ctx);
2812 if (ret != LDB_SUCCESS) {
2813 talloc_free(tmp_ctx);
2817 if (res->count < 1) {
2823 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2825 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
2829 talloc_free(tmp_ctx);
2834 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2835 const struct drsuapi_DsReplicaCursor2 *c2)
2837 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2840 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2841 const struct drsuapi_DsReplicaCursor *c2)
2843 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2848 see if a computer identified by its invocationId is a RODC
2850 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
2852 /* 1) find the DN for this servers NTDSDSA object
2853 2) search for the msDS-isRODC attribute
2854 3) if not present then not a RODC
2855 4) if present and TRUE then is a RODC
2857 struct ldb_dn *config_dn;
2858 const char *attrs[] = { "msDS-isRODC", NULL };
2860 struct ldb_result *res;
2861 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
2863 config_dn = ldb_get_config_basedn(sam_ctx);
2865 talloc_free(tmp_ctx);
2866 return ldb_operr(sam_ctx);
2869 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
2870 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
2872 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2874 talloc_free(tmp_ctx);
2878 if (ret != LDB_SUCCESS) {
2879 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
2880 GUID_string(tmp_ctx, objectGUID)));
2882 talloc_free(tmp_ctx);
2886 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
2887 *is_rodc = (ret == 1);
2889 talloc_free(tmp_ctx);
2895 see if we are a RODC
2897 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
2899 const struct GUID *objectGUID;
2903 /* see if we have a cached copy */
2904 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
2910 objectGUID = samdb_ntds_objectGUID(sam_ctx);
2912 return ldb_operr(sam_ctx);
2915 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
2916 if (ret != LDB_SUCCESS) {
2920 cached = talloc(sam_ctx, bool);
2921 if (cached == NULL) {
2922 return ldb_oom(sam_ctx);
2926 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
2927 if (ret != LDB_SUCCESS) {
2928 talloc_free(cached);
2929 return ldb_operr(sam_ctx);
2935 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
2937 TALLOC_CTX *tmp_ctx;
2940 tmp_ctx = talloc_new(ldb);
2941 if (tmp_ctx == NULL) {
2945 cached = talloc(tmp_ctx, bool);
2951 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
2955 talloc_steal(ldb, cached);
2956 talloc_free(tmp_ctx);
2960 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
2961 talloc_free(tmp_ctx);
2967 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2969 flags are DS_NTDS_OPTION_*
2971 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2973 TALLOC_CTX *tmp_ctx;
2974 const char *attrs[] = { "options", NULL };
2976 struct ldb_result *res;
2978 tmp_ctx = talloc_new(ldb);
2979 if (tmp_ctx == NULL) {
2983 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2984 if (ret != LDB_SUCCESS) {
2988 if (res->count != 1) {
2992 *options = samdb_result_uint(res->msgs[0], "options", 0);
2994 talloc_free(tmp_ctx);
2999 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3000 talloc_free(tmp_ctx);
3001 return LDB_ERR_NO_SUCH_OBJECT;
3004 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3006 const char *attrs[] = { "objectCategory", NULL };
3008 struct ldb_result *res;
3010 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
3011 if (ret != LDB_SUCCESS) {
3015 if (res->count != 1) {
3019 return samdb_result_string(res->msgs[0], "objectCategory", NULL);
3022 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3027 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3028 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3030 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3032 char **tokens, *ret;
3035 tokens = str_list_make(mem_ctx, cn, " -_");
3039 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3040 tokens[0][0] = tolower(tokens[0][0]);
3041 for (i = 1; i < str_list_length((const char **)tokens); i++)
3042 tokens[i][0] = toupper(tokens[i][0]);
3044 ret = talloc_strdup(mem_ctx, tokens[0]);
3045 for (i = 1; i < str_list_length((const char **)tokens); i++)
3046 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3048 talloc_free(tokens);
3054 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3056 int dsdb_functional_level(struct ldb_context *ldb)
3058 int *domainFunctionality =
3059 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3060 if (!domainFunctionality) {
3061 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
3062 return DS_DOMAIN_FUNCTION_2000;
3064 return *domainFunctionality;
3068 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3070 int dsdb_forest_functional_level(struct ldb_context *ldb)
3072 int *forestFunctionality =
3073 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3074 if (!forestFunctionality) {
3075 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3076 return DS_DOMAIN_FUNCTION_2000;
3078 return *forestFunctionality;
3082 set a GUID in an extended DN structure
3084 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3090 status = GUID_to_ndr_blob(guid, dn, &v);
3091 if (!NT_STATUS_IS_OK(status)) {
3092 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3095 ret = ldb_dn_set_extended_component(dn, component_name, &v);
3101 return a GUID from a extended DN structure
3103 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3105 const struct ldb_val *v;
3107 v = ldb_dn_get_extended_component(dn, component_name);
3109 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3112 return GUID_from_ndr_blob(v, guid);
3116 return a uint64_t from a extended DN structure
3118 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3120 const struct ldb_val *v;
3123 v = ldb_dn_get_extended_component(dn, component_name);
3125 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3127 s = talloc_strndup(dn, (const char *)v->data, v->length);
3128 NT_STATUS_HAVE_NO_MEMORY(s);
3130 *val = strtoull(s, NULL, 0);
3133 return NT_STATUS_OK;
3137 return a NTTIME from a extended DN structure
3139 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3141 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3145 return a uint32_t from a extended DN structure
3147 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3149 const struct ldb_val *v;
3152 v = ldb_dn_get_extended_component(dn, component_name);
3154 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3157 s = talloc_strndup(dn, (const char *)v->data, v->length);
3158 NT_STATUS_HAVE_NO_MEMORY(s);
3160 *val = strtoul(s, NULL, 0);
3163 return NT_STATUS_OK;
3167 return a dom_sid from a extended DN structure
3169 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3171 const struct ldb_val *sid_blob;
3172 struct TALLOC_CTX *tmp_ctx;
3173 enum ndr_err_code ndr_err;
3175 sid_blob = ldb_dn_get_extended_component(dn, component_name);
3177 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3180 tmp_ctx = talloc_new(NULL);
3182 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
3183 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3185 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3186 talloc_free(tmp_ctx);
3190 talloc_free(tmp_ctx);
3191 return NT_STATUS_OK;
3196 return RMD_FLAGS directly from a ldb_dn
3197 returns 0 if not found
3199 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3201 const struct ldb_val *v;
3203 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3204 if (!v || v->length > sizeof(buf)-1) return 0;
3205 strncpy(buf, (const char *)v->data, v->length);
3207 return strtoul(buf, NULL, 10);
3211 return RMD_FLAGS directly from a ldb_val for a DN
3212 returns 0 if RMD_FLAGS is not found
3214 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3220 if (val->length < 13) {
3223 p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
3227 flags = strtoul(p+11, &end, 10);
3228 if (!end || *end != '>') {
3229 /* it must end in a > */
3236 return true if a ldb_val containing a DN in storage form is deleted
3238 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3240 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3244 return true if a ldb_val containing a DN in storage form is
3245 in the upgraded w2k3 linked attribute format
3247 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3249 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3253 return a DN for a wellknown GUID
3255 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3256 struct ldb_dn *nc_root, const char *wk_guid,
3257 struct ldb_dn **wkguid_dn)
3259 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3260 const char *attrs[] = { NULL };
3263 struct ldb_result *res;
3265 /* construct the magic WKGUID DN */
3266 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3267 wk_guid, ldb_dn_get_linearized(nc_root));
3269 talloc_free(tmp_ctx);
3270 return ldb_operr(samdb);
3273 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
3274 if (ret != LDB_SUCCESS) {
3275 talloc_free(tmp_ctx);
3279 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3280 talloc_free(tmp_ctx);
3285 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3287 return ldb_dn_compare(*dn1, *dn2);
3291 find a NC root given a DN within the NC
3293 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3294 struct ldb_dn **nc_root)
3296 const char *root_attrs[] = { "namingContexts", NULL };
3297 TALLOC_CTX *tmp_ctx;
3299 struct ldb_message_element *el;
3300 struct ldb_result *root_res;
3302 struct ldb_dn **nc_dns;
3304 tmp_ctx = talloc_new(samdb);
3305 if (tmp_ctx == NULL) {
3306 return ldb_oom(samdb);
3309 ret = ldb_search(samdb, tmp_ctx, &root_res,
3310 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3311 if (ret != LDB_SUCCESS) {
3312 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3313 talloc_free(tmp_ctx);
3317 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3319 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3320 ldb_errstring(samdb)));
3321 talloc_free(tmp_ctx);
3322 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3325 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3327 talloc_free(tmp_ctx);
3328 return ldb_oom(samdb);
3331 for (i=0; i<el->num_values; i++) {
3332 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3333 if (nc_dns[i] == NULL) {
3334 talloc_free(tmp_ctx);
3335 return ldb_operr(samdb);
3339 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
3341 for (i=0; i<el->num_values; i++) {
3342 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3343 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3344 talloc_free(tmp_ctx);
3349 talloc_free(tmp_ctx);
3350 return LDB_ERR_NO_SUCH_OBJECT;
3355 find the deleted objects DN for any object, by looking for the NC
3356 root, then looking up the wellknown GUID
3358 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3359 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3360 struct ldb_dn **do_dn)
3362 struct ldb_dn *nc_root;
3365 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3366 if (ret != LDB_SUCCESS) {
3370 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3371 talloc_free(nc_root);
3376 return the tombstoneLifetime, in days
3378 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3381 dn = ldb_get_config_basedn(ldb);
3383 return LDB_ERR_NO_SUCH_OBJECT;
3385 dn = ldb_dn_copy(ldb, dn);
3387 return ldb_operr(ldb);
3389 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3390 be a wellknown GUID for this */
3391 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
3393 return ldb_operr(ldb);
3396 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3402 compare a ldb_val to a string case insensitively
3404 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3406 size_t len = strlen(s);
3408 if (len > v->length) return 1;
3409 ret = strncasecmp(s, (const char *)v->data, v->length);
3410 if (ret != 0) return ret;
3411 if (v->length > len && v->data[len] != 0) {
3419 load the UDV for a partition in v2 format
3420 The list is returned sorted, and with our local cursor added
3422 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3423 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
3425 static const char *attrs[] = { "replUpToDateVector", NULL };
3426 struct ldb_result *r;
3427 const struct ldb_val *ouv_value;
3430 uint64_t highest_usn;
3431 const struct GUID *our_invocation_id;
3432 struct timeval now = timeval_current();
3434 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
3435 if (ret != LDB_SUCCESS) {
3439 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
3441 enum ndr_err_code ndr_err;
3442 struct replUpToDateVectorBlob ouv;
3444 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
3445 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3446 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3448 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3450 if (ouv.version != 2) {
3451 /* we always store as version 2, and
3452 * replUpToDateVector is not replicated
3454 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3457 *count = ouv.ctr.ctr2.count;
3458 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
3466 our_invocation_id = samdb_ntds_invocation_id(samdb);
3467 if (!our_invocation_id) {
3468 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
3469 talloc_free(*cursors);
3470 return ldb_operr(samdb);
3473 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
3474 if (ret != LDB_SUCCESS) {
3475 /* nothing to add - this can happen after a vampire */
3476 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3480 for (i=0; i<*count; i++) {
3481 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
3482 (*cursors)[i].highest_usn = highest_usn;
3483 (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
3484 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3489 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
3491 return ldb_oom(samdb);
3494 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
3495 (*cursors)[*count].highest_usn = highest_usn;
3496 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
3499 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
3505 load the UDV for a partition in version 1 format
3506 The list is returned sorted, and with our local cursor added
3508 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
3509 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
3511 struct drsuapi_DsReplicaCursor2 *v2;
3515 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
3516 if (ret != LDB_SUCCESS) {
3526 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
3527 if (*cursors == NULL) {
3529 return ldb_oom(samdb);
3532 for (i=0; i<*count; i++) {
3533 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
3534 (*cursors)[i].highest_usn = v2[i].highest_usn;
3541 add a set of controls to a ldb_request structure based on a set of
3542 flags. See util.h for a list of available flags
3544 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
3547 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
3548 struct ldb_search_options_control *options;
3549 /* Using the phantom root control allows us to search all partitions */
3550 options = talloc(req, struct ldb_search_options_control);
3551 if (options == NULL) {
3552 return LDB_ERR_OPERATIONS_ERROR;
3554 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3556 ret = ldb_request_add_control(req,
3557 LDB_CONTROL_SEARCH_OPTIONS_OID,
3559 if (ret != LDB_SUCCESS) {
3564 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
3565 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3566 if (ret != LDB_SUCCESS) {
3571 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
3572 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
3573 if (ret != LDB_SUCCESS) {
3578 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
3579 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
3580 if (!extended_ctrl) {
3581 return LDB_ERR_OPERATIONS_ERROR;
3583 extended_ctrl->type = 1;
3585 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
3586 if (ret != LDB_SUCCESS) {
3591 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
3592 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
3593 if (ret != LDB_SUCCESS) {
3598 if (dsdb_flags & DSDB_MODIFY_RELAX) {
3599 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
3600 if (ret != LDB_SUCCESS) {
3605 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
3606 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
3607 if (ret != LDB_SUCCESS) {
3612 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
3613 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
3614 if (ret != LDB_SUCCESS) {
3619 if (dsdb_flags & DSDB_TREE_DELETE) {
3620 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
3621 if (ret != LDB_SUCCESS) {
3630 an add with a set of controls
3632 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
3633 uint32_t dsdb_flags)
3635 struct ldb_request *req;
3638 ret = ldb_build_add_req(&req, ldb, ldb,
3642 ldb_op_default_callback,
3645 if (ret != LDB_SUCCESS) return ret;
3647 ret = dsdb_request_add_controls(req, dsdb_flags);
3648 if (ret != LDB_SUCCESS) {
3653 ret = dsdb_autotransaction_request(ldb, req);
3660 a modify with a set of controls
3662 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
3663 uint32_t dsdb_flags)
3665 struct ldb_request *req;
3668 ret = ldb_build_mod_req(&req, ldb, ldb,
3672 ldb_op_default_callback,
3675 if (ret != LDB_SUCCESS) return ret;
3677 ret = dsdb_request_add_controls(req, dsdb_flags);
3678 if (ret != LDB_SUCCESS) {
3683 ret = dsdb_autotransaction_request(ldb, req);
3690 like dsdb_modify() but set all the element flags to
3691 LDB_FLAG_MOD_REPLACE
3693 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
3697 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
3698 for (i=0;i<msg->num_elements;i++) {
3699 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3702 return dsdb_modify(ldb, msg, dsdb_flags);
3707 search for attrs on one DN, allowing for dsdb_flags controls
3709 int dsdb_search_dn(struct ldb_context *ldb,
3710 TALLOC_CTX *mem_ctx,
3711 struct ldb_result **_res,
3712 struct ldb_dn *basedn,
3713 const char * const *attrs,
3714 uint32_t dsdb_flags)
3717 struct ldb_request *req;
3718 struct ldb_result *res;
3720 res = talloc_zero(mem_ctx, struct ldb_result);
3722 return ldb_oom(ldb);
3725 ret = ldb_build_search_req(&req, ldb, res,
3732 ldb_search_default_callback,
3734 if (ret != LDB_SUCCESS) {
3739 ret = dsdb_request_add_controls(req, dsdb_flags);
3740 if (ret != LDB_SUCCESS) {
3745 ret = ldb_request(ldb, req);
3746 if (ret == LDB_SUCCESS) {
3747 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3751 if (ret != LDB_SUCCESS) {
3761 general search with dsdb_flags for controls
3763 int dsdb_search(struct ldb_context *ldb,
3764 TALLOC_CTX *mem_ctx,
3765 struct ldb_result **_res,
3766 struct ldb_dn *basedn,
3767 enum ldb_scope scope,
3768 const char * const *attrs,
3769 uint32_t dsdb_flags,
3770 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3773 struct ldb_request *req;
3774 struct ldb_result *res;
3776 char *expression = NULL;
3777 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3779 res = talloc_zero(tmp_ctx, struct ldb_result);
3781 talloc_free(tmp_ctx);
3782 return ldb_oom(ldb);
3786 va_start(ap, exp_fmt);
3787 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3791 talloc_free(tmp_ctx);
3792 return ldb_oom(ldb);
3796 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3803 ldb_search_default_callback,
3805 if (ret != LDB_SUCCESS) {
3806 talloc_free(tmp_ctx);
3810 ret = dsdb_request_add_controls(req, dsdb_flags);
3811 if (ret != LDB_SUCCESS) {
3812 talloc_free(tmp_ctx);
3816 ret = ldb_request(ldb, req);
3817 if (ret == LDB_SUCCESS) {
3818 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3821 if (ret != LDB_SUCCESS) {
3822 talloc_free(tmp_ctx);
3826 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
3827 if (res->count == 0) {
3828 talloc_free(tmp_ctx);
3829 return LDB_ERR_NO_SUCH_OBJECT;
3831 if (res->count != 1) {
3832 talloc_free(tmp_ctx);
3833 return LDB_ERR_CONSTRAINT_VIOLATION;
3837 *_res = talloc_steal(mem_ctx, res);
3838 talloc_free(tmp_ctx);
3845 general search with dsdb_flags for controls
3846 returns exactly 1 record or an error
3848 int dsdb_search_one(struct ldb_context *ldb,
3849 TALLOC_CTX *mem_ctx,
3850 struct ldb_message **msg,
3851 struct ldb_dn *basedn,
3852 enum ldb_scope scope,
3853 const char * const *attrs,
3854 uint32_t dsdb_flags,
3855 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
3858 struct ldb_result *res;
3860 char *expression = NULL;
3861 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3863 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
3865 res = talloc_zero(tmp_ctx, struct ldb_result);
3867 talloc_free(tmp_ctx);
3868 return ldb_oom(ldb);
3872 va_start(ap, exp_fmt);
3873 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
3877 talloc_free(tmp_ctx);
3878 return ldb_oom(ldb);
3880 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3881 dsdb_flags, "%s", expression);
3883 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
3887 if (ret != LDB_SUCCESS) {
3888 talloc_free(tmp_ctx);
3892 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3893 talloc_free(tmp_ctx);
3898 /* returns back the forest DNS name */
3899 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
3901 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
3902 ldb_get_root_basedn(ldb));
3905 if (forest_name == NULL) {
3909 p = strchr(forest_name, '/');
3918 validate that an DSA GUID belongs to the specified user sid.
3919 The user SID must be a domain controller account (either RODC or
3922 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
3923 const struct GUID *dsa_guid,
3924 const struct dom_sid *sid)
3927 - find DN of record with the DSA GUID in the
3928 configuration partition (objectGUID)
3929 - remove "NTDS Settings" component from DN
3930 - do a base search on that DN for serverReference with
3932 - extract objectSid from resulting serverReference
3934 - check this sid matches the sid argument
3936 struct ldb_dn *config_dn;
3937 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3938 struct ldb_message *msg;
3939 const char *attrs1[] = { NULL };
3940 const char *attrs2[] = { "serverReference", NULL };
3942 struct ldb_dn *dn, *account_dn;
3943 struct dom_sid sid2;
3946 config_dn = ldb_get_config_basedn(ldb);
3948 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
3949 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
3950 if (ret != LDB_SUCCESS) {
3951 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
3952 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3953 talloc_free(tmp_ctx);
3954 return ldb_operr(ldb);
3958 if (!ldb_dn_remove_child_components(dn, 1)) {
3959 talloc_free(tmp_ctx);
3960 return ldb_operr(ldb);
3963 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
3964 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
3965 "(objectClass=server)");
3966 if (ret != LDB_SUCCESS) {
3967 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
3968 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3969 talloc_free(tmp_ctx);
3970 return ldb_operr(ldb);
3973 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
3974 if (account_dn == NULL) {
3975 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
3976 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3977 talloc_free(tmp_ctx);
3978 return ldb_operr(ldb);
3981 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
3982 if (!NT_STATUS_IS_OK(status)) {
3983 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
3984 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
3985 talloc_free(tmp_ctx);
3986 return ldb_operr(ldb);
3989 if (!dom_sid_equal(sid, &sid2)) {
3990 /* someone is trying to spoof another account */
3991 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
3992 GUID_string(tmp_ctx, dsa_guid),
3993 dom_sid_string(tmp_ctx, sid),
3994 dom_sid_string(tmp_ctx, &sid2)));
3995 talloc_free(tmp_ctx);
3996 return ldb_operr(ldb);
3999 talloc_free(tmp_ctx);
4003 static const char *secret_attributes[] = {
4006 "initialAuthIncoming",
4007 "initialAuthOutgoing",
4011 "supplementalCredentials",
4012 "trustAuthIncoming",
4013 "trustAuthOutgoing",
4019 check if the attribute belongs to the RODC filtered attribute set
4020 Note that attributes that are in the filtered attribute set are the
4021 ones that _are_ always sent to a RODC
4023 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4025 /* they never get secret attributes */
4026 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4030 /* they do get non-secret critical attributes */
4031 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4035 /* they do get non-secret attributes marked as being in the FAS */
4036 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4040 /* other attributes are denied */
4044 /* return fsmo role dn and role owner dn for a particular role*/
4045 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4046 struct ldb_context *ldb,
4048 struct ldb_dn **fsmo_role_dn,
4049 struct ldb_dn **role_owner_dn)
4053 case DREPL_NAMING_MASTER:
4054 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4055 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4056 if (ret != LDB_SUCCESS) {
4057 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4058 ldb_errstring(ldb)));
4059 talloc_free(tmp_ctx);
4060 return WERR_DS_DRA_INTERNAL_ERROR;
4063 case DREPL_INFRASTRUCTURE_MASTER:
4064 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4065 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4066 if (ret != LDB_SUCCESS) {
4067 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4068 ldb_errstring(ldb)));
4069 talloc_free(tmp_ctx);
4070 return WERR_DS_DRA_INTERNAL_ERROR;
4073 case DREPL_RID_MASTER:
4074 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4075 if (ret != LDB_SUCCESS) {
4076 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4077 talloc_free(tmp_ctx);
4078 return WERR_DS_DRA_INTERNAL_ERROR;
4081 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4082 if (ret != LDB_SUCCESS) {
4083 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4084 ldb_errstring(ldb)));
4085 talloc_free(tmp_ctx);
4086 return WERR_DS_DRA_INTERNAL_ERROR;
4089 case DREPL_SCHEMA_MASTER:
4090 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4091 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4092 if (ret != LDB_SUCCESS) {
4093 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4094 ldb_errstring(ldb)));
4095 talloc_free(tmp_ctx);
4096 return WERR_DS_DRA_INTERNAL_ERROR;
4099 case DREPL_PDC_MASTER:
4100 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4101 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4102 if (ret != LDB_SUCCESS) {
4103 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4104 ldb_errstring(ldb)));
4105 talloc_free(tmp_ctx);
4106 return WERR_DS_DRA_INTERNAL_ERROR;
4110 return WERR_DS_DRA_INTERNAL_ERROR;
4115 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
4116 TALLOC_CTX *mem_ctx,
4117 struct ldb_dn *server_dn)
4120 struct ldb_result *res = NULL;
4121 const char * const attrs[] = { "dNSHostName", NULL};
4123 ldb_ret = ldb_search(ldb, mem_ctx, &res,
4127 if (ldb_ret != LDB_SUCCESS) {
4128 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
4129 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
4133 return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
4137 returns true if an attribute is in the filter,
4138 false otherwise, provided that attribute value is provided with the expression
4140 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
4144 switch (tree->operation) {
4147 for (i=0;i<tree->u.list.num_elements;i++) {
4148 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
4154 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
4155 case LDB_OP_EQUALITY:
4156 case LDB_OP_GREATER:
4159 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
4163 case LDB_OP_SUBSTRING:
4164 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
4168 case LDB_OP_PRESENT:
4169 /* (attrname=*) is not filtered out */
4171 case LDB_OP_EXTENDED:
4172 if (tree->u.extended.attr &&
4173 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {