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_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39 #include "librpc/gen_ndr/ndr_drsblobs.h"
42 search the sam for the specified attributes in a specific domain, filter on
43 objectSid being in domain_sid.
45 int samdb_search_domain(struct ldb_context *sam_ldb,
47 struct ldb_dn *basedn,
48 struct ldb_message ***res,
49 const char * const *attrs,
50 const struct dom_sid *domain_sid,
51 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
57 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
58 res, attrs, format, ap);
64 struct dom_sid *entry_sid;
66 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
68 if ((entry_sid == NULL) ||
69 (!dom_sid_in_domain(domain_sid, entry_sid))) {
70 /* Delete that entry from the result set */
71 (*res)[i] = (*res)[count-1];
73 talloc_free(entry_sid);
76 talloc_free(entry_sid);
84 search the sam for a single string attribute in exactly 1 record
86 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
88 struct ldb_dn *basedn,
89 const char *attr_name,
90 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
93 const char *attrs[2] = { NULL, NULL };
94 struct ldb_message **res = NULL;
98 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
100 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
101 attr_name, format, count));
108 return samdb_result_string(res[0], attr_name, NULL);
112 search the sam for a single string attribute in exactly 1 record
114 const char *samdb_search_string(struct ldb_context *sam_ldb,
116 struct ldb_dn *basedn,
117 const char *attr_name,
118 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
123 va_start(ap, format);
124 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
132 struct ldb_dn *basedn,
133 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
137 struct ldb_message **res = NULL;
140 va_start(ap, format);
141 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
144 if (count != 1) return NULL;
146 ret = talloc_steal(mem_ctx, res[0]->dn);
153 search the sam for a dom_sid attribute in exactly 1 record
155 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
157 struct ldb_dn *basedn,
158 const char *attr_name,
159 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
163 struct ldb_message **res;
164 const char *attrs[2] = { NULL, NULL };
167 attrs[0] = attr_name;
169 va_start(ap, format);
170 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174 attr_name, format, count));
180 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
186 return the count of the number of records in the sam matching the query
188 int samdb_search_count(struct ldb_context *sam_ldb,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
194 struct ldb_message **res;
195 const char * const attrs[] = { NULL };
198 va_start(ap, format);
199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
207 search the sam for a single integer attribute in exactly 1 record
209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
211 uint_t default_value,
212 struct ldb_dn *basedn,
213 const char *attr_name,
214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
218 struct ldb_message **res;
219 const char *attrs[2] = { NULL, NULL };
221 attrs[0] = attr_name;
223 va_start(ap, format);
224 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
228 return default_value;
231 return samdb_result_uint(res[0], attr_name, default_value);
235 search the sam for a single signed 64 bit integer attribute in exactly 1 record
237 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
239 int64_t default_value,
240 struct ldb_dn *basedn,
241 const char *attr_name,
242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
246 struct ldb_message **res;
247 const char *attrs[2] = { NULL, NULL };
249 attrs[0] = attr_name;
251 va_start(ap, format);
252 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
256 return default_value;
259 return samdb_result_int64(res[0], attr_name, default_value);
263 search the sam for multipe records each giving a single string attribute
264 return the number of matches, or -1 on error
266 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
268 struct ldb_dn *basedn,
270 const char *attr_name,
271 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
275 const char *attrs[2] = { NULL, NULL };
276 struct ldb_message **res = NULL;
278 attrs[0] = attr_name;
280 va_start(ap, format);
281 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
288 /* make sure its single valued */
289 for (i=0;i<count;i++) {
290 if (res[i]->num_elements != 1) {
291 DEBUG(1,("samdb: search for %s %s not single valued\n",
298 *strs = talloc_array(mem_ctx, const char *, count+1);
304 for (i=0;i<count;i++) {
305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
307 (*strs)[count] = NULL;
313 pull a uint from a result set.
315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
317 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
321 pull a (signed) int64 from a result set.
323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
325 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
329 pull a string from a result set.
331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
332 const char *default_value)
334 return ldb_msg_find_attr_as_string(msg, attr, default_value);
337 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
338 const char *attr, struct ldb_dn *default_value)
340 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
342 return default_value;
348 pull a rid from a objectSid in a result set.
350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
351 const char *attr, uint32_t default_value)
356 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
358 return default_value;
360 rid = sid->sub_auths[sid->num_auths-1];
366 pull a dom_sid structure from a objectSid in a result set.
368 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
371 const struct ldb_val *v;
373 enum ndr_err_code ndr_err;
374 v = ldb_msg_find_ldb_val(msg, attr);
378 sid = talloc(mem_ctx, struct dom_sid);
382 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
383 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
392 pull a guid structure from a objectGUID in a result set.
394 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
396 const struct ldb_val *v;
397 enum ndr_err_code ndr_err;
403 v = ldb_msg_find_ldb_val(msg, attr);
406 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
407 if (!mem_ctx) return guid;
408 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
409 (ndr_pull_flags_fn_t)ndr_pull_GUID);
410 talloc_free(mem_ctx);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
419 pull a sid prefix from a objectSid in a result set.
420 this is used to find the domain sid for a user
422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426 if (!sid || sid->num_auths < 1) return NULL;
432 pull a NTTIME in a result set.
434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
436 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
440 * Windows stores 0 for lastLogoff.
441 * But when a MS DC return the lastLogoff (as Logoff Time)
442 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
443 * cause windows 2008 and newer version to fail for SMB requests
445 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
447 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
450 ret = 0x7FFFFFFFFFFFFFFFULL;
456 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
457 * indicate an account doesn't expire.
459 * When Windows initially creates an account, it sets
460 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
461 * when changing from an account having a specific expiration date to
462 * that account never expiring, it sets accountExpires = 0.
464 * Consolidate that logic here to allow clearer logic for account expiry in
465 * the rest of the code.
467 NTTIME samdb_result_account_expires(struct ldb_message *msg)
469 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
473 ret = 0x7FFFFFFFFFFFFFFFULL;
479 pull a uint64_t from a result set.
481 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
483 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
488 construct the allow_password_change field from the PwdLastSet attribute and the
489 domain password settings
491 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
493 struct ldb_dn *domain_dn,
494 struct ldb_message *msg,
497 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
500 if (attr_time == 0) {
504 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
506 /* yes, this is a -= not a += as minPwdAge is stored as the negative
507 of the number of 100-nano-seconds */
508 attr_time -= minPwdAge;
514 construct the force_password_change field from the PwdLastSet
515 attribute, the userAccountControl and the domain password settings
517 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
519 struct ldb_dn *domain_dn,
520 struct ldb_message *msg)
522 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
523 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
526 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
527 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
528 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
529 return 0x7FFFFFFFFFFFFFFFULL;
532 if (attr_time == 0) {
536 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
537 if (maxPwdAge == 0) {
538 return 0x7FFFFFFFFFFFFFFFULL;
540 attr_time -= maxPwdAge;
547 pull a samr_Password structutre from a result set.
549 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
551 struct samr_Password *hash = NULL;
552 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
553 if (val && (val->length >= sizeof(hash->hash))) {
554 hash = talloc(mem_ctx, struct samr_Password);
555 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
561 pull an array of samr_Password structutres from a result set.
563 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
564 const char *attr, struct samr_Password **hashes)
567 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
574 count = val->length / 16;
579 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
584 for (i=0;i<count;i++) {
585 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
591 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
592 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
594 struct samr_Password *lmPwdHash, *ntPwdHash;
597 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
600 } else if (num_nt > 1) {
601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
603 *nt_pwd = &ntPwdHash[0];
607 /* Ensure that if we have turned off LM
608 * authentication, that we never use the LM hash, even
610 if (lp_lanman_auth(lp_ctx)) {
612 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
615 } else if (num_lm > 1) {
616 return NT_STATUS_INTERNAL_DB_CORRUPTION;
618 *lm_pwd = &lmPwdHash[0];
628 pull a samr_LogonHours structutre from a result set.
630 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
632 struct samr_LogonHours hours;
633 const int units_per_week = 168;
634 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
636 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
640 hours.units_per_week = units_per_week;
641 memset(hours.bits, 0xFF, units_per_week);
643 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
649 pull a set of account_flags from a result set.
651 This requires that the attributes:
656 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
657 struct ldb_message *msg, struct ldb_dn *domain_dn)
659 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
660 uint32_t acct_flags = ds_uf2acb(userAccountControl);
661 NTTIME must_change_time;
664 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
667 /* Test account expire time */
668 unix_to_nt_time(&now, time(NULL));
669 /* check for expired password */
670 if (must_change_time < now) {
671 acct_flags |= ACB_PW_EXPIRED;
676 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
677 struct ldb_message *msg,
680 struct lsa_BinaryString s;
681 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
689 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
693 s.length = s.size = val->length/2;
694 memcpy(s.array, val->data, val->length);
699 /* Find an attribute, with a particular value */
701 /* The current callers of this function expect a very specific
702 * behaviour: In particular, objectClass subclass equivilance is not
703 * wanted. This means that we should not lookup the schema for the
704 * comparison function */
705 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
706 const struct ldb_message *msg,
707 const char *name, const char *value)
710 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
716 for (i=0;i<el->num_values;i++) {
717 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
725 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
727 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
728 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
733 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
735 struct ldb_message_element *el;
737 el = ldb_msg_find_element(msg, name);
742 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
748 add a string element to a message
750 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
751 const char *attr_name, const char *str)
753 char *s = talloc_strdup(mem_ctx, str);
754 char *a = talloc_strdup(mem_ctx, attr_name);
755 if (s == NULL || a == NULL) {
756 return LDB_ERR_OPERATIONS_ERROR;
758 return ldb_msg_add_string(msg, a, s);
762 add a dom_sid element to a message
764 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
765 const char *attr_name, struct dom_sid *sid)
768 enum ndr_err_code ndr_err;
770 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
771 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
773 (ndr_push_flags_fn_t)ndr_push_dom_sid);
774 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
777 return ldb_msg_add_value(msg, attr_name, &v, NULL);
782 add a delete element operation to a message
784 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name)
787 /* we use an empty replace rather than a delete, as it allows for
788 samdb_replace() to be used everywhere */
789 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
793 add a add attribute value to a message
795 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
796 const char *attr_name, const char *value)
798 struct ldb_message_element *el;
801 a = talloc_strdup(mem_ctx, attr_name);
804 v = talloc_strdup(mem_ctx, value);
807 ret = ldb_msg_add_string(msg, a, v);
810 el = ldb_msg_find_element(msg, a);
813 el->flags = LDB_FLAG_MOD_ADD;
818 add a delete attribute value to a message
820 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, const char *value)
823 struct ldb_message_element *el;
826 a = talloc_strdup(mem_ctx, attr_name);
829 v = talloc_strdup(mem_ctx, value);
832 ret = ldb_msg_add_string(msg, a, v);
835 el = ldb_msg_find_element(msg, a);
838 el->flags = LDB_FLAG_MOD_DELETE;
843 add a int element to a message
845 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846 const char *attr_name, int v)
848 const char *s = talloc_asprintf(mem_ctx, "%d", v);
849 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
853 add a uint_t element to a message
855 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
856 const char *attr_name, uint_t v)
858 const char *s = talloc_asprintf(mem_ctx, "%u", v);
859 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
863 add a (signed) int64_t element to a message
865 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866 const char *attr_name, int64_t v)
868 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
869 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
873 add a uint64_t element to a message
875 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876 const char *attr_name, uint64_t v)
878 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
879 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
883 add a samr_Password element to a message
885 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
886 const char *attr_name, struct samr_Password *hash)
889 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
894 return ldb_msg_add_value(msg, attr_name, &val, NULL);
898 add a samr_Password array to a message
900 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
901 const char *attr_name, struct samr_Password *hashes, uint_t count)
905 val.data = talloc_array_size(mem_ctx, 16, count);
906 val.length = count*16;
910 for (i=0;i<count;i++) {
911 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
913 return ldb_msg_add_value(msg, attr_name, &val, NULL);
917 add a acct_flags element to a message
919 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
920 const char *attr_name, uint32_t v)
922 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
926 add a logon_hours element to a message
928 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
929 const char *attr_name, struct samr_LogonHours *hours)
932 val.length = hours->units_per_week / 8;
933 val.data = hours->bits;
934 return ldb_msg_add_value(msg, attr_name, &val, NULL);
938 add a parameters element to a message
940 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
941 const char *attr_name, struct lsa_BinaryString *parameters)
944 val.length = parameters->length * 2;
945 val.data = (uint8_t *)parameters->array;
946 return ldb_msg_add_value(msg, attr_name, &val, NULL);
949 add a general value element to a message
951 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
952 const char *attr_name, const struct ldb_val *val)
954 return ldb_msg_add_value(msg, attr_name, val, NULL);
958 sets a general value element to a message
960 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961 const char *attr_name, const struct ldb_val *val)
963 struct ldb_message_element *el;
965 el = ldb_msg_find_element(msg, attr_name);
969 return ldb_msg_add_value(msg, attr_name, val, NULL);
973 set a string element in a message
975 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
976 const char *attr_name, const char *str)
978 struct ldb_message_element *el;
980 el = ldb_msg_find_element(msg, attr_name);
984 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
988 replace elements in a record
990 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
994 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
995 for (i=0;i<msg->num_elements;i++) {
996 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
999 /* modify the samdb record */
1000 return ldb_modify(sam_ldb, msg);
1004 return a default security descriptor
1006 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1008 struct security_descriptor *sd;
1010 sd = security_descriptor_initialise(mem_ctx);
1015 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1017 return ldb_get_default_basedn(sam_ctx);
1020 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1022 return ldb_get_config_basedn(sam_ctx);
1025 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1027 return ldb_get_schema_basedn(sam_ctx);
1030 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1032 return ldb_get_root_basedn(sam_ctx);
1035 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1037 struct ldb_dn *new_dn;
1039 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1040 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1041 talloc_free(new_dn);
1047 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1049 struct ldb_dn *new_dn;
1051 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1052 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1053 talloc_free(new_dn);
1060 work out the domain sid for the current open ldb
1062 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1064 TALLOC_CTX *tmp_ctx;
1065 const struct dom_sid *domain_sid;
1066 const char *attrs[] = {
1070 struct ldb_result *res;
1073 /* see if we have a cached copy */
1074 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1079 tmp_ctx = talloc_new(ldb);
1080 if (tmp_ctx == NULL) {
1084 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1086 if (ret != LDB_SUCCESS) {
1090 if (res->count != 1) {
1094 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1095 if (domain_sid == NULL) {
1099 /* cache the domain_sid in the ldb */
1100 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1104 talloc_steal(ldb, domain_sid);
1105 talloc_free(tmp_ctx);
1110 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1111 talloc_free(tmp_ctx);
1115 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1117 TALLOC_CTX *tmp_ctx;
1118 struct dom_sid *dom_sid_new;
1119 struct dom_sid *dom_sid_old;
1121 /* see if we have a cached copy */
1122 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1123 "cache.domain_sid"), struct dom_sid);
1125 tmp_ctx = talloc_new(ldb);
1126 if (tmp_ctx == NULL) {
1130 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1135 /* cache the domain_sid in the ldb */
1136 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1140 talloc_steal(ldb, dom_sid_new);
1141 talloc_free(tmp_ctx);
1142 talloc_free(dom_sid_old);
1147 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1148 talloc_free(tmp_ctx);
1152 /* Obtain the short name of the flexible single master operator
1153 * (FSMO), such as the PDC Emulator */
1154 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1157 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1158 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1159 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1160 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1162 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1163 /* Ensure this matches the format. This gives us a
1164 * bit more confidence that a 'cn' value will be a
1169 return (char *)val->data;
1175 work out the ntds settings dn for the current open ldb
1177 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1179 TALLOC_CTX *tmp_ctx;
1180 const char *root_attrs[] = { "dsServiceName", NULL };
1182 struct ldb_result *root_res;
1183 struct ldb_dn *settings_dn;
1185 /* see if we have a cached copy */
1186 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1191 tmp_ctx = talloc_new(ldb);
1192 if (tmp_ctx == NULL) {
1196 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1198 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1199 ldb_errstring(ldb)));
1203 if (root_res->count != 1) {
1207 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1209 /* cache the domain_sid in the ldb */
1210 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1214 talloc_steal(ldb, settings_dn);
1215 talloc_free(tmp_ctx);
1220 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1221 talloc_free(tmp_ctx);
1226 work out the ntds settings invocationId for the current open ldb
1228 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1230 TALLOC_CTX *tmp_ctx;
1231 const char *attrs[] = { "invocationId", NULL };
1233 struct ldb_result *res;
1234 struct GUID *invocation_id;
1236 /* see if we have a cached copy */
1237 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1238 if (invocation_id) {
1239 return invocation_id;
1242 tmp_ctx = talloc_new(ldb);
1243 if (tmp_ctx == NULL) {
1247 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1252 if (res->count != 1) {
1256 invocation_id = talloc(tmp_ctx, struct GUID);
1257 if (!invocation_id) {
1261 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1263 /* cache the domain_sid in the ldb */
1264 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1268 talloc_steal(ldb, invocation_id);
1269 talloc_free(tmp_ctx);
1271 return invocation_id;
1274 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1275 talloc_free(tmp_ctx);
1279 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1281 TALLOC_CTX *tmp_ctx;
1282 struct GUID *invocation_id_new;
1283 struct GUID *invocation_id_old;
1285 /* see if we have a cached copy */
1286 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1287 "cache.invocation_id");
1289 tmp_ctx = talloc_new(ldb);
1290 if (tmp_ctx == NULL) {
1294 invocation_id_new = talloc(tmp_ctx, struct GUID);
1295 if (!invocation_id_new) {
1299 *invocation_id_new = *invocation_id_in;
1301 /* cache the domain_sid in the ldb */
1302 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1306 talloc_steal(ldb, invocation_id_new);
1307 talloc_free(tmp_ctx);
1308 talloc_free(invocation_id_old);
1313 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314 talloc_free(tmp_ctx);
1319 work out the ntds settings objectGUID for the current open ldb
1321 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1323 TALLOC_CTX *tmp_ctx;
1324 const char *attrs[] = { "objectGUID", NULL };
1326 struct ldb_result *res;
1327 struct GUID *ntds_guid;
1329 /* see if we have a cached copy */
1330 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1335 tmp_ctx = talloc_new(ldb);
1336 if (tmp_ctx == NULL) {
1340 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1345 if (res->count != 1) {
1349 ntds_guid = talloc(tmp_ctx, struct GUID);
1354 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1356 /* cache the domain_sid in the ldb */
1357 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1361 talloc_steal(ldb, ntds_guid);
1362 talloc_free(tmp_ctx);
1367 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1368 talloc_free(tmp_ctx);
1372 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1374 TALLOC_CTX *tmp_ctx;
1375 struct GUID *ntds_guid_new;
1376 struct GUID *ntds_guid_old;
1378 /* see if we have a cached copy */
1379 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1381 tmp_ctx = talloc_new(ldb);
1382 if (tmp_ctx == NULL) {
1386 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1387 if (!ntds_guid_new) {
1391 *ntds_guid_new = *ntds_guid_in;
1393 /* cache the domain_sid in the ldb */
1394 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1398 talloc_steal(ldb, ntds_guid_new);
1399 talloc_free(tmp_ctx);
1400 talloc_free(ntds_guid_old);
1405 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1406 talloc_free(tmp_ctx);
1411 work out the server dn for the current open ldb
1413 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1415 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1419 work out the server dn for the current open ldb
1421 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1423 struct ldb_dn *server_dn;
1424 struct ldb_dn *server_site_dn;
1426 server_dn = samdb_server_dn(ldb, mem_ctx);
1427 if (!server_dn) return NULL;
1429 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1431 talloc_free(server_dn);
1432 return server_site_dn;
1435 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1437 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
1440 return (const char *) val->data;
1446 work out if we are the PDC for the domain of the current open ldb
1448 bool samdb_is_pdc(struct ldb_context *ldb)
1450 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1452 struct ldb_result *dom_res;
1453 TALLOC_CTX *tmp_ctx;
1457 tmp_ctx = talloc_new(ldb);
1458 if (tmp_ctx == NULL) {
1459 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1463 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1465 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1466 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1467 ldb_errstring(ldb)));
1470 if (dom_res->count != 1) {
1474 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1476 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1482 talloc_free(tmp_ctx);
1487 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1488 talloc_free(tmp_ctx);
1493 work out if we are a Global Catalog server for the domain of the current open ldb
1495 bool samdb_is_gc(struct ldb_context *ldb)
1497 const char *attrs[] = { "options", NULL };
1499 struct ldb_result *res;
1500 TALLOC_CTX *tmp_ctx;
1502 tmp_ctx = talloc_new(ldb);
1503 if (tmp_ctx == NULL) {
1504 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1508 /* Query cn=ntds settings,.... */
1509 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1511 talloc_free(tmp_ctx);
1514 if (res->count != 1) {
1515 talloc_free(tmp_ctx);
1519 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1520 talloc_free(tmp_ctx);
1522 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1523 if (options & 0x000000001) {
1529 /* Find a domain object in the parents of a particular DN. */
1530 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1531 struct ldb_dn **parent_dn, const char **errstring)
1533 TALLOC_CTX *local_ctx;
1534 struct ldb_dn *sdn = dn;
1535 struct ldb_result *res = NULL;
1537 const char *attrs[] = { NULL };
1539 local_ctx = talloc_new(mem_ctx);
1540 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1542 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1543 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1544 "(|(objectClass=domain)(objectClass=builtinDomain))");
1545 if (ret == LDB_SUCCESS) {
1546 if (res->count == 1) {
1554 if (ret != LDB_SUCCESS) {
1555 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1556 ldb_dn_get_linearized(dn),
1557 ldb_dn_get_linearized(sdn),
1558 ldb_errstring(ldb));
1559 talloc_free(local_ctx);
1562 if (res->count != 1) {
1563 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1564 ldb_dn_get_linearized(dn));
1565 DEBUG(0,(__location__ ": %s\n", *errstring));
1566 talloc_free(local_ctx);
1567 return LDB_ERR_CONSTRAINT_VIOLATION;
1570 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1571 talloc_free(local_ctx);
1577 set the user password using plaintext, obeying any user or domain
1578 password restrictions
1580 note that this function doesn't actually store the result in the
1581 database, it just fills in the "mod" structure with ldb modify
1582 elements to setup the correct change when samdb_replace() is
1583 called. This allows the caller to combine the change with other
1584 changes (as is needed by some of the set user info levels)
1586 The caller should probably have a transaction wrapping this
1588 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1589 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1590 struct ldb_message *mod,
1591 const DATA_BLOB *new_password,
1592 struct samr_Password *param_lmNewHash,
1593 struct samr_Password *param_ntNewHash,
1595 enum samPwdChangeReason *reject_reason,
1596 struct samr_DomInfo1 **_dominfo)
1598 const char * const user_attrs[] = { "userAccountControl",
1601 "dBCSPwd", "unicodePwd",
1603 "pwdLastSet", NULL };
1604 const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1606 "maxPwdAge", "minPwdAge", NULL };
1608 uint32_t minPwdLength, pwdProperties, pwdHistoryLength;
1609 int64_t maxPwdAge, minPwdAge;
1610 uint32_t userAccountControl;
1611 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1612 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1613 struct samr_Password local_lmNewHash, local_ntNewHash;
1614 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1615 struct dom_sid *domain_sid;
1616 struct ldb_message **res;
1619 time_t now = time(NULL);
1623 /* we need to know the time to compute password age */
1624 unix_to_nt_time(&now_nt, now);
1626 /* pull all the user parameters */
1627 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1629 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1631 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1632 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1633 "lmPwdHistory", &sambaLMPwdHistory);
1634 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1635 "ntPwdHistory", &sambaNTPwdHistory);
1636 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1637 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1638 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1640 /* Copy parameters */
1641 lmNewHash = param_lmNewHash;
1642 ntNewHash = param_ntNewHash;
1644 /* Only non-trust accounts have restrictions (possibly this
1645 * test is the wrong way around, but I like to be restrictive
1647 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1648 |UF_WORKSTATION_TRUST_ACCOUNT
1649 |UF_SERVER_TRUST_ACCOUNT));
1651 if (domain_dn != NULL) {
1652 /* pull the domain parameters */
1653 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res,
1656 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1657 ldb_dn_get_linearized(domain_dn),
1658 ldb_dn_get_linearized(user_dn)));
1659 return NT_STATUS_NO_SUCH_DOMAIN;
1662 /* work out the domain sid, and pull the domain from there */
1663 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1665 if (domain_sid == NULL) {
1666 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1669 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1671 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1673 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1674 dom_sid_string(mem_ctx, domain_sid),
1675 ldb_dn_get_linearized(user_dn)));
1676 return NT_STATUS_NO_SUCH_DOMAIN;
1680 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1681 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1682 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1683 maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0);
1684 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1686 if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1687 /* see [MS-ADTS] 2.2.15 */
1691 if (_dominfo != NULL) {
1692 struct samr_DomInfo1 *dominfo;
1693 /* on failure we need to fill in the reject reasons */
1694 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1695 if (dominfo == NULL) {
1696 return NT_STATUS_NO_MEMORY;
1698 dominfo->min_password_length = minPwdLength;
1699 dominfo->password_properties = pwdProperties;
1700 dominfo->password_history_length = pwdHistoryLength;
1701 dominfo->max_password_age = maxPwdAge;
1702 dominfo->min_password_age = minPwdAge;
1703 *_dominfo = dominfo;
1706 if ((restrictions != 0) && (new_password != 0)) {
1709 /* checks if the "minPwdLength" property is satisfied */
1710 if ((restrictions != 0)
1711 && (minPwdLength > utf16_len_n(
1712 new_password->data, new_password->length)/2)) {
1713 if (reject_reason) {
1714 *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1716 return NT_STATUS_PASSWORD_RESTRICTION;
1719 /* Create the NT hash */
1720 mdfour(local_ntNewHash.hash, new_password->data,
1721 new_password->length);
1723 ntNewHash = &local_ntNewHash;
1725 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1726 if (convert_string_talloc_convenience(mem_ctx,
1727 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1729 new_password->data, new_password->length,
1730 (void **)&new_pass, NULL, false)) {
1732 /* checks the password complexity */
1733 if ((restrictions != 0)
1735 & DOMAIN_PASSWORD_COMPLEX) != 0)
1736 && (!check_password_quality(new_pass))) {
1737 if (reject_reason) {
1738 *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1740 return NT_STATUS_PASSWORD_RESTRICTION;
1743 /* compute the new lm hashes (for checking history - case insenitivly!) */
1744 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1745 lmNewHash = &local_lmNewHash;
1750 if ((restrictions != 0) && user_change) {
1751 /* are all password changes disallowed? */
1752 if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) {
1753 if (reject_reason) {
1754 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1756 return NT_STATUS_PASSWORD_RESTRICTION;
1759 /* can this user change the password? */
1760 if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) {
1761 if (reject_reason) {
1762 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1764 return NT_STATUS_PASSWORD_RESTRICTION;
1767 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1768 if (pwdLastSet - minPwdAge > now_nt) {
1769 if (reject_reason) {
1770 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1772 return NT_STATUS_PASSWORD_RESTRICTION;
1775 /* check the immediately past password */
1776 if (pwdHistoryLength > 0) {
1777 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash,
1778 lmPwdHash->hash, 16) == 0) {
1779 if (reject_reason) {
1780 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1782 return NT_STATUS_PASSWORD_RESTRICTION;
1784 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash,
1785 ntPwdHash->hash, 16) == 0) {
1786 if (reject_reason) {
1787 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1789 return NT_STATUS_PASSWORD_RESTRICTION;
1793 /* check the password history */
1794 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len,
1796 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1799 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1800 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
1802 if (reject_reason) {
1803 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1805 return NT_STATUS_PASSWORD_RESTRICTION;
1808 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1809 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash,
1811 if (reject_reason) {
1812 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1814 return NT_STATUS_PASSWORD_RESTRICTION;
1819 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1821 /* the password is acceptable. Start forming the new fields */
1822 if (new_password != NULL) {
1823 /* if we know the cleartext UTF16 password, then set it.
1824 * Modules in ldb will set all the appropriate
1826 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1828 /* We don't have the cleartext, so delete the old one
1829 * and set what we have of the hashes */
1830 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1833 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1835 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1839 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1841 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1845 if (reject_reason) {
1846 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1848 return NT_STATUS_OK;
1853 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1854 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1855 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1856 * gives some more informations if the changed failed.
1858 * This wrapper function for "samdb_set_password" takes a SID as input rather
1861 * This call encapsulates a new LDB transaction for changing the password;
1862 * therefore the user hasn't to start a new one.
1864 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1865 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1866 * NT_STATUS_PASSWORD_RESTRICTION
1868 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1869 const struct dom_sid *user_sid,
1870 const DATA_BLOB *new_password,
1871 struct samr_Password *lmNewHash,
1872 struct samr_Password *ntNewHash,
1874 enum samPwdChangeReason *reject_reason,
1875 struct samr_DomInfo1 **_dominfo)
1878 struct ldb_dn *user_dn;
1879 struct ldb_message *msg;
1882 ret = ldb_transaction_start(ldb);
1883 if (ret != LDB_SUCCESS) {
1884 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
1885 return NT_STATUS_TRANSACTION_ABORTED;
1888 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
1889 "(&(objectSid=%s)(objectClass=user))",
1890 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1892 ldb_transaction_cancel(ldb);
1893 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1894 dom_sid_string(mem_ctx, user_sid)));
1895 return NT_STATUS_NO_SUCH_USER;
1898 msg = ldb_msg_new(mem_ctx);
1900 ldb_transaction_cancel(ldb);
1901 return NT_STATUS_NO_MEMORY;
1904 msg->dn = ldb_dn_copy(msg, user_dn);
1906 ldb_transaction_cancel(ldb);
1907 return NT_STATUS_NO_MEMORY;
1910 nt_status = samdb_set_password(ldb, mem_ctx,
1913 lmNewHash, ntNewHash,
1914 user_change, /* This is a password set, not change */
1915 reject_reason, _dominfo);
1916 if (!NT_STATUS_IS_OK(nt_status)) {
1917 ldb_transaction_cancel(ldb);
1921 /* modify the samdb record */
1922 ret = samdb_replace(ldb, mem_ctx, msg);
1923 if (ret != LDB_SUCCESS) {
1924 ldb_transaction_cancel(ldb);
1925 return NT_STATUS_ACCESS_DENIED;
1928 ret = ldb_transaction_commit(ldb);
1929 if (ret != LDB_SUCCESS) {
1930 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1931 ldb_dn_get_linearized(msg->dn),
1932 ldb_errstring(ldb)));
1933 return NT_STATUS_TRANSACTION_ABORTED;
1935 return NT_STATUS_OK;
1939 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1940 struct dom_sid *sid, struct ldb_dn **ret_dn)
1942 struct ldb_message *msg;
1943 struct ldb_dn *basedn;
1947 sidstr = dom_sid_string(mem_ctx, sid);
1948 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1950 /* We might have to create a ForeignSecurityPrincipal, even if this user
1951 * is in our own domain */
1953 msg = ldb_msg_new(mem_ctx);
1955 return NT_STATUS_NO_MEMORY;
1958 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1959 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1960 * not work, this is wrong for the Builtin domain, there's no
1961 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1964 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1965 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1967 if (basedn == NULL) {
1968 DEBUG(0, ("Failed to find DN for "
1969 "ForeignSecurityPrincipal container\n"));
1970 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1973 /* add core elements to the ldb_message for the alias */
1974 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1975 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1976 return NT_STATUS_NO_MEMORY;
1978 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1980 "foreignSecurityPrincipal");
1982 /* create the alias */
1983 ret = ldb_add(sam_ctx, msg);
1985 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1987 ldb_dn_get_linearized(msg->dn),
1988 ldb_errstring(sam_ctx)));
1989 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1992 return NT_STATUS_OK;
1997 Find the DN of a domain, assuming it to be a dotted.dns name
2000 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2003 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2004 const char *binary_encoded;
2005 const char **split_realm;
2012 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2014 talloc_free(tmp_ctx);
2017 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2018 for (i=0; split_realm[i]; i++) {
2019 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2020 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2021 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2022 binary_encoded, ldb_dn_get_linearized(dn)));
2023 talloc_free(tmp_ctx);
2027 if (!ldb_dn_validate(dn)) {
2028 DEBUG(2, ("Failed to validated DN %s\n",
2029 ldb_dn_get_linearized(dn)));
2035 Find the DN of a domain, be it the netbios or DNS name
2038 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2039 const char *domain_name)
2041 const char * const domain_ref_attrs[] = {
2044 const char * const domain_ref2_attrs[] = {
2047 struct ldb_result *res_domain_ref;
2048 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2049 /* find the domain's DN */
2050 int ret_domain = ldb_search(ldb, mem_ctx,
2052 samdb_partitions_dn(ldb, mem_ctx),
2055 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2057 if (ret_domain != 0) {
2061 if (res_domain_ref->count == 0) {
2062 ret_domain = ldb_search(ldb, mem_ctx,
2064 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2067 "(objectclass=domain)");
2068 if (ret_domain != 0) {
2072 if (res_domain_ref->count == 1) {
2073 return res_domain_ref->msgs[0]->dn;
2078 if (res_domain_ref->count > 1) {
2079 DEBUG(0,("Found %d records matching domain [%s]\n",
2080 ret_domain, domain_name));
2084 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2090 use a GUID to find a DN
2092 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2093 TALLOC_CTX *mem_ctx,
2094 const char *guid_str, struct ldb_dn **dn)
2097 struct ldb_result *res;
2098 const char *attrs[] = { NULL };
2099 struct ldb_request *search_req;
2101 struct ldb_search_options_control *options;
2103 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2105 DEBUG(0, (__location__ ": out of memory\n"));
2106 return LDB_ERR_OPERATIONS_ERROR;
2109 res = talloc_zero(mem_ctx, struct ldb_result);
2111 DEBUG(0, (__location__ ": out of memory\n"));
2112 return LDB_ERR_OPERATIONS_ERROR;
2115 ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2116 ldb_get_default_basedn(ldb),
2120 res, ldb_search_default_callback,
2122 if (ret != LDB_SUCCESS) {
2126 /* we need to cope with cross-partition links, so search for
2127 the GUID over all partitions */
2128 options = talloc(search_req, struct ldb_search_options_control);
2129 if (options == NULL) {
2130 DEBUG(0, (__location__ ": out of memory\n"));
2131 return LDB_ERR_OPERATIONS_ERROR;
2133 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2135 ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2136 if (ret != LDB_SUCCESS) {
2140 ret = ldb_request_add_control(search_req,
2141 LDB_CONTROL_SEARCH_OPTIONS_OID,
2143 if (ret != LDB_SUCCESS) {
2147 ret = ldb_request(ldb, search_req);
2148 if (ret != LDB_SUCCESS) {
2152 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2153 if (ret != LDB_SUCCESS) {
2157 /* this really should be exactly 1, but there is a bug in the
2158 partitions module that can return two here with the
2159 search_options control set */
2160 if (res->count < 1) {
2161 return LDB_ERR_NO_SUCH_OBJECT;
2164 *dn = res->msgs[0]->dn;
2170 search for attrs on one DN, allowing for deleted objects
2172 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2173 TALLOC_CTX *mem_ctx,
2174 struct ldb_result **_res,
2175 struct ldb_dn *basedn,
2176 const char * const *attrs)
2179 struct ldb_request *req;
2180 TALLOC_CTX *tmp_ctx;
2181 struct ldb_result *res;
2183 tmp_ctx = talloc_new(mem_ctx);
2185 res = talloc_zero(tmp_ctx, struct ldb_result);
2187 return LDB_ERR_OPERATIONS_ERROR;
2190 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2197 ldb_search_default_callback,
2199 if (ret != LDB_SUCCESS) {
2200 talloc_free(tmp_ctx);
2204 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2205 if (ret != LDB_SUCCESS) {
2209 ret = ldb_request(ldb, req);
2210 if (ret == LDB_SUCCESS) {
2211 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2215 *_res = talloc_steal(mem_ctx, res);
2221 use a DN to find a GUID
2223 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2224 struct ldb_dn *dn, struct GUID *guid)
2227 struct ldb_result *res;
2228 const char *attrs[] = { "objectGUID", NULL };
2229 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2231 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2232 if (ret != LDB_SUCCESS) {
2233 talloc_free(tmp_ctx);
2236 if (res->count < 1) {
2237 talloc_free(tmp_ctx);
2238 return LDB_ERR_NO_SUCH_OBJECT;
2240 *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2241 talloc_free(tmp_ctx);
2246 use a DN to find a SID
2248 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2249 struct ldb_dn *dn, struct dom_sid *sid)
2252 struct ldb_result *res;
2253 const char *attrs[] = { "objectSID", NULL };
2254 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2259 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2260 if (ret != LDB_SUCCESS) {
2261 talloc_free(tmp_ctx);
2264 if (res->count < 1) {
2265 talloc_free(tmp_ctx);
2266 return LDB_ERR_NO_SUCH_OBJECT;
2268 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2270 talloc_free(tmp_ctx);
2271 return LDB_ERR_NO_SUCH_OBJECT;
2274 talloc_free(tmp_ctx);
2281 load a repsFromTo blob list for a given partition GUID
2282 attr must be "repsFrom" or "repsTo"
2284 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2285 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2287 const char *attrs[] = { attr, NULL };
2288 struct ldb_result *res = NULL;
2289 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2291 struct ldb_message_element *el;
2296 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2298 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2299 talloc_free(tmp_ctx);
2300 return WERR_DS_DRA_INTERNAL_ERROR;
2303 el = ldb_msg_find_element(res->msgs[0], attr);
2305 /* it's OK to be empty */
2306 talloc_free(tmp_ctx);
2310 *count = el->num_values;
2311 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2313 talloc_free(tmp_ctx);
2314 return WERR_DS_DRA_INTERNAL_ERROR;
2317 for (i=0; i<(*count); i++) {
2318 enum ndr_err_code ndr_err;
2319 ndr_err = ndr_pull_struct_blob(&el->values[i],
2320 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2322 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2323 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2324 talloc_free(tmp_ctx);
2325 return WERR_DS_DRA_INTERNAL_ERROR;
2329 talloc_free(tmp_ctx);
2335 save the repsFromTo blob list for a given partition GUID
2336 attr must be "repsFrom" or "repsTo"
2338 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2339 const char *attr, struct repsFromToBlob *r, uint32_t count)
2341 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2342 struct ldb_message *msg;
2343 struct ldb_message_element *el;
2346 msg = ldb_msg_new(tmp_ctx);
2348 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2352 el->values = talloc_array(msg, struct ldb_val, count);
2357 for (i=0; i<count; i++) {
2359 enum ndr_err_code ndr_err;
2361 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2363 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2364 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2372 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2373 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2377 talloc_free(tmp_ctx);
2382 talloc_free(tmp_ctx);
2383 return WERR_DS_DRA_INTERNAL_ERROR;
2388 load the uSNHighest attribute from the @REPLCHANGED object for a
2391 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2393 struct ldb_request *req;
2395 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2396 struct dsdb_control_current_partition *p_ctrl;
2397 struct ldb_result *res;
2399 res = talloc_zero(tmp_ctx, struct ldb_result);
2401 talloc_free(tmp_ctx);
2402 return LDB_ERR_OPERATIONS_ERROR;
2405 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2406 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2410 res, ldb_search_default_callback,
2412 if (ret != LDB_SUCCESS) {
2413 talloc_free(tmp_ctx);
2417 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2418 if (p_ctrl == NULL) {
2420 return LDB_ERR_OPERATIONS_ERROR;
2422 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2426 ret = ldb_request_add_control(req,
2427 DSDB_CONTROL_CURRENT_PARTITION_OID,
2429 if (ret != LDB_SUCCESS) {
2430 talloc_free(tmp_ctx);
2434 /* Run the new request */
2435 ret = ldb_request(ldb, req);
2437 if (ret == LDB_SUCCESS) {
2438 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2441 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2442 /* it hasn't been created yet, which means
2443 an implicit value of zero */
2445 talloc_free(tmp_ctx);
2449 if (ret != LDB_SUCCESS) {
2450 talloc_free(tmp_ctx);
2454 if (res->count < 1) {
2457 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2460 talloc_free(tmp_ctx);
2466 save the uSNHighest attribute in the @REPLCHANGED object for a
2469 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2471 struct ldb_request *req;
2472 struct ldb_message *msg;
2473 struct dsdb_control_current_partition *p_ctrl;
2476 msg = ldb_msg_new(ldb);
2478 return LDB_ERR_OPERATIONS_ERROR;
2481 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2482 if (msg->dn == NULL) {
2484 return LDB_ERR_OPERATIONS_ERROR;
2487 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2488 if (ret != LDB_SUCCESS) {
2492 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2495 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2496 if (p_ctrl == NULL) {
2498 return LDB_ERR_OPERATIONS_ERROR;
2500 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2503 ret = ldb_build_mod_req(&req, ldb, msg,
2506 NULL, ldb_op_default_callback,
2509 if (ret != LDB_SUCCESS) {
2514 ret = ldb_request_add_control(req,
2515 DSDB_CONTROL_CURRENT_PARTITION_OID,
2517 if (ret != LDB_SUCCESS) {
2522 /* Run the new request */
2523 ret = ldb_request(ldb, req);
2525 if (ret == LDB_SUCCESS) {
2526 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2528 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2529 ret = ldb_build_add_req(&req, ldb, msg,
2532 NULL, ldb_op_default_callback,
2542 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2543 const struct drsuapi_DsReplicaCursor2 *c2)
2545 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2549 see if we are a RODC
2551 TODO: This should take a sam_ctx, and lookup the right object (with
2554 bool samdb_rodc(struct loadparm_context *lp_ctx)
2556 return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false);
2561 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2563 flags are DS_NTDS_OPTION_*
2565 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2567 TALLOC_CTX *tmp_ctx;
2568 const char *attrs[] = { "options", NULL };
2570 struct ldb_result *res;
2572 tmp_ctx = talloc_new(ldb);
2573 if (tmp_ctx == NULL) {
2577 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2582 if (res->count != 1) {
2586 *options = samdb_result_uint(res->msgs[0], "options", 0);
2588 talloc_free(tmp_ctx);
2593 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2594 talloc_free(tmp_ctx);
2595 return LDB_ERR_NO_SUCH_OBJECT;