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,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
194 struct ldb_message **res;
195 const char *attrs[] = { NULL };
197 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
199 va_start(ap, format);
200 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
202 talloc_free(tmp_ctx);
209 search the sam for a single integer attribute in exactly 1 record
211 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
213 uint_t default_value,
214 struct ldb_dn *basedn,
215 const char *attr_name,
216 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
220 struct ldb_message **res;
221 const char *attrs[2] = { NULL, NULL };
223 attrs[0] = attr_name;
225 va_start(ap, format);
226 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
230 return default_value;
233 return samdb_result_uint(res[0], attr_name, default_value);
237 search the sam for a single signed 64 bit integer attribute in exactly 1 record
239 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
241 int64_t default_value,
242 struct ldb_dn *basedn,
243 const char *attr_name,
244 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
248 struct ldb_message **res;
249 const char *attrs[2] = { NULL, NULL };
251 attrs[0] = attr_name;
253 va_start(ap, format);
254 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
258 return default_value;
261 return samdb_result_int64(res[0], attr_name, default_value);
265 search the sam for multipe records each giving a single string attribute
266 return the number of matches, or -1 on error
268 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
270 struct ldb_dn *basedn,
272 const char *attr_name,
273 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
277 const char *attrs[2] = { NULL, NULL };
278 struct ldb_message **res = NULL;
280 attrs[0] = attr_name;
282 va_start(ap, format);
283 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
290 /* make sure its single valued */
291 for (i=0;i<count;i++) {
292 if (res[i]->num_elements != 1) {
293 DEBUG(1,("samdb: search for %s %s not single valued\n",
300 *strs = talloc_array(mem_ctx, const char *, count+1);
306 for (i=0;i<count;i++) {
307 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
309 (*strs)[count] = NULL;
315 pull a uint from a result set.
317 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
319 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
323 pull a (signed) int64 from a result set.
325 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
327 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
331 pull a string from a result set.
333 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
334 const char *default_value)
336 return ldb_msg_find_attr_as_string(msg, attr, default_value);
339 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
340 const char *attr, struct ldb_dn *default_value)
342 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
344 return default_value;
350 pull a rid from a objectSid in a result set.
352 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
353 const char *attr, uint32_t default_value)
358 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
360 return default_value;
362 rid = sid->sub_auths[sid->num_auths-1];
368 pull a dom_sid structure from a objectSid in a result set.
370 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
373 const struct ldb_val *v;
375 enum ndr_err_code ndr_err;
376 v = ldb_msg_find_ldb_val(msg, attr);
380 sid = talloc(mem_ctx, struct dom_sid);
384 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
385 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
386 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
394 pull a guid structure from a objectGUID in a result set.
396 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
398 const struct ldb_val *v;
399 enum ndr_err_code ndr_err;
405 v = ldb_msg_find_ldb_val(msg, attr);
408 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
409 if (!mem_ctx) return guid;
410 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
411 (ndr_pull_flags_fn_t)ndr_pull_GUID);
412 talloc_free(mem_ctx);
413 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
421 pull a sid prefix from a objectSid in a result set.
422 this is used to find the domain sid for a user
424 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
427 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
428 if (!sid || sid->num_auths < 1) return NULL;
434 pull a NTTIME in a result set.
436 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
438 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
442 * Windows stores 0 for lastLogoff.
443 * But when a MS DC return the lastLogoff (as Logoff Time)
444 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
445 * cause windows 2008 and newer version to fail for SMB requests
447 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
449 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
452 ret = 0x7FFFFFFFFFFFFFFFULL;
458 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
459 * indicate an account doesn't expire.
461 * When Windows initially creates an account, it sets
462 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
463 * when changing from an account having a specific expiration date to
464 * that account never expiring, it sets accountExpires = 0.
466 * Consolidate that logic here to allow clearer logic for account expiry in
467 * the rest of the code.
469 NTTIME samdb_result_account_expires(struct ldb_message *msg)
471 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
475 ret = 0x7FFFFFFFFFFFFFFFULL;
481 pull a uint64_t from a result set.
483 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
485 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
490 construct the allow_password_change field from the PwdLastSet attribute and the
491 domain password settings
493 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
495 struct ldb_dn *domain_dn,
496 struct ldb_message *msg,
499 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
502 if (attr_time == 0) {
506 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
508 /* yes, this is a -= not a += as minPwdAge is stored as the negative
509 of the number of 100-nano-seconds */
510 attr_time -= minPwdAge;
516 construct the force_password_change field from the PwdLastSet
517 attribute, the userAccountControl and the domain password settings
519 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
521 struct ldb_dn *domain_dn,
522 struct ldb_message *msg)
524 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
525 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
528 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
529 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
530 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
531 return 0x7FFFFFFFFFFFFFFFULL;
534 if (attr_time == 0) {
538 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
539 if (maxPwdAge == 0) {
540 return 0x7FFFFFFFFFFFFFFFULL;
542 attr_time -= maxPwdAge;
549 pull a samr_Password structutre from a result set.
551 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
553 struct samr_Password *hash = NULL;
554 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
555 if (val && (val->length >= sizeof(hash->hash))) {
556 hash = talloc(mem_ctx, struct samr_Password);
557 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
563 pull an array of samr_Password structutres from a result set.
565 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
566 const char *attr, struct samr_Password **hashes)
569 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
575 count = val->length / 16;
580 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
585 for (i=0;i<count;i++) {
586 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
592 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
593 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
595 struct samr_Password *lmPwdHash, *ntPwdHash;
598 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
601 } else if (num_nt > 1) {
602 return NT_STATUS_INTERNAL_DB_CORRUPTION;
604 *nt_pwd = &ntPwdHash[0];
608 /* Ensure that if we have turned off LM
609 * authentication, that we never use the LM hash, even
611 if (lp_lanman_auth(lp_ctx)) {
613 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
616 } else if (num_lm > 1) {
617 return NT_STATUS_INTERNAL_DB_CORRUPTION;
619 *lm_pwd = &lmPwdHash[0];
629 pull a samr_LogonHours structutre from a result set.
631 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
633 struct samr_LogonHours hours;
634 const int units_per_week = 168;
635 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
637 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
641 hours.units_per_week = units_per_week;
642 memset(hours.bits, 0xFF, units_per_week);
644 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
650 pull a set of account_flags from a result set.
652 This requires that the attributes:
657 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
658 struct ldb_message *msg, struct ldb_dn *domain_dn)
660 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
661 uint32_t acct_flags = ds_uf2acb(userAccountControl);
662 NTTIME must_change_time;
665 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
668 /* Test account expire time */
669 unix_to_nt_time(&now, time(NULL));
670 /* check for expired password */
671 if (must_change_time < now) {
672 acct_flags |= ACB_PW_EXPIRED;
677 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
678 struct ldb_message *msg,
681 struct lsa_BinaryString s;
682 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
690 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
694 s.length = s.size = val->length/2;
695 memcpy(s.array, val->data, val->length);
700 /* Find an attribute, with a particular value */
702 /* The current callers of this function expect a very specific
703 * behaviour: In particular, objectClass subclass equivilance is not
704 * wanted. This means that we should not lookup the schema for the
705 * comparison function */
706 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
707 const struct ldb_message *msg,
708 const char *name, const char *value)
711 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
717 for (i=0;i<el->num_values;i++) {
718 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
726 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
728 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
729 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
734 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
736 struct ldb_message_element *el;
738 el = ldb_msg_find_element(msg, name);
743 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
749 add a string element to a message
751 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
752 const char *attr_name, const char *str)
754 char *s = talloc_strdup(mem_ctx, str);
755 char *a = talloc_strdup(mem_ctx, attr_name);
756 if (s == NULL || a == NULL) {
757 return LDB_ERR_OPERATIONS_ERROR;
759 return ldb_msg_add_string(msg, a, s);
763 add a dom_sid element to a message
765 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
766 const char *attr_name, struct dom_sid *sid)
769 enum ndr_err_code ndr_err;
771 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
772 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
774 (ndr_push_flags_fn_t)ndr_push_dom_sid);
775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
778 return ldb_msg_add_value(msg, attr_name, &v, NULL);
783 add a delete element operation to a message
785 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
786 const char *attr_name)
788 /* we use an empty replace rather than a delete, as it allows for
789 samdb_replace() to be used everywhere */
790 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
794 add a add attribute value to a message
796 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
797 const char *attr_name, const char *value)
799 struct ldb_message_element *el;
802 a = talloc_strdup(mem_ctx, attr_name);
805 v = talloc_strdup(mem_ctx, value);
808 ret = ldb_msg_add_string(msg, a, v);
811 el = ldb_msg_find_element(msg, a);
814 el->flags = LDB_FLAG_MOD_ADD;
819 add a delete attribute value to a message
821 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
822 const char *attr_name, const char *value)
824 struct ldb_message_element *el;
827 a = talloc_strdup(mem_ctx, attr_name);
830 v = talloc_strdup(mem_ctx, value);
833 ret = ldb_msg_add_string(msg, a, v);
836 el = ldb_msg_find_element(msg, a);
839 el->flags = LDB_FLAG_MOD_DELETE;
844 add a int element to a message
846 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
847 const char *attr_name, int v)
849 const char *s = talloc_asprintf(mem_ctx, "%d", v);
850 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
854 add a uint_t element to a message
856 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
857 const char *attr_name, uint_t v)
859 const char *s = talloc_asprintf(mem_ctx, "%u", v);
860 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
864 add a (signed) int64_t element to a message
866 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
867 const char *attr_name, int64_t v)
869 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
870 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
874 add a uint64_t element to a message
876 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
877 const char *attr_name, uint64_t v)
879 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
880 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
884 add a samr_Password element to a message
886 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
887 const char *attr_name, struct samr_Password *hash)
890 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
895 return ldb_msg_add_value(msg, attr_name, &val, NULL);
899 add a samr_Password array to a message
901 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
902 const char *attr_name, struct samr_Password *hashes, uint_t count)
906 val.data = talloc_array_size(mem_ctx, 16, count);
907 val.length = count*16;
911 for (i=0;i<count;i++) {
912 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
914 return ldb_msg_add_value(msg, attr_name, &val, NULL);
918 add a acct_flags element to a message
920 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
921 const char *attr_name, uint32_t v)
923 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
927 add a logon_hours element to a message
929 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
930 const char *attr_name, struct samr_LogonHours *hours)
933 val.length = hours->units_per_week / 8;
934 val.data = hours->bits;
935 return ldb_msg_add_value(msg, attr_name, &val, NULL);
939 add a parameters element to a message
941 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
942 const char *attr_name, struct lsa_BinaryString *parameters)
945 val.length = parameters->length * 2;
946 val.data = (uint8_t *)parameters->array;
947 return ldb_msg_add_value(msg, attr_name, &val, NULL);
950 add a general value element to a message
952 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
953 const char *attr_name, const struct ldb_val *val)
955 return ldb_msg_add_value(msg, attr_name, val, NULL);
959 sets a general value element to a message
961 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
962 const char *attr_name, const struct ldb_val *val)
964 struct ldb_message_element *el;
966 el = ldb_msg_find_element(msg, attr_name);
970 return ldb_msg_add_value(msg, attr_name, val, NULL);
974 set a string element in a message
976 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
977 const char *attr_name, const char *str)
979 struct ldb_message_element *el;
981 el = ldb_msg_find_element(msg, attr_name);
985 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
989 replace elements in a record
991 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
995 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
996 for (i=0;i<msg->num_elements;i++) {
997 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1000 /* modify the samdb record */
1001 return ldb_modify(sam_ldb, msg);
1005 return a default security descriptor
1007 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1009 struct security_descriptor *sd;
1011 sd = security_descriptor_initialise(mem_ctx);
1016 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1018 return ldb_get_default_basedn(sam_ctx);
1021 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1023 return ldb_get_config_basedn(sam_ctx);
1026 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1028 return ldb_get_schema_basedn(sam_ctx);
1031 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1033 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1034 struct ldb_dn *aggregate_dn;
1039 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1040 if (!aggregate_dn) {
1043 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1046 return aggregate_dn;
1049 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1051 return ldb_get_root_basedn(sam_ctx);
1054 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1056 struct ldb_dn *new_dn;
1058 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1059 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1060 talloc_free(new_dn);
1066 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1068 struct ldb_dn *new_dn;
1070 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1071 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1072 talloc_free(new_dn);
1079 work out the domain sid for the current open ldb
1081 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1083 TALLOC_CTX *tmp_ctx;
1084 const struct dom_sid *domain_sid;
1085 const char *attrs[] = {
1089 struct ldb_result *res;
1092 /* see if we have a cached copy */
1093 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1098 tmp_ctx = talloc_new(ldb);
1099 if (tmp_ctx == NULL) {
1103 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1105 if (ret != LDB_SUCCESS) {
1109 if (res->count != 1) {
1113 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1114 if (domain_sid == NULL) {
1118 /* cache the domain_sid in the ldb */
1119 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1123 talloc_steal(ldb, domain_sid);
1124 talloc_free(tmp_ctx);
1129 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1130 talloc_free(tmp_ctx);
1134 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1136 TALLOC_CTX *tmp_ctx;
1137 struct dom_sid *dom_sid_new;
1138 struct dom_sid *dom_sid_old;
1140 /* see if we have a cached copy */
1141 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1142 "cache.domain_sid"), struct dom_sid);
1144 tmp_ctx = talloc_new(ldb);
1145 if (tmp_ctx == NULL) {
1149 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1154 /* cache the domain_sid in the ldb */
1155 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1159 talloc_steal(ldb, dom_sid_new);
1160 talloc_free(tmp_ctx);
1161 talloc_free(dom_sid_old);
1166 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1167 talloc_free(tmp_ctx);
1171 /* Obtain the short name of the flexible single master operator
1172 * (FSMO), such as the PDC Emulator */
1173 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1176 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1177 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1178 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1179 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1181 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1182 /* Ensure this matches the format. This gives us a
1183 * bit more confidence that a 'cn' value will be a
1188 return (char *)val->data;
1194 work out the ntds settings dn for the current open ldb
1196 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1198 TALLOC_CTX *tmp_ctx;
1199 const char *root_attrs[] = { "dsServiceName", NULL };
1201 struct ldb_result *root_res;
1202 struct ldb_dn *settings_dn;
1204 /* see if we have a cached copy */
1205 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1210 tmp_ctx = talloc_new(ldb);
1211 if (tmp_ctx == NULL) {
1215 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1217 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1218 ldb_errstring(ldb)));
1222 if (root_res->count != 1) {
1226 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1228 /* cache the domain_sid in the ldb */
1229 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1233 talloc_steal(ldb, settings_dn);
1234 talloc_free(tmp_ctx);
1239 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1240 talloc_free(tmp_ctx);
1245 work out the ntds settings invocationId for the current open ldb
1247 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1249 TALLOC_CTX *tmp_ctx;
1250 const char *attrs[] = { "invocationId", NULL };
1252 struct ldb_result *res;
1253 struct GUID *invocation_id;
1255 /* see if we have a cached copy */
1256 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1257 if (invocation_id) {
1258 return invocation_id;
1261 tmp_ctx = talloc_new(ldb);
1262 if (tmp_ctx == NULL) {
1266 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1271 if (res->count != 1) {
1275 invocation_id = talloc(tmp_ctx, struct GUID);
1276 if (!invocation_id) {
1280 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1282 /* cache the domain_sid in the ldb */
1283 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1287 talloc_steal(ldb, invocation_id);
1288 talloc_free(tmp_ctx);
1290 return invocation_id;
1293 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1294 talloc_free(tmp_ctx);
1298 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1300 TALLOC_CTX *tmp_ctx;
1301 struct GUID *invocation_id_new;
1302 struct GUID *invocation_id_old;
1304 /* see if we have a cached copy */
1305 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1306 "cache.invocation_id");
1308 tmp_ctx = talloc_new(ldb);
1309 if (tmp_ctx == NULL) {
1313 invocation_id_new = talloc(tmp_ctx, struct GUID);
1314 if (!invocation_id_new) {
1318 *invocation_id_new = *invocation_id_in;
1320 /* cache the domain_sid in the ldb */
1321 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1325 talloc_steal(ldb, invocation_id_new);
1326 talloc_free(tmp_ctx);
1327 talloc_free(invocation_id_old);
1332 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1333 talloc_free(tmp_ctx);
1338 work out the ntds settings objectGUID for the current open ldb
1340 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1342 TALLOC_CTX *tmp_ctx;
1343 const char *attrs[] = { "objectGUID", NULL };
1345 struct ldb_result *res;
1346 struct GUID *ntds_guid;
1348 /* see if we have a cached copy */
1349 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1354 tmp_ctx = talloc_new(ldb);
1355 if (tmp_ctx == NULL) {
1359 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1364 if (res->count != 1) {
1368 ntds_guid = talloc(tmp_ctx, struct GUID);
1373 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1375 /* cache the domain_sid in the ldb */
1376 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1380 talloc_steal(ldb, ntds_guid);
1381 talloc_free(tmp_ctx);
1386 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1387 talloc_free(tmp_ctx);
1391 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1393 TALLOC_CTX *tmp_ctx;
1394 struct GUID *ntds_guid_new;
1395 struct GUID *ntds_guid_old;
1397 /* see if we have a cached copy */
1398 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1400 tmp_ctx = talloc_new(ldb);
1401 if (tmp_ctx == NULL) {
1405 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1406 if (!ntds_guid_new) {
1410 *ntds_guid_new = *ntds_guid_in;
1412 /* cache the domain_sid in the ldb */
1413 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1417 talloc_steal(ldb, ntds_guid_new);
1418 talloc_free(tmp_ctx);
1419 talloc_free(ntds_guid_old);
1424 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1425 talloc_free(tmp_ctx);
1430 work out the server dn for the current open ldb
1432 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1434 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1438 work out the server dn for the current open ldb
1440 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1442 struct ldb_dn *server_dn;
1443 struct ldb_dn *server_site_dn;
1445 server_dn = samdb_server_dn(ldb, mem_ctx);
1446 if (!server_dn) return NULL;
1448 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1450 talloc_free(server_dn);
1451 return server_site_dn;
1454 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1456 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
1459 return (const char *) val->data;
1465 work out if we are the PDC for the domain of the current open ldb
1467 bool samdb_is_pdc(struct ldb_context *ldb)
1469 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1471 struct ldb_result *dom_res;
1472 TALLOC_CTX *tmp_ctx;
1476 tmp_ctx = talloc_new(ldb);
1477 if (tmp_ctx == NULL) {
1478 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1482 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1484 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1485 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1486 ldb_errstring(ldb)));
1489 if (dom_res->count != 1) {
1493 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1495 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1501 talloc_free(tmp_ctx);
1506 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1507 talloc_free(tmp_ctx);
1512 work out if we are a Global Catalog server for the domain of the current open ldb
1514 bool samdb_is_gc(struct ldb_context *ldb)
1516 const char *attrs[] = { "options", NULL };
1518 struct ldb_result *res;
1519 TALLOC_CTX *tmp_ctx;
1521 tmp_ctx = talloc_new(ldb);
1522 if (tmp_ctx == NULL) {
1523 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1527 /* Query cn=ntds settings,.... */
1528 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1530 talloc_free(tmp_ctx);
1533 if (res->count != 1) {
1534 talloc_free(tmp_ctx);
1538 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1539 talloc_free(tmp_ctx);
1541 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1542 if (options & 0x000000001) {
1548 /* Find a domain object in the parents of a particular DN. */
1549 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1550 struct ldb_dn **parent_dn, const char **errstring)
1552 TALLOC_CTX *local_ctx;
1553 struct ldb_dn *sdn = dn;
1554 struct ldb_result *res = NULL;
1556 const char *attrs[] = { NULL };
1558 local_ctx = talloc_new(mem_ctx);
1559 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1561 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1562 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1563 "(|(objectClass=domain)(objectClass=builtinDomain))");
1564 if (ret == LDB_SUCCESS) {
1565 if (res->count == 1) {
1573 if (ret != LDB_SUCCESS) {
1574 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1575 ldb_dn_get_linearized(dn),
1576 ldb_dn_get_linearized(sdn),
1577 ldb_errstring(ldb));
1578 talloc_free(local_ctx);
1581 if (res->count != 1) {
1582 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1583 ldb_dn_get_linearized(dn));
1584 DEBUG(0,(__location__ ": %s\n", *errstring));
1585 talloc_free(local_ctx);
1586 return LDB_ERR_CONSTRAINT_VIOLATION;
1589 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1590 talloc_free(local_ctx);
1596 * Performs checks on a user password (plaintext UNIX format - attribute
1597 * "password"). The remaining parameters have to be extracted from the domain
1600 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1602 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1603 const uint32_t pwdProperties,
1604 const uint32_t minPwdLength)
1606 /* checks if the "minPwdLength" property is satisfied */
1607 if (minPwdLength > password->length)
1608 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1610 /* checks the password complexity */
1611 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1612 && (password->data != NULL)
1613 && (!check_password_quality((const char *) password->data)))
1614 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1616 return SAMR_VALIDATION_STATUS_SUCCESS;
1620 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1621 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1622 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1623 * gives some more informations if the changed failed.
1625 * The caller should have a LDB transaction wrapping this.
1627 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1628 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1629 * NT_STATUS_PASSWORD_RESTRICTION
1631 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1632 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1633 struct ldb_message *mod,
1634 const DATA_BLOB *new_password,
1635 struct samr_Password *param_lmNewHash,
1636 struct samr_Password *param_ntNewHash,
1638 enum samPwdChangeReason *reject_reason,
1639 struct samr_DomInfo1 **_dominfo)
1641 const char * const user_attrs[] = { "userAccountControl",
1644 "dBCSPwd", "unicodePwd",
1646 "pwdLastSet", NULL };
1647 const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1649 "maxPwdAge", "minPwdAge", NULL };
1651 uint32_t minPwdLength, pwdProperties, pwdHistoryLength;
1652 int64_t maxPwdAge, minPwdAge;
1653 uint32_t userAccountControl;
1654 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1655 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1656 struct samr_Password local_lmNewHash, local_ntNewHash;
1657 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1658 struct dom_sid *domain_sid;
1659 struct ldb_message **res;
1662 time_t now = time(NULL);
1666 /* we need to know the time to compute password age */
1667 unix_to_nt_time(&now_nt, now);
1669 /* pull all the user parameters */
1670 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1674 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1675 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1676 "lmPwdHistory", &sambaLMPwdHistory);
1677 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1678 "ntPwdHistory", &sambaNTPwdHistory);
1679 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1680 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1681 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1683 /* Copy parameters */
1684 lmNewHash = param_lmNewHash;
1685 ntNewHash = param_ntNewHash;
1687 /* Only non-trust accounts have restrictions (possibly this
1688 * test is the wrong way around, but I like to be restrictive
1690 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1691 |UF_WORKSTATION_TRUST_ACCOUNT
1692 |UF_SERVER_TRUST_ACCOUNT));
1694 if (domain_dn != NULL) {
1695 /* pull the domain parameters */
1696 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res,
1699 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1700 ldb_dn_get_linearized(domain_dn),
1701 ldb_dn_get_linearized(user_dn)));
1702 return NT_STATUS_NO_SUCH_DOMAIN;
1705 /* work out the domain sid, and pull the domain from there */
1706 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1708 if (domain_sid == NULL) {
1709 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1712 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1714 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1716 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1717 dom_sid_string(mem_ctx, domain_sid),
1718 ldb_dn_get_linearized(user_dn)));
1719 return NT_STATUS_NO_SUCH_DOMAIN;
1723 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1724 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1725 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1726 maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0);
1727 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1729 if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1730 /* see [MS-ADTS] 2.2.15 */
1734 if (_dominfo != NULL) {
1735 struct samr_DomInfo1 *dominfo;
1736 /* on failure we need to fill in the reject reasons */
1737 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1738 if (dominfo == NULL) {
1739 return NT_STATUS_NO_MEMORY;
1741 dominfo->min_password_length = minPwdLength;
1742 dominfo->password_properties = pwdProperties;
1743 dominfo->password_history_length = pwdHistoryLength;
1744 dominfo->max_password_age = maxPwdAge;
1745 dominfo->min_password_age = minPwdAge;
1746 *_dominfo = dominfo;
1749 if ((restrictions != 0) && (new_password != 0)) {
1752 /* checks if the "minPwdLength" property is satisfied */
1753 if ((restrictions != 0)
1754 && (minPwdLength > utf16_len_n(
1755 new_password->data, new_password->length)/2)) {
1756 if (reject_reason) {
1757 *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1759 return NT_STATUS_PASSWORD_RESTRICTION;
1762 /* Create the NT hash */
1763 mdfour(local_ntNewHash.hash, new_password->data,
1764 new_password->length);
1766 ntNewHash = &local_ntNewHash;
1768 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1769 if (convert_string_talloc_convenience(mem_ctx,
1770 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1772 new_password->data, new_password->length,
1773 (void **)&new_pass, NULL, false)) {
1775 /* checks the password complexity */
1776 if ((restrictions != 0)
1778 & DOMAIN_PASSWORD_COMPLEX) != 0)
1779 && (!check_password_quality(new_pass))) {
1780 if (reject_reason) {
1781 *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1783 return NT_STATUS_PASSWORD_RESTRICTION;
1786 /* compute the new lm hashes (for checking history - case insenitivly!) */
1787 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1788 lmNewHash = &local_lmNewHash;
1793 if ((restrictions != 0) && user_change) {
1794 /* are all password changes disallowed? */
1795 if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) {
1796 if (reject_reason) {
1797 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1799 return NT_STATUS_PASSWORD_RESTRICTION;
1802 /* can this user change the password? */
1803 if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) {
1804 if (reject_reason) {
1805 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1807 return NT_STATUS_PASSWORD_RESTRICTION;
1810 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1811 if (pwdLastSet - minPwdAge > now_nt) {
1812 if (reject_reason) {
1813 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1815 return NT_STATUS_PASSWORD_RESTRICTION;
1818 /* check the immediately past password */
1819 if (pwdHistoryLength > 0) {
1820 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash,
1821 lmPwdHash->hash, 16) == 0) {
1822 if (reject_reason) {
1823 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1825 return NT_STATUS_PASSWORD_RESTRICTION;
1827 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash,
1828 ntPwdHash->hash, 16) == 0) {
1829 if (reject_reason) {
1830 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1832 return NT_STATUS_PASSWORD_RESTRICTION;
1836 /* check the password history */
1837 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len,
1839 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1842 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1843 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
1845 if (reject_reason) {
1846 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1848 return NT_STATUS_PASSWORD_RESTRICTION;
1851 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1852 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash,
1854 if (reject_reason) {
1855 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1857 return NT_STATUS_PASSWORD_RESTRICTION;
1862 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1864 /* the password is acceptable. Start forming the new fields */
1865 if (new_password != NULL) {
1866 /* if we know the cleartext UTF16 password, then set it.
1867 * Modules in ldb will set all the appropriate
1869 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1871 /* We don't have the cleartext, so delete the old one
1872 * and set what we have of the hashes */
1873 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1876 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1878 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1882 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1884 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1888 if (reject_reason) {
1889 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1891 return NT_STATUS_OK;
1896 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1897 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1898 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1899 * gives some more informations if the changed failed.
1901 * This wrapper function for "samdb_set_password" takes a SID as input rather
1904 * This call encapsulates a new LDB transaction for changing the password;
1905 * therefore the user hasn't to start a new one.
1907 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1908 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1909 * NT_STATUS_PASSWORD_RESTRICTION
1911 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1912 const struct dom_sid *user_sid,
1913 const DATA_BLOB *new_password,
1914 struct samr_Password *lmNewHash,
1915 struct samr_Password *ntNewHash,
1917 enum samPwdChangeReason *reject_reason,
1918 struct samr_DomInfo1 **_dominfo)
1921 struct ldb_dn *user_dn;
1922 struct ldb_message *msg;
1925 ret = ldb_transaction_start(ldb);
1926 if (ret != LDB_SUCCESS) {
1927 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
1928 return NT_STATUS_TRANSACTION_ABORTED;
1931 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
1932 "(&(objectSid=%s)(objectClass=user))",
1933 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1935 ldb_transaction_cancel(ldb);
1936 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1937 dom_sid_string(mem_ctx, user_sid)));
1938 return NT_STATUS_NO_SUCH_USER;
1941 msg = ldb_msg_new(mem_ctx);
1943 ldb_transaction_cancel(ldb);
1944 return NT_STATUS_NO_MEMORY;
1947 msg->dn = ldb_dn_copy(msg, user_dn);
1949 ldb_transaction_cancel(ldb);
1950 return NT_STATUS_NO_MEMORY;
1953 nt_status = samdb_set_password(ldb, mem_ctx,
1956 lmNewHash, ntNewHash,
1957 user_change, /* This is a password set, not change */
1958 reject_reason, _dominfo);
1959 if (!NT_STATUS_IS_OK(nt_status)) {
1960 ldb_transaction_cancel(ldb);
1964 /* modify the samdb record */
1965 ret = samdb_replace(ldb, mem_ctx, msg);
1966 if (ret != LDB_SUCCESS) {
1967 ldb_transaction_cancel(ldb);
1968 return NT_STATUS_ACCESS_DENIED;
1971 ret = ldb_transaction_commit(ldb);
1972 if (ret != LDB_SUCCESS) {
1973 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1974 ldb_dn_get_linearized(msg->dn),
1975 ldb_errstring(ldb)));
1976 return NT_STATUS_TRANSACTION_ABORTED;
1978 return NT_STATUS_OK;
1982 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1983 struct dom_sid *sid, struct ldb_dn **ret_dn)
1985 struct ldb_message *msg;
1986 struct ldb_dn *basedn;
1990 sidstr = dom_sid_string(mem_ctx, sid);
1991 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1993 /* We might have to create a ForeignSecurityPrincipal, even if this user
1994 * is in our own domain */
1996 msg = ldb_msg_new(mem_ctx);
1998 return NT_STATUS_NO_MEMORY;
2001 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2002 * put the ForeignSecurityPrincipals? d_state->domain_dn does
2003 * not work, this is wrong for the Builtin domain, there's no
2004 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
2007 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
2008 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
2010 if (basedn == NULL) {
2011 DEBUG(0, ("Failed to find DN for "
2012 "ForeignSecurityPrincipal container\n"));
2013 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2016 /* add core elements to the ldb_message for the alias */
2017 msg->dn = ldb_dn_copy(mem_ctx, basedn);
2018 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
2019 return NT_STATUS_NO_MEMORY;
2021 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
2023 "foreignSecurityPrincipal");
2025 /* create the alias */
2026 ret = ldb_add(sam_ctx, msg);
2028 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2030 ldb_dn_get_linearized(msg->dn),
2031 ldb_errstring(sam_ctx)));
2032 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2035 return NT_STATUS_OK;
2040 Find the DN of a domain, assuming it to be a dotted.dns name
2043 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2046 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2047 const char *binary_encoded;
2048 const char **split_realm;
2055 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2057 talloc_free(tmp_ctx);
2060 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2061 for (i=0; split_realm[i]; i++) {
2062 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2063 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2064 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2065 binary_encoded, ldb_dn_get_linearized(dn)));
2066 talloc_free(tmp_ctx);
2070 if (!ldb_dn_validate(dn)) {
2071 DEBUG(2, ("Failed to validated DN %s\n",
2072 ldb_dn_get_linearized(dn)));
2078 Find the DN of a domain, be it the netbios or DNS name
2081 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2082 const char *domain_name)
2084 const char * const domain_ref_attrs[] = {
2087 const char * const domain_ref2_attrs[] = {
2090 struct ldb_result *res_domain_ref;
2091 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2092 /* find the domain's DN */
2093 int ret_domain = ldb_search(ldb, mem_ctx,
2095 samdb_partitions_dn(ldb, mem_ctx),
2098 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2100 if (ret_domain != 0) {
2104 if (res_domain_ref->count == 0) {
2105 ret_domain = ldb_search(ldb, mem_ctx,
2107 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2110 "(objectclass=domain)");
2111 if (ret_domain != 0) {
2115 if (res_domain_ref->count == 1) {
2116 return res_domain_ref->msgs[0]->dn;
2121 if (res_domain_ref->count > 1) {
2122 DEBUG(0,("Found %d records matching domain [%s]\n",
2123 ret_domain, domain_name));
2127 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2133 use a GUID to find a DN
2135 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2136 TALLOC_CTX *mem_ctx,
2137 const char *guid_str, struct ldb_dn **dn)
2140 struct ldb_result *res;
2141 const char *attrs[] = { NULL };
2142 struct ldb_request *search_req;
2144 struct ldb_search_options_control *options;
2146 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2148 DEBUG(0, (__location__ ": out of memory\n"));
2149 return LDB_ERR_OPERATIONS_ERROR;
2152 res = talloc_zero(mem_ctx, struct ldb_result);
2154 DEBUG(0, (__location__ ": out of memory\n"));
2155 return LDB_ERR_OPERATIONS_ERROR;
2158 ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2159 ldb_get_default_basedn(ldb),
2163 res, ldb_search_default_callback,
2165 if (ret != LDB_SUCCESS) {
2169 /* we need to cope with cross-partition links, so search for
2170 the GUID over all partitions */
2171 options = talloc(search_req, struct ldb_search_options_control);
2172 if (options == NULL) {
2173 DEBUG(0, (__location__ ": out of memory\n"));
2174 return LDB_ERR_OPERATIONS_ERROR;
2176 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2178 ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2179 if (ret != LDB_SUCCESS) {
2183 ret = ldb_request_add_control(search_req,
2184 LDB_CONTROL_SEARCH_OPTIONS_OID,
2186 if (ret != LDB_SUCCESS) {
2190 ret = ldb_request(ldb, search_req);
2191 if (ret != LDB_SUCCESS) {
2195 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2196 if (ret != LDB_SUCCESS) {
2200 /* this really should be exactly 1, but there is a bug in the
2201 partitions module that can return two here with the
2202 search_options control set */
2203 if (res->count < 1) {
2204 return LDB_ERR_NO_SUCH_OBJECT;
2207 *dn = res->msgs[0]->dn;
2213 search for attrs on one DN, allowing for deleted objects
2215 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2216 TALLOC_CTX *mem_ctx,
2217 struct ldb_result **_res,
2218 struct ldb_dn *basedn,
2219 const char * const *attrs)
2222 struct ldb_request *req;
2223 TALLOC_CTX *tmp_ctx;
2224 struct ldb_result *res;
2226 tmp_ctx = talloc_new(mem_ctx);
2228 res = talloc_zero(tmp_ctx, struct ldb_result);
2230 return LDB_ERR_OPERATIONS_ERROR;
2233 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2240 ldb_search_default_callback,
2242 if (ret != LDB_SUCCESS) {
2243 talloc_free(tmp_ctx);
2247 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2248 if (ret != LDB_SUCCESS) {
2252 ret = ldb_request(ldb, req);
2253 if (ret == LDB_SUCCESS) {
2254 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2258 *_res = talloc_steal(mem_ctx, res);
2264 use a DN to find a GUID
2266 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2267 struct ldb_dn *dn, struct GUID *guid)
2270 struct ldb_result *res;
2271 const char *attrs[] = { "objectGUID", NULL };
2272 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2274 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2275 if (ret != LDB_SUCCESS) {
2276 talloc_free(tmp_ctx);
2279 if (res->count < 1) {
2280 talloc_free(tmp_ctx);
2281 return LDB_ERR_NO_SUCH_OBJECT;
2283 *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2284 talloc_free(tmp_ctx);
2291 adds the given GUID to the given ldb_message. This value is added
2292 for the given attr_name (may be either "objectGUID" or "parentGUID").
2294 int dsdb_msg_add_guid(struct ldb_message *msg,
2296 const char *attr_name)
2299 enum ndr_err_code ndr_err;
2302 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2304 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, NULL,
2306 (ndr_push_flags_fn_t)ndr_push_GUID);
2308 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2309 ret = LDB_ERR_OPERATIONS_ERROR;
2313 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2314 if (ret != LDB_SUCCESS) {
2315 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2323 talloc_free(tmp_ctx);
2330 use a DN to find a SID
2332 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2333 struct ldb_dn *dn, struct dom_sid *sid)
2336 struct ldb_result *res;
2337 const char *attrs[] = { "objectSID", NULL };
2338 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2343 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2344 if (ret != LDB_SUCCESS) {
2345 talloc_free(tmp_ctx);
2348 if (res->count < 1) {
2349 talloc_free(tmp_ctx);
2350 return LDB_ERR_NO_SUCH_OBJECT;
2352 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2354 talloc_free(tmp_ctx);
2355 return LDB_ERR_NO_SUCH_OBJECT;
2358 talloc_free(tmp_ctx);
2365 load a repsFromTo blob list for a given partition GUID
2366 attr must be "repsFrom" or "repsTo"
2368 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2369 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2371 const char *attrs[] = { attr, NULL };
2372 struct ldb_result *res = NULL;
2373 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2375 struct ldb_message_element *el;
2380 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2382 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2383 talloc_free(tmp_ctx);
2384 return WERR_DS_DRA_INTERNAL_ERROR;
2387 el = ldb_msg_find_element(res->msgs[0], attr);
2389 /* it's OK to be empty */
2390 talloc_free(tmp_ctx);
2394 *count = el->num_values;
2395 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2397 talloc_free(tmp_ctx);
2398 return WERR_DS_DRA_INTERNAL_ERROR;
2401 for (i=0; i<(*count); i++) {
2402 enum ndr_err_code ndr_err;
2403 ndr_err = ndr_pull_struct_blob(&el->values[i],
2404 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2406 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2407 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2408 talloc_free(tmp_ctx);
2409 return WERR_DS_DRA_INTERNAL_ERROR;
2413 talloc_free(tmp_ctx);
2419 save the repsFromTo blob list for a given partition GUID
2420 attr must be "repsFrom" or "repsTo"
2422 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2423 const char *attr, struct repsFromToBlob *r, uint32_t count)
2425 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2426 struct ldb_message *msg;
2427 struct ldb_message_element *el;
2430 msg = ldb_msg_new(tmp_ctx);
2432 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2436 el->values = talloc_array(msg, struct ldb_val, count);
2441 for (i=0; i<count; i++) {
2443 enum ndr_err_code ndr_err;
2445 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2447 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2448 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2456 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2457 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2461 talloc_free(tmp_ctx);
2466 talloc_free(tmp_ctx);
2467 return WERR_DS_DRA_INTERNAL_ERROR;
2472 load the uSNHighest attribute from the @REPLCHANGED object for a
2475 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2477 struct ldb_request *req;
2479 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2480 struct dsdb_control_current_partition *p_ctrl;
2481 struct ldb_result *res;
2483 res = talloc_zero(tmp_ctx, struct ldb_result);
2485 talloc_free(tmp_ctx);
2486 return LDB_ERR_OPERATIONS_ERROR;
2489 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2490 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2494 res, ldb_search_default_callback,
2496 if (ret != LDB_SUCCESS) {
2497 talloc_free(tmp_ctx);
2501 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2502 if (p_ctrl == NULL) {
2504 return LDB_ERR_OPERATIONS_ERROR;
2506 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2510 ret = ldb_request_add_control(req,
2511 DSDB_CONTROL_CURRENT_PARTITION_OID,
2513 if (ret != LDB_SUCCESS) {
2514 talloc_free(tmp_ctx);
2518 /* Run the new request */
2519 ret = ldb_request(ldb, req);
2521 if (ret == LDB_SUCCESS) {
2522 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2525 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2526 /* it hasn't been created yet, which means
2527 an implicit value of zero */
2529 talloc_free(tmp_ctx);
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(tmp_ctx);
2538 if (res->count < 1) {
2541 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2544 talloc_free(tmp_ctx);
2550 save the uSNHighest attribute in the @REPLCHANGED object for a
2553 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2555 struct ldb_request *req;
2556 struct ldb_message *msg;
2557 struct dsdb_control_current_partition *p_ctrl;
2560 msg = ldb_msg_new(ldb);
2562 return LDB_ERR_OPERATIONS_ERROR;
2565 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2566 if (msg->dn == NULL) {
2568 return LDB_ERR_OPERATIONS_ERROR;
2571 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2572 if (ret != LDB_SUCCESS) {
2576 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2579 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2580 if (p_ctrl == NULL) {
2582 return LDB_ERR_OPERATIONS_ERROR;
2584 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2587 ret = ldb_build_mod_req(&req, ldb, msg,
2590 NULL, ldb_op_default_callback,
2593 if (ret != LDB_SUCCESS) {
2598 ret = ldb_request_add_control(req,
2599 DSDB_CONTROL_CURRENT_PARTITION_OID,
2601 if (ret != LDB_SUCCESS) {
2606 /* Run the new request */
2607 ret = ldb_request(ldb, req);
2609 if (ret == LDB_SUCCESS) {
2610 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2612 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2613 ret = ldb_build_add_req(&req, ldb, msg,
2616 NULL, ldb_op_default_callback,
2626 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2627 const struct drsuapi_DsReplicaCursor2 *c2)
2629 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2633 see if we are a RODC
2635 TODO: This should take a sam_ctx, and lookup the right object (with
2638 bool samdb_rodc(struct loadparm_context *lp_ctx)
2640 return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false);
2645 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2647 flags are DS_NTDS_OPTION_*
2649 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2651 TALLOC_CTX *tmp_ctx;
2652 const char *attrs[] = { "options", NULL };
2654 struct ldb_result *res;
2656 tmp_ctx = talloc_new(ldb);
2657 if (tmp_ctx == NULL) {
2661 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2666 if (res->count != 1) {
2670 *options = samdb_result_uint(res->msgs[0], "options", 0);
2672 talloc_free(tmp_ctx);
2677 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2678 talloc_free(tmp_ctx);
2679 return LDB_ERR_NO_SUCH_OBJECT;
2683 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2684 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2686 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2688 char **tokens, *ret;
2691 tokens = str_list_make(mem_ctx, cn, " -_");
2695 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2696 tokens[0][0] = tolower(tokens[0][0]);
2697 for (i = 1; i < str_list_length((const char **)tokens); i++)
2698 tokens[i][0] = toupper(tokens[i][0]);
2700 ret = talloc_strdup(mem_ctx, tokens[0]);
2701 for (i = 1; i < str_list_length((const char **)tokens); i++)
2702 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2704 talloc_free(tokens);
2710 return domain functional level
2711 returns DS_DOMAIN_FUNCTION_*
2713 int dsdb_functional_level(struct ldb_context *ldb)
2715 int *domainFunctionality =
2716 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
2717 if (!domainFunctionality) {
2718 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
2719 return DS_DOMAIN_FUNCTION_2000;
2721 return *domainFunctionality;
2725 return a GUID from a extended DN structure
2727 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid)
2729 const struct ldb_val *v;
2731 v = ldb_dn_get_extended_component(dn, "GUID");
2733 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2736 return GUID_from_ndr_blob(v, guid);