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"
40 #include "system/locale.h"
43 search the sam for the specified attributes in a specific domain, filter on
44 objectSid being in domain_sid.
46 int samdb_search_domain(struct ldb_context *sam_ldb,
48 struct ldb_dn *basedn,
49 struct ldb_message ***res,
50 const char * const *attrs,
51 const struct dom_sid *domain_sid,
52 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
58 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
59 res, attrs, format, ap);
65 struct dom_sid *entry_sid;
67 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
69 if ((entry_sid == NULL) ||
70 (!dom_sid_in_domain(domain_sid, entry_sid))) {
71 /* Delete that entry from the result set */
72 (*res)[i] = (*res)[count-1];
74 talloc_free(entry_sid);
77 talloc_free(entry_sid);
85 search the sam for a single string attribute in exactly 1 record
87 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
89 struct ldb_dn *basedn,
90 const char *attr_name,
91 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
94 const char *attrs[2] = { NULL, NULL };
95 struct ldb_message **res = NULL;
99 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
101 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
102 attr_name, format, count));
109 return samdb_result_string(res[0], attr_name, NULL);
113 search the sam for a single string attribute in exactly 1 record
115 const char *samdb_search_string(struct ldb_context *sam_ldb,
117 struct ldb_dn *basedn,
118 const char *attr_name,
119 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
124 va_start(ap, format);
125 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
131 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
133 struct ldb_dn *basedn,
134 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
138 struct ldb_message **res = NULL;
141 va_start(ap, format);
142 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
145 if (count != 1) return NULL;
147 ret = talloc_steal(mem_ctx, res[0]->dn);
154 search the sam for a dom_sid attribute in exactly 1 record
156 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
158 struct ldb_dn *basedn,
159 const char *attr_name,
160 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
164 struct ldb_message **res;
165 const char *attrs[2] = { NULL, NULL };
168 attrs[0] = attr_name;
170 va_start(ap, format);
171 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
174 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
175 attr_name, format, count));
181 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
187 return the count of the number of records in the sam matching the query
189 int samdb_search_count(struct ldb_context *sam_ldb,
191 struct ldb_dn *basedn,
192 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
195 struct ldb_message **res;
196 const char * const attrs[] = { NULL };
199 va_start(ap, format);
200 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
208 search the sam for a single integer attribute in exactly 1 record
210 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
212 uint_t default_value,
213 struct ldb_dn *basedn,
214 const char *attr_name,
215 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
219 struct ldb_message **res;
220 const char *attrs[2] = { NULL, NULL };
222 attrs[0] = attr_name;
224 va_start(ap, format);
225 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
229 return default_value;
232 return samdb_result_uint(res[0], attr_name, default_value);
236 search the sam for a single signed 64 bit integer attribute in exactly 1 record
238 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
240 int64_t default_value,
241 struct ldb_dn *basedn,
242 const char *attr_name,
243 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
247 struct ldb_message **res;
248 const char *attrs[2] = { NULL, NULL };
250 attrs[0] = attr_name;
252 va_start(ap, format);
253 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
257 return default_value;
260 return samdb_result_int64(res[0], attr_name, default_value);
264 search the sam for multipe records each giving a single string attribute
265 return the number of matches, or -1 on error
267 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
269 struct ldb_dn *basedn,
271 const char *attr_name,
272 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
276 const char *attrs[2] = { NULL, NULL };
277 struct ldb_message **res = NULL;
279 attrs[0] = attr_name;
281 va_start(ap, format);
282 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
289 /* make sure its single valued */
290 for (i=0;i<count;i++) {
291 if (res[i]->num_elements != 1) {
292 DEBUG(1,("samdb: search for %s %s not single valued\n",
299 *strs = talloc_array(mem_ctx, const char *, count+1);
305 for (i=0;i<count;i++) {
306 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
308 (*strs)[count] = NULL;
314 pull a uint from a result set.
316 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
318 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
322 pull a (signed) int64 from a result set.
324 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
326 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
330 pull a string from a result set.
332 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
333 const char *default_value)
335 return ldb_msg_find_attr_as_string(msg, attr, default_value);
338 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
339 const char *attr, struct ldb_dn *default_value)
341 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
343 return default_value;
349 pull a rid from a objectSid in a result set.
351 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
352 const char *attr, uint32_t default_value)
357 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
359 return default_value;
361 rid = sid->sub_auths[sid->num_auths-1];
367 pull a dom_sid structure from a objectSid in a result set.
369 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
372 const struct ldb_val *v;
374 enum ndr_err_code ndr_err;
375 v = ldb_msg_find_ldb_val(msg, attr);
379 sid = talloc(mem_ctx, struct dom_sid);
383 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
384 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
385 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
393 pull a guid structure from a objectGUID in a result set.
395 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
397 const struct ldb_val *v;
398 enum ndr_err_code ndr_err;
404 v = ldb_msg_find_ldb_val(msg, attr);
407 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
408 if (!mem_ctx) return guid;
409 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
410 (ndr_pull_flags_fn_t)ndr_pull_GUID);
411 talloc_free(mem_ctx);
412 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
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(struct ldb_message *msg, const char *attr, NTTIME default_value)
437 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
441 * Windows stores 0 for lastLogoff.
442 * But when a MS DC return the lastLogoff (as Logoff Time)
443 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
444 * cause windows 2008 and newer version to fail for SMB requests
446 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
448 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
451 ret = 0x7FFFFFFFFFFFFFFFULL;
457 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
458 * indicate an account doesn't expire.
460 * When Windows initially creates an account, it sets
461 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
462 * when changing from an account having a specific expiration date to
463 * that account never expiring, it sets accountExpires = 0.
465 * Consolidate that logic here to allow clearer logic for account expiry in
466 * the rest of the code.
468 NTTIME samdb_result_account_expires(struct ldb_message *msg)
470 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
474 ret = 0x7FFFFFFFFFFFFFFFULL;
480 pull a uint64_t from a result set.
482 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
484 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
489 construct the allow_password_change field from the PwdLastSet attribute and the
490 domain password settings
492 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
494 struct ldb_dn *domain_dn,
495 struct ldb_message *msg,
498 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
501 if (attr_time == 0) {
505 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
507 /* yes, this is a -= not a += as minPwdAge is stored as the negative
508 of the number of 100-nano-seconds */
509 attr_time -= minPwdAge;
515 construct the force_password_change field from the PwdLastSet
516 attribute, the userAccountControl and the domain password settings
518 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
520 struct ldb_dn *domain_dn,
521 struct ldb_message *msg)
523 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
524 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
527 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
528 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
529 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
530 return 0x7FFFFFFFFFFFFFFFULL;
533 if (attr_time == 0) {
537 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
538 if (maxPwdAge == 0) {
539 return 0x7FFFFFFFFFFFFFFFULL;
541 attr_time -= maxPwdAge;
548 pull a samr_Password structutre from a result set.
550 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
552 struct samr_Password *hash = NULL;
553 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
554 if (val && (val->length >= sizeof(hash->hash))) {
555 hash = talloc(mem_ctx, struct samr_Password);
556 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
562 pull an array of samr_Password structutres from a result set.
564 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
565 const char *attr, struct samr_Password **hashes)
568 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_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1032 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1033 struct ldb_dn *aggregate_dn;
1038 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1039 if (!aggregate_dn) {
1042 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1045 return aggregate_dn;
1048 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1050 return ldb_get_root_basedn(sam_ctx);
1053 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1055 struct ldb_dn *new_dn;
1057 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1058 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1059 talloc_free(new_dn);
1065 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1067 struct ldb_dn *new_dn;
1069 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1070 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1071 talloc_free(new_dn);
1078 work out the domain sid for the current open ldb
1080 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1082 TALLOC_CTX *tmp_ctx;
1083 const struct dom_sid *domain_sid;
1084 const char *attrs[] = {
1088 struct ldb_result *res;
1091 /* see if we have a cached copy */
1092 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1097 tmp_ctx = talloc_new(ldb);
1098 if (tmp_ctx == NULL) {
1102 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1104 if (ret != LDB_SUCCESS) {
1108 if (res->count != 1) {
1112 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1113 if (domain_sid == NULL) {
1117 /* cache the domain_sid in the ldb */
1118 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1122 talloc_steal(ldb, domain_sid);
1123 talloc_free(tmp_ctx);
1128 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1129 talloc_free(tmp_ctx);
1133 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1135 TALLOC_CTX *tmp_ctx;
1136 struct dom_sid *dom_sid_new;
1137 struct dom_sid *dom_sid_old;
1139 /* see if we have a cached copy */
1140 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1141 "cache.domain_sid"), struct dom_sid);
1143 tmp_ctx = talloc_new(ldb);
1144 if (tmp_ctx == NULL) {
1148 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1153 /* cache the domain_sid in the ldb */
1154 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1158 talloc_steal(ldb, dom_sid_new);
1159 talloc_free(tmp_ctx);
1160 talloc_free(dom_sid_old);
1165 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1166 talloc_free(tmp_ctx);
1170 /* Obtain the short name of the flexible single master operator
1171 * (FSMO), such as the PDC Emulator */
1172 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1175 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1176 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1177 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1178 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1180 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1181 /* Ensure this matches the format. This gives us a
1182 * bit more confidence that a 'cn' value will be a
1187 return (char *)val->data;
1193 work out the ntds settings dn for the current open ldb
1195 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1197 TALLOC_CTX *tmp_ctx;
1198 const char *root_attrs[] = { "dsServiceName", NULL };
1200 struct ldb_result *root_res;
1201 struct ldb_dn *settings_dn;
1203 /* see if we have a cached copy */
1204 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1209 tmp_ctx = talloc_new(ldb);
1210 if (tmp_ctx == NULL) {
1214 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1216 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1217 ldb_errstring(ldb)));
1221 if (root_res->count != 1) {
1225 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1227 /* cache the domain_sid in the ldb */
1228 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1232 talloc_steal(ldb, settings_dn);
1233 talloc_free(tmp_ctx);
1238 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1239 talloc_free(tmp_ctx);
1244 work out the ntds settings invocationId for the current open ldb
1246 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1248 TALLOC_CTX *tmp_ctx;
1249 const char *attrs[] = { "invocationId", NULL };
1251 struct ldb_result *res;
1252 struct GUID *invocation_id;
1254 /* see if we have a cached copy */
1255 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1256 if (invocation_id) {
1257 return invocation_id;
1260 tmp_ctx = talloc_new(ldb);
1261 if (tmp_ctx == NULL) {
1265 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1270 if (res->count != 1) {
1274 invocation_id = talloc(tmp_ctx, struct GUID);
1275 if (!invocation_id) {
1279 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1281 /* cache the domain_sid in the ldb */
1282 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1286 talloc_steal(ldb, invocation_id);
1287 talloc_free(tmp_ctx);
1289 return invocation_id;
1292 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1293 talloc_free(tmp_ctx);
1297 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1299 TALLOC_CTX *tmp_ctx;
1300 struct GUID *invocation_id_new;
1301 struct GUID *invocation_id_old;
1303 /* see if we have a cached copy */
1304 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1305 "cache.invocation_id");
1307 tmp_ctx = talloc_new(ldb);
1308 if (tmp_ctx == NULL) {
1312 invocation_id_new = talloc(tmp_ctx, struct GUID);
1313 if (!invocation_id_new) {
1317 *invocation_id_new = *invocation_id_in;
1319 /* cache the domain_sid in the ldb */
1320 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1324 talloc_steal(ldb, invocation_id_new);
1325 talloc_free(tmp_ctx);
1326 talloc_free(invocation_id_old);
1331 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1332 talloc_free(tmp_ctx);
1337 work out the ntds settings objectGUID for the current open ldb
1339 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1341 TALLOC_CTX *tmp_ctx;
1342 const char *attrs[] = { "objectGUID", NULL };
1344 struct ldb_result *res;
1345 struct GUID *ntds_guid;
1347 /* see if we have a cached copy */
1348 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1353 tmp_ctx = talloc_new(ldb);
1354 if (tmp_ctx == NULL) {
1358 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1363 if (res->count != 1) {
1367 ntds_guid = talloc(tmp_ctx, struct GUID);
1372 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1374 /* cache the domain_sid in the ldb */
1375 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1379 talloc_steal(ldb, ntds_guid);
1380 talloc_free(tmp_ctx);
1385 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1386 talloc_free(tmp_ctx);
1390 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1392 TALLOC_CTX *tmp_ctx;
1393 struct GUID *ntds_guid_new;
1394 struct GUID *ntds_guid_old;
1396 /* see if we have a cached copy */
1397 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1399 tmp_ctx = talloc_new(ldb);
1400 if (tmp_ctx == NULL) {
1404 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1405 if (!ntds_guid_new) {
1409 *ntds_guid_new = *ntds_guid_in;
1411 /* cache the domain_sid in the ldb */
1412 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1416 talloc_steal(ldb, ntds_guid_new);
1417 talloc_free(tmp_ctx);
1418 talloc_free(ntds_guid_old);
1423 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1424 talloc_free(tmp_ctx);
1429 work out the server dn for the current open ldb
1431 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1433 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1437 work out the server dn for the current open ldb
1439 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1441 struct ldb_dn *server_dn;
1442 struct ldb_dn *server_site_dn;
1444 server_dn = samdb_server_dn(ldb, mem_ctx);
1445 if (!server_dn) return NULL;
1447 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1449 talloc_free(server_dn);
1450 return server_site_dn;
1453 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1455 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
1458 return (const char *) val->data;
1464 work out if we are the PDC for the domain of the current open ldb
1466 bool samdb_is_pdc(struct ldb_context *ldb)
1468 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1470 struct ldb_result *dom_res;
1471 TALLOC_CTX *tmp_ctx;
1475 tmp_ctx = talloc_new(ldb);
1476 if (tmp_ctx == NULL) {
1477 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1481 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1483 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1484 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1485 ldb_errstring(ldb)));
1488 if (dom_res->count != 1) {
1492 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1494 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1500 talloc_free(tmp_ctx);
1505 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1506 talloc_free(tmp_ctx);
1511 work out if we are a Global Catalog server for the domain of the current open ldb
1513 bool samdb_is_gc(struct ldb_context *ldb)
1515 const char *attrs[] = { "options", NULL };
1517 struct ldb_result *res;
1518 TALLOC_CTX *tmp_ctx;
1520 tmp_ctx = talloc_new(ldb);
1521 if (tmp_ctx == NULL) {
1522 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1526 /* Query cn=ntds settings,.... */
1527 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1529 talloc_free(tmp_ctx);
1532 if (res->count != 1) {
1533 talloc_free(tmp_ctx);
1537 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1538 talloc_free(tmp_ctx);
1540 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1541 if (options & 0x000000001) {
1547 /* Find a domain object in the parents of a particular DN. */
1548 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1549 struct ldb_dn **parent_dn, const char **errstring)
1551 TALLOC_CTX *local_ctx;
1552 struct ldb_dn *sdn = dn;
1553 struct ldb_result *res = NULL;
1555 const char *attrs[] = { NULL };
1557 local_ctx = talloc_new(mem_ctx);
1558 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1560 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1561 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1562 "(|(objectClass=domain)(objectClass=builtinDomain))");
1563 if (ret == LDB_SUCCESS) {
1564 if (res->count == 1) {
1572 if (ret != LDB_SUCCESS) {
1573 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1574 ldb_dn_get_linearized(dn),
1575 ldb_dn_get_linearized(sdn),
1576 ldb_errstring(ldb));
1577 talloc_free(local_ctx);
1580 if (res->count != 1) {
1581 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1582 ldb_dn_get_linearized(dn));
1583 DEBUG(0,(__location__ ": %s\n", *errstring));
1584 talloc_free(local_ctx);
1585 return LDB_ERR_CONSTRAINT_VIOLATION;
1588 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1589 talloc_free(local_ctx);
1595 * Performs checks on a user password (plaintext UNIX format - attribute
1596 * "password"). The remaining parameters have to be extracted from the domain
1599 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1601 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1602 const uint32_t pwdProperties,
1603 const uint32_t minPwdLength)
1605 /* checks if the "minPwdLength" property is satisfied */
1606 if (minPwdLength > password->length)
1607 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1609 /* checks the password complexity */
1610 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1611 && (password->data != NULL)
1612 && (!check_password_quality((const char *) password->data)))
1613 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1615 return SAMR_VALIDATION_STATUS_SUCCESS;
1619 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1620 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1621 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1622 * gives some more informations if the changed failed.
1624 * The caller should have a LDB transaction wrapping this.
1626 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1627 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1628 * NT_STATUS_PASSWORD_RESTRICTION
1630 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1631 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1632 struct ldb_message *mod,
1633 const DATA_BLOB *new_password,
1634 struct samr_Password *param_lmNewHash,
1635 struct samr_Password *param_ntNewHash,
1637 enum samPwdChangeReason *reject_reason,
1638 struct samr_DomInfo1 **_dominfo)
1640 const char * const user_attrs[] = { "userAccountControl",
1643 "dBCSPwd", "unicodePwd",
1645 "pwdLastSet", NULL };
1646 const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1648 "maxPwdAge", "minPwdAge", NULL };
1650 uint32_t minPwdLength, pwdProperties, pwdHistoryLength;
1651 int64_t maxPwdAge, minPwdAge;
1652 uint32_t userAccountControl;
1653 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1654 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1655 struct samr_Password local_lmNewHash, local_ntNewHash;
1656 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1657 struct dom_sid *domain_sid;
1658 struct ldb_message **res;
1661 time_t now = time(NULL);
1665 /* we need to know the time to compute password age */
1666 unix_to_nt_time(&now_nt, now);
1668 /* pull all the user parameters */
1669 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1671 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1673 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1674 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1675 "lmPwdHistory", &sambaLMPwdHistory);
1676 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1677 "ntPwdHistory", &sambaNTPwdHistory);
1678 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1679 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1680 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1682 /* Copy parameters */
1683 lmNewHash = param_lmNewHash;
1684 ntNewHash = param_ntNewHash;
1686 /* Only non-trust accounts have restrictions (possibly this
1687 * test is the wrong way around, but I like to be restrictive
1689 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1690 |UF_WORKSTATION_TRUST_ACCOUNT
1691 |UF_SERVER_TRUST_ACCOUNT));
1693 if (domain_dn != NULL) {
1694 /* pull the domain parameters */
1695 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res,
1698 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1699 ldb_dn_get_linearized(domain_dn),
1700 ldb_dn_get_linearized(user_dn)));
1701 return NT_STATUS_NO_SUCH_DOMAIN;
1704 /* work out the domain sid, and pull the domain from there */
1705 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1707 if (domain_sid == NULL) {
1708 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1711 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1713 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1715 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1716 dom_sid_string(mem_ctx, domain_sid),
1717 ldb_dn_get_linearized(user_dn)));
1718 return NT_STATUS_NO_SUCH_DOMAIN;
1722 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1723 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1724 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1725 maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0);
1726 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1728 if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1729 /* see [MS-ADTS] 2.2.15 */
1733 if (_dominfo != NULL) {
1734 struct samr_DomInfo1 *dominfo;
1735 /* on failure we need to fill in the reject reasons */
1736 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1737 if (dominfo == NULL) {
1738 return NT_STATUS_NO_MEMORY;
1740 dominfo->min_password_length = minPwdLength;
1741 dominfo->password_properties = pwdProperties;
1742 dominfo->password_history_length = pwdHistoryLength;
1743 dominfo->max_password_age = maxPwdAge;
1744 dominfo->min_password_age = minPwdAge;
1745 *_dominfo = dominfo;
1748 if ((restrictions != 0) && (new_password != 0)) {
1751 /* checks if the "minPwdLength" property is satisfied */
1752 if ((restrictions != 0)
1753 && (minPwdLength > utf16_len_n(
1754 new_password->data, new_password->length)/2)) {
1755 if (reject_reason) {
1756 *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1758 return NT_STATUS_PASSWORD_RESTRICTION;
1761 /* Create the NT hash */
1762 mdfour(local_ntNewHash.hash, new_password->data,
1763 new_password->length);
1765 ntNewHash = &local_ntNewHash;
1767 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1768 if (convert_string_talloc_convenience(mem_ctx,
1769 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1771 new_password->data, new_password->length,
1772 (void **)&new_pass, NULL, false)) {
1774 /* checks the password complexity */
1775 if ((restrictions != 0)
1777 & DOMAIN_PASSWORD_COMPLEX) != 0)
1778 && (!check_password_quality(new_pass))) {
1779 if (reject_reason) {
1780 *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1782 return NT_STATUS_PASSWORD_RESTRICTION;
1785 /* compute the new lm hashes (for checking history - case insenitivly!) */
1786 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1787 lmNewHash = &local_lmNewHash;
1792 if ((restrictions != 0) && user_change) {
1793 /* are all password changes disallowed? */
1794 if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) {
1795 if (reject_reason) {
1796 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1798 return NT_STATUS_PASSWORD_RESTRICTION;
1801 /* can this user change the password? */
1802 if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) {
1803 if (reject_reason) {
1804 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1806 return NT_STATUS_PASSWORD_RESTRICTION;
1809 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1810 if (pwdLastSet - minPwdAge > now_nt) {
1811 if (reject_reason) {
1812 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1814 return NT_STATUS_PASSWORD_RESTRICTION;
1817 /* check the immediately past password */
1818 if (pwdHistoryLength > 0) {
1819 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash,
1820 lmPwdHash->hash, 16) == 0) {
1821 if (reject_reason) {
1822 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1824 return NT_STATUS_PASSWORD_RESTRICTION;
1826 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash,
1827 ntPwdHash->hash, 16) == 0) {
1828 if (reject_reason) {
1829 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1831 return NT_STATUS_PASSWORD_RESTRICTION;
1835 /* check the password history */
1836 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len,
1838 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1841 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1842 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
1844 if (reject_reason) {
1845 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1847 return NT_STATUS_PASSWORD_RESTRICTION;
1850 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1851 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash,
1853 if (reject_reason) {
1854 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1856 return NT_STATUS_PASSWORD_RESTRICTION;
1861 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1863 /* the password is acceptable. Start forming the new fields */
1864 if (new_password != NULL) {
1865 /* if we know the cleartext UTF16 password, then set it.
1866 * Modules in ldb will set all the appropriate
1868 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1870 /* We don't have the cleartext, so delete the old one
1871 * and set what we have of the hashes */
1872 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1875 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1877 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1881 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1883 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1887 if (reject_reason) {
1888 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1890 return NT_STATUS_OK;
1895 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1896 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1897 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1898 * gives some more informations if the changed failed.
1900 * This wrapper function for "samdb_set_password" takes a SID as input rather
1903 * This call encapsulates a new LDB transaction for changing the password;
1904 * therefore the user hasn't to start a new one.
1906 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1907 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1908 * NT_STATUS_PASSWORD_RESTRICTION
1910 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1911 const struct dom_sid *user_sid,
1912 const DATA_BLOB *new_password,
1913 struct samr_Password *lmNewHash,
1914 struct samr_Password *ntNewHash,
1916 enum samPwdChangeReason *reject_reason,
1917 struct samr_DomInfo1 **_dominfo)
1920 struct ldb_dn *user_dn;
1921 struct ldb_message *msg;
1924 ret = ldb_transaction_start(ldb);
1925 if (ret != LDB_SUCCESS) {
1926 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
1927 return NT_STATUS_TRANSACTION_ABORTED;
1930 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
1931 "(&(objectSid=%s)(objectClass=user))",
1932 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1934 ldb_transaction_cancel(ldb);
1935 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1936 dom_sid_string(mem_ctx, user_sid)));
1937 return NT_STATUS_NO_SUCH_USER;
1940 msg = ldb_msg_new(mem_ctx);
1942 ldb_transaction_cancel(ldb);
1943 return NT_STATUS_NO_MEMORY;
1946 msg->dn = ldb_dn_copy(msg, user_dn);
1948 ldb_transaction_cancel(ldb);
1949 return NT_STATUS_NO_MEMORY;
1952 nt_status = samdb_set_password(ldb, mem_ctx,
1955 lmNewHash, ntNewHash,
1956 user_change, /* This is a password set, not change */
1957 reject_reason, _dominfo);
1958 if (!NT_STATUS_IS_OK(nt_status)) {
1959 ldb_transaction_cancel(ldb);
1963 /* modify the samdb record */
1964 ret = samdb_replace(ldb, mem_ctx, msg);
1965 if (ret != LDB_SUCCESS) {
1966 ldb_transaction_cancel(ldb);
1967 return NT_STATUS_ACCESS_DENIED;
1970 ret = ldb_transaction_commit(ldb);
1971 if (ret != LDB_SUCCESS) {
1972 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1973 ldb_dn_get_linearized(msg->dn),
1974 ldb_errstring(ldb)));
1975 return NT_STATUS_TRANSACTION_ABORTED;
1977 return NT_STATUS_OK;
1981 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1982 struct dom_sid *sid, struct ldb_dn **ret_dn)
1984 struct ldb_message *msg;
1985 struct ldb_dn *basedn;
1989 sidstr = dom_sid_string(mem_ctx, sid);
1990 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1992 /* We might have to create a ForeignSecurityPrincipal, even if this user
1993 * is in our own domain */
1995 msg = ldb_msg_new(mem_ctx);
1997 return NT_STATUS_NO_MEMORY;
2000 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2001 * put the ForeignSecurityPrincipals? d_state->domain_dn does
2002 * not work, this is wrong for the Builtin domain, there's no
2003 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
2006 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
2007 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
2009 if (basedn == NULL) {
2010 DEBUG(0, ("Failed to find DN for "
2011 "ForeignSecurityPrincipal container\n"));
2012 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2015 /* add core elements to the ldb_message for the alias */
2016 msg->dn = ldb_dn_copy(mem_ctx, basedn);
2017 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
2018 return NT_STATUS_NO_MEMORY;
2020 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
2022 "foreignSecurityPrincipal");
2024 /* create the alias */
2025 ret = ldb_add(sam_ctx, msg);
2027 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2029 ldb_dn_get_linearized(msg->dn),
2030 ldb_errstring(sam_ctx)));
2031 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2034 return NT_STATUS_OK;
2039 Find the DN of a domain, assuming it to be a dotted.dns name
2042 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2045 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2046 const char *binary_encoded;
2047 const char **split_realm;
2054 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2056 talloc_free(tmp_ctx);
2059 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2060 for (i=0; split_realm[i]; i++) {
2061 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2062 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2063 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2064 binary_encoded, ldb_dn_get_linearized(dn)));
2065 talloc_free(tmp_ctx);
2069 if (!ldb_dn_validate(dn)) {
2070 DEBUG(2, ("Failed to validated DN %s\n",
2071 ldb_dn_get_linearized(dn)));
2077 Find the DN of a domain, be it the netbios or DNS name
2080 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2081 const char *domain_name)
2083 const char * const domain_ref_attrs[] = {
2086 const char * const domain_ref2_attrs[] = {
2089 struct ldb_result *res_domain_ref;
2090 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2091 /* find the domain's DN */
2092 int ret_domain = ldb_search(ldb, mem_ctx,
2094 samdb_partitions_dn(ldb, mem_ctx),
2097 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2099 if (ret_domain != 0) {
2103 if (res_domain_ref->count == 0) {
2104 ret_domain = ldb_search(ldb, mem_ctx,
2106 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2109 "(objectclass=domain)");
2110 if (ret_domain != 0) {
2114 if (res_domain_ref->count == 1) {
2115 return res_domain_ref->msgs[0]->dn;
2120 if (res_domain_ref->count > 1) {
2121 DEBUG(0,("Found %d records matching domain [%s]\n",
2122 ret_domain, domain_name));
2126 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2132 use a GUID to find a DN
2134 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2135 TALLOC_CTX *mem_ctx,
2136 const char *guid_str, struct ldb_dn **dn)
2139 struct ldb_result *res;
2140 const char *attrs[] = { NULL };
2141 struct ldb_request *search_req;
2143 struct ldb_search_options_control *options;
2145 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2147 DEBUG(0, (__location__ ": out of memory\n"));
2148 return LDB_ERR_OPERATIONS_ERROR;
2151 res = talloc_zero(mem_ctx, struct ldb_result);
2153 DEBUG(0, (__location__ ": out of memory\n"));
2154 return LDB_ERR_OPERATIONS_ERROR;
2157 ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2158 ldb_get_default_basedn(ldb),
2162 res, ldb_search_default_callback,
2164 if (ret != LDB_SUCCESS) {
2168 /* we need to cope with cross-partition links, so search for
2169 the GUID over all partitions */
2170 options = talloc(search_req, struct ldb_search_options_control);
2171 if (options == NULL) {
2172 DEBUG(0, (__location__ ": out of memory\n"));
2173 return LDB_ERR_OPERATIONS_ERROR;
2175 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2177 ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2178 if (ret != LDB_SUCCESS) {
2182 ret = ldb_request_add_control(search_req,
2183 LDB_CONTROL_SEARCH_OPTIONS_OID,
2185 if (ret != LDB_SUCCESS) {
2189 ret = ldb_request(ldb, search_req);
2190 if (ret != LDB_SUCCESS) {
2194 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2195 if (ret != LDB_SUCCESS) {
2199 /* this really should be exactly 1, but there is a bug in the
2200 partitions module that can return two here with the
2201 search_options control set */
2202 if (res->count < 1) {
2203 return LDB_ERR_NO_SUCH_OBJECT;
2206 *dn = res->msgs[0]->dn;
2212 search for attrs on one DN, allowing for deleted objects
2214 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2215 TALLOC_CTX *mem_ctx,
2216 struct ldb_result **_res,
2217 struct ldb_dn *basedn,
2218 const char * const *attrs)
2221 struct ldb_request *req;
2222 TALLOC_CTX *tmp_ctx;
2223 struct ldb_result *res;
2225 tmp_ctx = talloc_new(mem_ctx);
2227 res = talloc_zero(tmp_ctx, struct ldb_result);
2229 return LDB_ERR_OPERATIONS_ERROR;
2232 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2239 ldb_search_default_callback,
2241 if (ret != LDB_SUCCESS) {
2242 talloc_free(tmp_ctx);
2246 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2247 if (ret != LDB_SUCCESS) {
2251 ret = ldb_request(ldb, req);
2252 if (ret == LDB_SUCCESS) {
2253 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2257 *_res = talloc_steal(mem_ctx, res);
2263 use a DN to find a GUID
2265 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2266 struct ldb_dn *dn, struct GUID *guid)
2269 struct ldb_result *res;
2270 const char *attrs[] = { "objectGUID", NULL };
2271 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2273 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2274 if (ret != LDB_SUCCESS) {
2275 talloc_free(tmp_ctx);
2278 if (res->count < 1) {
2279 talloc_free(tmp_ctx);
2280 return LDB_ERR_NO_SUCH_OBJECT;
2282 *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2283 talloc_free(tmp_ctx);
2289 Use a DN to find it's parentGUID
2292 LDB_ERR_OPERATIONS_ERROR for out of memory
2293 LDB_ERR_NO_SUCH_OBJECT if there is no parent object for the given DN
2294 LDB_ERR_NO_SUCH_ATTRIBUTE if couldn't get the ObjectGUID from the parent
2295 LDB_SUCCESS if it could find the parentGUID correctly
2297 int dsdb_find_parentguid_by_dn(struct ldb_context *ldb,
2299 struct GUID *parent_guid)
2303 struct ldb_result *res;
2304 struct ldb_dn *parent_dn;
2305 const char *attrs[] = { "objectGUID", NULL };
2306 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2309 parent_dn = ldb_dn_get_parent(tmp_ctx, dn);
2311 if (parent_dn == NULL){
2312 DEBUG(4,(__location__ ": Failed to find parent for dn %s\n",
2313 ldb_dn_get_linearized(dn)));
2314 ret = LDB_ERR_NO_SUCH_OBJECT;
2319 The few lines of code bellow are very similar to the
2320 dsdb_find_guid_by_dn() function implementation, but this way we can
2321 differ situations when the parent_dn doesn't exist from when there is
2322 an error on returning it's GUID.
2324 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, parent_dn, attrs);
2325 if (ret != LDB_SUCCESS) {
2326 DEBUG(4,(__location__ ": Parent dn for %s does not exist \n",
2327 ldb_dn_get_linearized(dn)));
2328 /* When there is no parent dn, it simply doesn't return a parentGUID */
2329 ret = LDB_ERR_NO_SUCH_OBJECT;
2332 if (res->count < 1) {
2333 DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
2334 ldb_dn_get_linearized(parent_dn)));
2335 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
2339 *parent_guid = samdb_result_guid(res->msgs[0], "objectGUID");
2343 talloc_free(tmp_ctx);
2348 adds the given GUID to the given ldb_message. This value is added
2349 for the given attr_name (may be either "objectGUID" or "parentGUID").
2351 int dsdb_msg_add_guid(struct ldb_message *msg,
2353 const char *attr_name)
2356 enum ndr_err_code ndr_err;
2359 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2361 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, NULL,
2363 (ndr_push_flags_fn_t)ndr_push_GUID);
2365 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2366 ret = LDB_ERR_OPERATIONS_ERROR;
2370 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2371 if (ret != LDB_SUCCESS) {
2372 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2380 talloc_free(tmp_ctx);
2387 use a DN to find a SID
2389 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2390 struct ldb_dn *dn, struct dom_sid *sid)
2393 struct ldb_result *res;
2394 const char *attrs[] = { "objectSID", NULL };
2395 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2400 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2401 if (ret != LDB_SUCCESS) {
2402 talloc_free(tmp_ctx);
2405 if (res->count < 1) {
2406 talloc_free(tmp_ctx);
2407 return LDB_ERR_NO_SUCH_OBJECT;
2409 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2411 talloc_free(tmp_ctx);
2412 return LDB_ERR_NO_SUCH_OBJECT;
2415 talloc_free(tmp_ctx);
2422 load a repsFromTo blob list for a given partition GUID
2423 attr must be "repsFrom" or "repsTo"
2425 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2426 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2428 const char *attrs[] = { attr, NULL };
2429 struct ldb_result *res = NULL;
2430 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2432 struct ldb_message_element *el;
2437 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2439 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2440 talloc_free(tmp_ctx);
2441 return WERR_DS_DRA_INTERNAL_ERROR;
2444 el = ldb_msg_find_element(res->msgs[0], attr);
2446 /* it's OK to be empty */
2447 talloc_free(tmp_ctx);
2451 *count = el->num_values;
2452 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2454 talloc_free(tmp_ctx);
2455 return WERR_DS_DRA_INTERNAL_ERROR;
2458 for (i=0; i<(*count); i++) {
2459 enum ndr_err_code ndr_err;
2460 ndr_err = ndr_pull_struct_blob(&el->values[i],
2461 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2463 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2464 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2465 talloc_free(tmp_ctx);
2466 return WERR_DS_DRA_INTERNAL_ERROR;
2470 talloc_free(tmp_ctx);
2476 save the repsFromTo blob list for a given partition GUID
2477 attr must be "repsFrom" or "repsTo"
2479 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2480 const char *attr, struct repsFromToBlob *r, uint32_t count)
2482 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2483 struct ldb_message *msg;
2484 struct ldb_message_element *el;
2487 msg = ldb_msg_new(tmp_ctx);
2489 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2493 el->values = talloc_array(msg, struct ldb_val, count);
2498 for (i=0; i<count; i++) {
2500 enum ndr_err_code ndr_err;
2502 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2504 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2505 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2513 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2514 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2518 talloc_free(tmp_ctx);
2523 talloc_free(tmp_ctx);
2524 return WERR_DS_DRA_INTERNAL_ERROR;
2529 load the uSNHighest attribute from the @REPLCHANGED object for a
2532 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2534 struct ldb_request *req;
2536 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2537 struct dsdb_control_current_partition *p_ctrl;
2538 struct ldb_result *res;
2540 res = talloc_zero(tmp_ctx, struct ldb_result);
2542 talloc_free(tmp_ctx);
2543 return LDB_ERR_OPERATIONS_ERROR;
2546 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2547 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2551 res, ldb_search_default_callback,
2553 if (ret != LDB_SUCCESS) {
2554 talloc_free(tmp_ctx);
2558 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2559 if (p_ctrl == NULL) {
2561 return LDB_ERR_OPERATIONS_ERROR;
2563 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2567 ret = ldb_request_add_control(req,
2568 DSDB_CONTROL_CURRENT_PARTITION_OID,
2570 if (ret != LDB_SUCCESS) {
2571 talloc_free(tmp_ctx);
2575 /* Run the new request */
2576 ret = ldb_request(ldb, req);
2578 if (ret == LDB_SUCCESS) {
2579 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2582 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2583 /* it hasn't been created yet, which means
2584 an implicit value of zero */
2586 talloc_free(tmp_ctx);
2590 if (ret != LDB_SUCCESS) {
2591 talloc_free(tmp_ctx);
2595 if (res->count < 1) {
2598 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2601 talloc_free(tmp_ctx);
2607 save the uSNHighest attribute in the @REPLCHANGED object for a
2610 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2612 struct ldb_request *req;
2613 struct ldb_message *msg;
2614 struct dsdb_control_current_partition *p_ctrl;
2617 msg = ldb_msg_new(ldb);
2619 return LDB_ERR_OPERATIONS_ERROR;
2622 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2623 if (msg->dn == NULL) {
2625 return LDB_ERR_OPERATIONS_ERROR;
2628 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2629 if (ret != LDB_SUCCESS) {
2633 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2636 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2637 if (p_ctrl == NULL) {
2639 return LDB_ERR_OPERATIONS_ERROR;
2641 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2644 ret = ldb_build_mod_req(&req, ldb, msg,
2647 NULL, ldb_op_default_callback,
2650 if (ret != LDB_SUCCESS) {
2655 ret = ldb_request_add_control(req,
2656 DSDB_CONTROL_CURRENT_PARTITION_OID,
2658 if (ret != LDB_SUCCESS) {
2663 /* Run the new request */
2664 ret = ldb_request(ldb, req);
2666 if (ret == LDB_SUCCESS) {
2667 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2669 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2670 ret = ldb_build_add_req(&req, ldb, msg,
2673 NULL, ldb_op_default_callback,
2683 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2684 const struct drsuapi_DsReplicaCursor2 *c2)
2686 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2690 see if we are a RODC
2692 TODO: This should take a sam_ctx, and lookup the right object (with
2695 bool samdb_rodc(struct loadparm_context *lp_ctx)
2697 return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false);
2702 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2704 flags are DS_NTDS_OPTION_*
2706 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2708 TALLOC_CTX *tmp_ctx;
2709 const char *attrs[] = { "options", NULL };
2711 struct ldb_result *res;
2713 tmp_ctx = talloc_new(ldb);
2714 if (tmp_ctx == NULL) {
2718 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2723 if (res->count != 1) {
2727 *options = samdb_result_uint(res->msgs[0], "options", 0);
2729 talloc_free(tmp_ctx);
2734 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2735 talloc_free(tmp_ctx);
2736 return LDB_ERR_NO_SUCH_OBJECT;
2740 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2741 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2743 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2745 char **tokens, *ret;
2748 tokens = str_list_make(mem_ctx, cn, " -_");
2752 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2753 tokens[0][0] = tolower(tokens[0][0]);
2754 for (i = 1; i < str_list_length((const char **)tokens); i++)
2755 tokens[i][0] = toupper(tokens[i][0]);
2757 ret = talloc_strdup(mem_ctx, tokens[0]);
2758 for (i = 1; i < str_list_length((const char **)tokens); i++)
2759 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2761 talloc_free(tokens);