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/>.
26 #include "ldb_errors.h"
27 #include "lib/util/util_ldb.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "libcli/security/security.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "dsdb/common/flags.h"
32 #include "dsdb/common/proto.h"
33 #include "libcli/ldap/ldap_ndr.h"
34 #include "param/param.h"
35 #include "libcli/auth/libcli_auth.h"
38 search the sam for the specified attributes in a specific domain, filter on
39 objectSid being in domain_sid.
41 int samdb_search_domain(struct ldb_context *sam_ldb,
43 struct ldb_dn *basedn,
44 struct ldb_message ***res,
45 const char * const *attrs,
46 const struct dom_sid *domain_sid,
47 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
53 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
54 res, attrs, format, ap);
60 struct dom_sid *entry_sid;
62 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
64 if ((entry_sid == NULL) ||
65 (!dom_sid_in_domain(domain_sid, entry_sid))) {
66 /* Delete that entry from the result set */
67 (*res)[i] = (*res)[count-1];
69 talloc_free(entry_sid);
72 talloc_free(entry_sid);
80 search the sam for a single string attribute in exactly 1 record
82 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
84 struct ldb_dn *basedn,
85 const char *attr_name,
86 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
89 const char *attrs[2] = { NULL, NULL };
90 struct ldb_message **res = NULL;
94 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
96 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
97 attr_name, format, count));
104 return samdb_result_string(res[0], attr_name, NULL);
109 search the sam for a single string attribute in exactly 1 record
111 const char *samdb_search_string(struct ldb_context *sam_ldb,
113 struct ldb_dn *basedn,
114 const char *attr_name,
115 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
120 va_start(ap, format);
121 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
127 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
129 struct ldb_dn *basedn,
130 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
134 struct ldb_message **res = NULL;
137 va_start(ap, format);
138 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
141 if (count != 1) return NULL;
143 ret = talloc_steal(mem_ctx, res[0]->dn);
150 search the sam for a dom_sid attribute in exactly 1 record
152 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
154 struct ldb_dn *basedn,
155 const char *attr_name,
156 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
160 struct ldb_message **res;
161 const char *attrs[2] = { NULL, NULL };
164 attrs[0] = attr_name;
166 va_start(ap, format);
167 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
170 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
171 attr_name, format, count));
177 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
183 return the count of the number of records in the sam matching the query
185 int samdb_search_count(struct ldb_context *sam_ldb,
187 struct ldb_dn *basedn,
188 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
191 struct ldb_message **res;
192 const char * const attrs[] = { NULL };
195 va_start(ap, format);
196 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
204 search the sam for a single integer attribute in exactly 1 record
206 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
208 uint_t default_value,
209 struct ldb_dn *basedn,
210 const char *attr_name,
211 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 struct ldb_message **res;
216 const char *attrs[2] = { NULL, NULL };
218 attrs[0] = attr_name;
220 va_start(ap, format);
221 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
225 return default_value;
228 return samdb_result_uint(res[0], attr_name, default_value);
232 search the sam for a single signed 64 bit integer attribute in exactly 1 record
234 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
236 int64_t default_value,
237 struct ldb_dn *basedn,
238 const char *attr_name,
239 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243 struct ldb_message **res;
244 const char *attrs[2] = { NULL, NULL };
246 attrs[0] = attr_name;
248 va_start(ap, format);
249 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
253 return default_value;
256 return samdb_result_int64(res[0], attr_name, default_value);
260 search the sam for multipe records each giving a single string attribute
261 return the number of matches, or -1 on error
263 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
265 struct ldb_dn *basedn,
267 const char *attr_name,
268 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
272 const char *attrs[2] = { NULL, NULL };
273 struct ldb_message **res = NULL;
275 attrs[0] = attr_name;
277 va_start(ap, format);
278 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
285 /* make sure its single valued */
286 for (i=0;i<count;i++) {
287 if (res[i]->num_elements != 1) {
288 DEBUG(1,("samdb: search for %s %s not single valued\n",
295 *strs = talloc_array(mem_ctx, const char *, count+1);
301 for (i=0;i<count;i++) {
302 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
304 (*strs)[count] = NULL;
310 pull a uint from a result set.
312 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
314 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
318 pull a (signed) int64 from a result set.
320 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
322 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
326 pull a string from a result set.
328 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
329 const char *default_value)
331 return ldb_msg_find_attr_as_string(msg, attr, default_value);
334 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
335 const char *attr, struct ldb_dn *default_value)
337 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
339 return default_value;
345 pull a rid from a objectSid in a result set.
347 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
348 const char *attr, uint32_t default_value)
353 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
355 return default_value;
357 rid = sid->sub_auths[sid->num_auths-1];
363 pull a dom_sid structure from a objectSid in a result set.
365 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
368 const struct ldb_val *v;
370 enum ndr_err_code ndr_err;
371 v = ldb_msg_find_ldb_val(msg, attr);
375 sid = talloc(mem_ctx, struct dom_sid);
379 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
380 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
389 pull a guid structure from a objectGUID in a result set.
391 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
393 const struct ldb_val *v;
394 enum ndr_err_code ndr_err;
400 v = ldb_msg_find_ldb_val(msg, attr);
403 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
404 if (!mem_ctx) return guid;
405 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
406 (ndr_pull_flags_fn_t)ndr_pull_GUID);
407 talloc_free(mem_ctx);
408 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
416 pull a sid prefix from a objectSid in a result set.
417 this is used to find the domain sid for a user
419 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
422 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
423 if (!sid || sid->num_auths < 1) return NULL;
429 pull a NTTIME in a result set.
431 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
433 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
437 pull a uint64_t from a result set.
439 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
441 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
446 construct the allow_password_change field from the PwdLastSet attribute and the
447 domain password settings
449 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
451 struct ldb_dn *domain_dn,
452 struct ldb_message *msg,
455 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
458 if (attr_time == 0) {
462 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
464 /* yes, this is a -= not a += as minPwdAge is stored as the negative
465 of the number of 100-nano-seconds */
466 attr_time -= minPwdAge;
472 construct the force_password_change field from the PwdLastSet attribute and the
473 domain password settings
475 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
477 struct ldb_dn *domain_dn,
478 struct ldb_message *msg)
480 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
481 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
484 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
485 return 0x7FFFFFFFFFFFFFFFULL;
488 if (attr_time == 0) {
492 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
493 if (maxPwdAge == 0) {
496 attr_time -= maxPwdAge;
503 pull a samr_Password structutre from a result set.
505 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
507 struct samr_Password *hash = NULL;
508 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
509 if (val && (val->length >= sizeof(hash->hash))) {
510 hash = talloc(mem_ctx, struct samr_Password);
511 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
517 pull an array of samr_Password structutres from a result set.
519 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
520 const char *attr, struct samr_Password **hashes)
523 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
530 count = val->length / 16;
535 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
540 for (i=0;i<count;i++) {
541 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
547 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
548 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
550 struct samr_Password *lmPwdHash, *ntPwdHash;
553 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
556 } else if (num_nt > 1) {
557 return NT_STATUS_INTERNAL_DB_CORRUPTION;
559 *nt_pwd = &ntPwdHash[0];
564 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
567 } else if (num_lm > 1) {
568 return NT_STATUS_INTERNAL_DB_CORRUPTION;
570 *lm_pwd = &lmPwdHash[0];
577 pull a samr_LogonHours structutre from a result set.
579 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
581 struct samr_LogonHours hours;
582 const int units_per_week = 168;
583 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
585 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
589 hours.units_per_week = units_per_week;
590 memset(hours.bits, 0xFF, units_per_week);
592 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
598 pull a set of account_flags from a result set.
600 This requires that the attributes:
605 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
606 struct ldb_message *msg, struct ldb_dn *domain_dn)
608 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
609 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
610 if ((userAccountControl & UF_NORMAL_ACCOUNT) && !(userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
611 NTTIME must_change_time;
612 NTTIME pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0);
613 if (pwdLastSet == 0) {
614 acct_flags |= ACB_PW_EXPIRED;
618 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
621 /* Test account expire time */
622 unix_to_nt_time(&now, time(NULL));
623 /* check for expired password */
624 if ((must_change_time != 0) && (must_change_time < now)) {
625 acct_flags |= ACB_PW_EXPIRED;
633 /* Find an attribute, with a particular value */
635 /* The current callers of this function expect a very specific
636 * behaviour: In particular, objectClass subclass equivilance is not
637 * wanted. This means that we should not lookup the schema for the
638 * comparison function */
639 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
640 const struct ldb_message *msg,
641 const char *name, const char *value)
644 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
650 for (i=0;i<el->num_values;i++) {
651 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
659 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
661 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
662 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
667 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
669 struct ldb_message_element *el;
671 el = ldb_msg_find_element(msg, name);
676 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
682 add a string element to a message
684 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
685 const char *attr_name, const char *str)
687 char *s = talloc_strdup(mem_ctx, str);
688 char *a = talloc_strdup(mem_ctx, attr_name);
689 if (s == NULL || a == NULL) {
690 return LDB_ERR_OPERATIONS_ERROR;
692 return ldb_msg_add_string(msg, a, s);
696 add a dom_sid element to a message
698 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
699 const char *attr_name, struct dom_sid *sid)
702 enum ndr_err_code ndr_err;
704 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
705 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
707 (ndr_push_flags_fn_t)ndr_push_dom_sid);
708 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
711 return ldb_msg_add_value(msg, attr_name, &v, NULL);
716 add a delete element operation to a message
718 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
719 const char *attr_name)
721 /* we use an empty replace rather than a delete, as it allows for
722 samdb_replace() to be used everywhere */
723 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
727 add a add attribute value to a message
729 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
730 const char *attr_name, const char *value)
732 struct ldb_message_element *el;
735 a = talloc_strdup(mem_ctx, attr_name);
738 v = talloc_strdup(mem_ctx, value);
741 ret = ldb_msg_add_string(msg, a, v);
744 el = ldb_msg_find_element(msg, a);
747 el->flags = LDB_FLAG_MOD_ADD;
752 add a delete attribute value to a message
754 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
755 const char *attr_name, const char *value)
757 struct ldb_message_element *el;
760 a = talloc_strdup(mem_ctx, attr_name);
763 v = talloc_strdup(mem_ctx, value);
766 ret = ldb_msg_add_string(msg, a, v);
769 el = ldb_msg_find_element(msg, a);
772 el->flags = LDB_FLAG_MOD_DELETE;
777 add a int element to a message
779 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
780 const char *attr_name, int v)
782 const char *s = talloc_asprintf(mem_ctx, "%d", v);
783 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
787 add a uint_t element to a message
789 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
790 const char *attr_name, uint_t v)
792 const char *s = talloc_asprintf(mem_ctx, "%u", v);
793 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
797 add a (signed) int64_t element to a message
799 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
800 const char *attr_name, int64_t v)
802 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
803 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
807 add a uint64_t element to a message
809 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
810 const char *attr_name, uint64_t v)
812 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
813 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
817 add a samr_Password element to a message
819 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820 const char *attr_name, struct samr_Password *hash)
823 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
828 return ldb_msg_add_value(msg, attr_name, &val, NULL);
832 add a samr_Password array to a message
834 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
835 const char *attr_name, struct samr_Password *hashes, uint_t count)
839 val.data = talloc_array_size(mem_ctx, 16, count);
840 val.length = count*16;
844 for (i=0;i<count;i++) {
845 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
847 return ldb_msg_add_value(msg, attr_name, &val, NULL);
851 add a acct_flags element to a message
853 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
854 const char *attr_name, uint32_t v)
856 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
860 add a logon_hours element to a message
862 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
863 const char *attr_name, struct samr_LogonHours *hours)
866 val.length = hours->units_per_week / 8;
867 val.data = hours->bits;
868 return ldb_msg_add_value(msg, attr_name, &val, NULL);
872 add a general value element to a message
874 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
875 const char *attr_name, const struct ldb_val *val)
877 return ldb_msg_add_value(msg, attr_name, val, NULL);
881 sets a general value element to a message
883 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
884 const char *attr_name, const struct ldb_val *val)
886 struct ldb_message_element *el;
888 el = ldb_msg_find_element(msg, attr_name);
892 return ldb_msg_add_value(msg, attr_name, val, NULL);
896 set a string element in a message
898 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
899 const char *attr_name, const char *str)
901 struct ldb_message_element *el;
903 el = ldb_msg_find_element(msg, attr_name);
907 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
911 replace elements in a record
913 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
917 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
918 for (i=0;i<msg->num_elements;i++) {
919 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
922 /* modify the samdb record */
923 return ldb_modify(sam_ldb, msg);
927 return a default security descriptor
929 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
931 struct security_descriptor *sd;
933 sd = security_descriptor_initialise(mem_ctx);
938 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
940 return ldb_get_default_basedn(sam_ctx);
943 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
945 return ldb_get_config_basedn(sam_ctx);
948 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
950 return ldb_get_schema_basedn(sam_ctx);
953 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
955 return ldb_get_root_basedn(sam_ctx);
958 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
960 struct ldb_dn *new_dn;
962 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
963 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
970 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
972 struct ldb_dn *new_dn;
974 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
975 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
983 work out the domain sid for the current open ldb
985 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
988 struct dom_sid *domain_sid;
990 /* see if we have a cached copy */
991 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
996 tmp_ctx = talloc_new(ldb);
997 if (tmp_ctx == NULL) {
1001 /* find the domain_sid */
1002 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1003 "objectSid", "objectClass=domainDNS");
1004 if (domain_sid == NULL) {
1008 /* cache the domain_sid in the ldb */
1009 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1013 talloc_steal(ldb, domain_sid);
1014 talloc_free(tmp_ctx);
1019 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1020 talloc_free(tmp_ctx);
1024 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1026 TALLOC_CTX *tmp_ctx;
1027 struct dom_sid *dom_sid_new;
1028 struct dom_sid *dom_sid_old;
1030 /* see if we have a cached copy */
1031 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1032 "cache.domain_sid"), struct dom_sid);
1034 tmp_ctx = talloc_new(ldb);
1035 if (tmp_ctx == NULL) {
1039 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1044 /* cache the domain_sid in the ldb */
1045 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1049 talloc_steal(ldb, dom_sid_new);
1050 talloc_free(tmp_ctx);
1051 talloc_free(dom_sid_old);
1056 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1057 talloc_free(tmp_ctx);
1061 /* Obtain the short name of the flexible single master operator
1062 * (FSMO), such as the PDC Emulator */
1063 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1066 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1067 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1068 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1069 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1071 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1072 /* Ensure this matches the format. This gives us a
1073 * bit more confidence that a 'cn' value will be a
1078 return (char *)val->data;
1084 work out the ntds settings dn for the current open ldb
1086 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1088 TALLOC_CTX *tmp_ctx;
1089 const char *root_attrs[] = { "dsServiceName", NULL };
1091 struct ldb_result *root_res;
1092 struct ldb_dn *settings_dn;
1094 /* see if we have a cached copy */
1095 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1100 tmp_ctx = talloc_new(ldb);
1101 if (tmp_ctx == NULL) {
1106 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1108 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1109 ldb_errstring(ldb)));
1112 talloc_steal(tmp_ctx, root_res);
1114 if (root_res->count != 1) {
1118 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1120 /* cache the domain_sid in the ldb */
1121 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1125 talloc_steal(ldb, settings_dn);
1126 talloc_free(tmp_ctx);
1131 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1132 talloc_free(tmp_ctx);
1137 work out the ntds settings invocationId for the current open ldb
1139 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1141 TALLOC_CTX *tmp_ctx;
1142 const char *attrs[] = { "invocationId", NULL };
1144 struct ldb_result *res;
1145 struct GUID *invocation_id;
1147 /* see if we have a cached copy */
1148 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1149 if (invocation_id) {
1150 return invocation_id;
1153 tmp_ctx = talloc_new(ldb);
1154 if (tmp_ctx == NULL) {
1158 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1162 talloc_steal(tmp_ctx, res);
1164 if (res->count != 1) {
1168 invocation_id = talloc(tmp_ctx, struct GUID);
1169 if (!invocation_id) {
1173 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1175 /* cache the domain_sid in the ldb */
1176 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1180 talloc_steal(ldb, invocation_id);
1181 talloc_free(tmp_ctx);
1183 return invocation_id;
1186 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1187 talloc_free(tmp_ctx);
1191 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1193 TALLOC_CTX *tmp_ctx;
1194 struct GUID *invocation_id_new;
1195 struct GUID *invocation_id_old;
1197 /* see if we have a cached copy */
1198 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1199 "cache.invocation_id");
1201 tmp_ctx = talloc_new(ldb);
1202 if (tmp_ctx == NULL) {
1206 invocation_id_new = talloc(tmp_ctx, struct GUID);
1207 if (!invocation_id_new) {
1211 *invocation_id_new = *invocation_id_in;
1213 /* cache the domain_sid in the ldb */
1214 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1218 talloc_steal(ldb, invocation_id_new);
1219 talloc_free(tmp_ctx);
1220 talloc_free(invocation_id_old);
1225 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1226 talloc_free(tmp_ctx);
1231 work out the ntds settings objectGUID for the current open ldb
1233 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1235 TALLOC_CTX *tmp_ctx;
1236 const char *attrs[] = { "objectGUID", NULL };
1238 struct ldb_result *res;
1239 struct GUID *ntds_guid;
1241 /* see if we have a cached copy */
1242 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1247 tmp_ctx = talloc_new(ldb);
1248 if (tmp_ctx == NULL) {
1252 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1256 talloc_steal(tmp_ctx, res);
1258 if (res->count != 1) {
1262 ntds_guid = talloc(tmp_ctx, struct GUID);
1267 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1269 /* cache the domain_sid in the ldb */
1270 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1274 talloc_steal(ldb, ntds_guid);
1275 talloc_free(tmp_ctx);
1280 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1281 talloc_free(tmp_ctx);
1285 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1287 TALLOC_CTX *tmp_ctx;
1288 struct GUID *ntds_guid_new;
1289 struct GUID *ntds_guid_old;
1291 /* see if we have a cached copy */
1292 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1294 tmp_ctx = talloc_new(ldb);
1295 if (tmp_ctx == NULL) {
1299 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1300 if (!ntds_guid_new) {
1304 *ntds_guid_new = *ntds_guid_in;
1306 /* cache the domain_sid in the ldb */
1307 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1311 talloc_steal(ldb, ntds_guid_new);
1312 talloc_free(tmp_ctx);
1313 talloc_free(ntds_guid_old);
1318 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1319 talloc_free(tmp_ctx);
1324 work out the server dn for the current open ldb
1326 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1328 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1332 work out the server dn for the current open ldb
1334 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1336 struct ldb_dn *server_dn;
1337 struct ldb_dn *server_site_dn;
1339 server_dn = samdb_server_dn(ldb, mem_ctx);
1340 if (!server_dn) return NULL;
1342 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1344 talloc_free(server_dn);
1345 return server_site_dn;
1349 work out if we are the PDC for the domain of the current open ldb
1351 bool samdb_is_pdc(struct ldb_context *ldb)
1353 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1355 struct ldb_result *dom_res;
1356 TALLOC_CTX *tmp_ctx;
1360 tmp_ctx = talloc_new(ldb);
1361 if (tmp_ctx == NULL) {
1362 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1366 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1368 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1369 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1370 ldb_errstring(ldb)));
1373 talloc_steal(tmp_ctx, dom_res);
1374 if (dom_res->count != 1) {
1378 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1380 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1386 talloc_free(tmp_ctx);
1391 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1392 talloc_free(tmp_ctx);
1397 work out if we are a Global Catalog server for the domain of the current open ldb
1399 bool samdb_is_gc(struct ldb_context *ldb)
1401 const char *attrs[] = { "options", NULL };
1403 struct ldb_result *res;
1404 TALLOC_CTX *tmp_ctx;
1406 tmp_ctx = talloc_new(ldb);
1407 if (tmp_ctx == NULL) {
1408 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1412 /* Query cn=ntds settings,.... */
1413 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1417 if (res->count != 1) {
1422 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1424 talloc_free(tmp_ctx);
1426 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1427 if (options & 0x000000001) {
1433 /* Find a domain object in the parents of a particular DN. */
1434 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1435 struct ldb_dn **parent_dn, const char **errstring)
1437 TALLOC_CTX *local_ctx;
1438 struct ldb_dn *sdn = dn;
1439 struct ldb_result *res = NULL;
1441 const char *attrs[] = { NULL };
1443 local_ctx = talloc_new(mem_ctx);
1444 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1446 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1447 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1448 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1449 if (ret == LDB_SUCCESS) {
1450 talloc_steal(local_ctx, res);
1451 if (res->count == 1) {
1459 if (ret != LDB_SUCCESS) {
1460 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1461 ldb_dn_get_linearized(dn),
1462 ldb_dn_get_linearized(sdn),
1463 ldb_errstring(ldb));
1464 talloc_free(local_ctx);
1467 if (res->count != 1) {
1468 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1469 ldb_dn_get_linearized(dn));
1470 talloc_free(local_ctx);
1471 return LDB_ERR_CONSTRAINT_VIOLATION;
1474 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1475 talloc_free(local_ctx);
1480 check that a password is sufficiently complex
1482 static bool samdb_password_complexity_ok(const char *pass)
1484 return check_password_quality(pass);
1490 set the user password using plaintext, obeying any user or domain
1491 password restrictions
1493 note that this function doesn't actually store the result in the
1494 database, it just fills in the "mod" structure with ldb modify
1495 elements to setup the correct change when samdb_replace() is
1496 called. This allows the caller to combine the change with other
1497 changes (as is needed by some of the set user info levels)
1499 The caller should probably have a transaction wrapping this
1501 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1502 struct ldb_dn *user_dn,
1503 struct ldb_dn *domain_dn,
1504 struct ldb_message *mod,
1505 const char *new_pass,
1506 struct samr_Password *lmNewHash,
1507 struct samr_Password *ntNewHash,
1509 enum samr_RejectReason *reject_reason,
1510 struct samr_DomInfo1 **_dominfo)
1512 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1514 "dBCSPwd", "unicodePwd",
1516 "pwdLastSet", NULL };
1517 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1518 "maxPwdAge", "minPwdAge",
1519 "minPwdLength", NULL };
1522 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1523 uint_t userAccountControl;
1524 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1525 struct samr_Password local_lmNewHash, local_ntNewHash;
1526 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1527 struct dom_sid *domain_sid;
1528 struct ldb_message **res;
1531 time_t now = time(NULL);
1535 /* we need to know the time to compute password age */
1536 unix_to_nt_time(&now_nt, now);
1538 /* pull all the user parameters */
1539 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1541 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1543 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1544 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1545 "lmPwdHistory", &sambaLMPwdHistory);
1546 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1547 "ntPwdHistory", &sambaNTPwdHistory);
1548 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1549 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1550 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1552 /* Only non-trust accounts have restrictions (possibly this
1553 * test is the wrong way around, but I like to be restrictive
1555 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1556 |UF_WORKSTATION_TRUST_ACCOUNT
1557 |UF_SERVER_TRUST_ACCOUNT));
1560 /* pull the domain parameters */
1561 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1563 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1564 ldb_dn_get_linearized(domain_dn),
1565 ldb_dn_get_linearized(user_dn)));
1566 return NT_STATUS_NO_SUCH_DOMAIN;
1569 /* work out the domain sid, and pull the domain from there */
1570 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1571 if (domain_sid == NULL) {
1572 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1575 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1577 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1579 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1580 dom_sid_string(mem_ctx, domain_sid),
1581 ldb_dn_get_linearized(user_dn)));
1582 return NT_STATUS_NO_SUCH_DOMAIN;
1586 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1587 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1588 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1589 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1592 struct samr_DomInfo1 *dominfo;
1593 /* on failure we need to fill in the reject reasons */
1594 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1595 if (dominfo == NULL) {
1596 return NT_STATUS_NO_MEMORY;
1598 dominfo->min_password_length = minPwdLength;
1599 dominfo->password_properties = pwdProperties;
1600 dominfo->password_history_length = pwdHistoryLength;
1601 dominfo->max_password_age = minPwdAge;
1602 dominfo->min_password_age = minPwdAge;
1603 *_dominfo = dominfo;
1606 if (restrictions && new_pass) {
1608 /* check the various password restrictions */
1609 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1610 if (reject_reason) {
1611 *reject_reason = SAMR_REJECT_TOO_SHORT;
1613 return NT_STATUS_PASSWORD_RESTRICTION;
1616 /* possibly check password complexity */
1617 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1618 !samdb_password_complexity_ok(new_pass)) {
1619 if (reject_reason) {
1620 *reject_reason = SAMR_REJECT_COMPLEXITY;
1622 return NT_STATUS_PASSWORD_RESTRICTION;
1625 /* compute the new nt and lm hashes */
1626 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1627 lmNewHash = &local_lmNewHash;
1629 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1630 /* If we can't convert this password to UCS2, then we should not accept it */
1631 if (reject_reason) {
1632 *reject_reason = SAMR_REJECT_OTHER;
1634 return NT_STATUS_PASSWORD_RESTRICTION;
1636 ntNewHash = &local_ntNewHash;
1640 /* are all password changes disallowed? */
1641 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1642 if (reject_reason) {
1643 *reject_reason = SAMR_REJECT_OTHER;
1645 return NT_STATUS_PASSWORD_RESTRICTION;
1648 /* can this user change password? */
1649 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1650 if (reject_reason) {
1651 *reject_reason = SAMR_REJECT_OTHER;
1653 return NT_STATUS_PASSWORD_RESTRICTION;
1656 /* yes, this is a minus. The ages are in negative 100nsec units! */
1657 if (pwdLastSet - minPwdAge > now_nt) {
1658 if (reject_reason) {
1659 *reject_reason = SAMR_REJECT_OTHER;
1661 return NT_STATUS_PASSWORD_RESTRICTION;
1664 /* check the immediately past password */
1665 if (pwdHistoryLength > 0) {
1666 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1667 if (reject_reason) {
1668 *reject_reason = SAMR_REJECT_IN_HISTORY;
1670 return NT_STATUS_PASSWORD_RESTRICTION;
1672 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1673 if (reject_reason) {
1674 *reject_reason = SAMR_REJECT_IN_HISTORY;
1676 return NT_STATUS_PASSWORD_RESTRICTION;
1680 /* check the password history */
1681 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1682 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1684 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1685 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1686 if (reject_reason) {
1687 *reject_reason = SAMR_REJECT_IN_HISTORY;
1689 return NT_STATUS_PASSWORD_RESTRICTION;
1692 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1693 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1694 if (reject_reason) {
1695 *reject_reason = SAMR_REJECT_IN_HISTORY;
1697 return NT_STATUS_PASSWORD_RESTRICTION;
1702 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1704 /* the password is acceptable. Start forming the new fields */
1706 /* if we know the cleartext, then only set it.
1707 * Modules in ldb will set all the appropriate
1709 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1710 "sambaPassword", new_pass));
1712 /* We don't have the cleartext, so delete the old one
1713 * and set what we have of the hashes */
1714 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1717 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1719 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1723 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1725 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1729 return NT_STATUS_OK;
1734 set the user password using plaintext, obeying any user or domain
1735 password restrictions
1737 This wrapper function takes a SID as input, rather than a user DN,
1738 and actually performs the password change
1741 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1742 const struct dom_sid *user_sid,
1743 const char *new_pass,
1744 struct samr_Password *lmNewHash,
1745 struct samr_Password *ntNewHash,
1747 enum samr_RejectReason *reject_reason,
1748 struct samr_DomInfo1 **_dominfo)
1751 struct ldb_dn *user_dn;
1752 struct ldb_message *msg;
1755 ret = ldb_transaction_start(ctx);
1757 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1758 return NT_STATUS_TRANSACTION_ABORTED;
1761 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1762 "(&(objectSid=%s)(objectClass=user))",
1763 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1765 ldb_transaction_cancel(ctx);
1766 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1767 dom_sid_string(mem_ctx, user_sid)));
1768 return NT_STATUS_NO_SUCH_USER;
1771 msg = ldb_msg_new(mem_ctx);
1773 ldb_transaction_cancel(ctx);
1774 return NT_STATUS_NO_MEMORY;
1777 msg->dn = ldb_dn_copy(msg, user_dn);
1779 ldb_transaction_cancel(ctx);
1780 return NT_STATUS_NO_MEMORY;
1783 nt_status = samdb_set_password(ctx, mem_ctx,
1786 lmNewHash, ntNewHash,
1787 user_change, /* This is a password set, not change */
1788 reject_reason, _dominfo);
1789 if (!NT_STATUS_IS_OK(nt_status)) {
1790 ldb_transaction_cancel(ctx);
1794 /* modify the samdb record */
1795 ret = samdb_replace(ctx, mem_ctx, msg);
1797 ldb_transaction_cancel(ctx);
1798 return NT_STATUS_ACCESS_DENIED;
1801 ret = ldb_transaction_commit(ctx);
1803 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1804 ldb_dn_get_linearized(msg->dn),
1805 ldb_errstring(ctx)));
1806 return NT_STATUS_TRANSACTION_ABORTED;
1808 return NT_STATUS_OK;
1813 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1814 struct dom_sid *sid, struct ldb_dn **ret_dn)
1816 struct ldb_message *msg;
1817 struct ldb_dn *basedn;
1821 sidstr = dom_sid_string(mem_ctx, sid);
1822 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1824 /* We might have to create a ForeignSecurityPrincipal, even if this user
1825 * is in our own domain */
1827 msg = ldb_msg_new(mem_ctx);
1829 return NT_STATUS_NO_MEMORY;
1832 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1833 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1834 * not work, this is wrong for the Builtin domain, there's no
1835 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1838 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1839 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1841 if (basedn == NULL) {
1842 DEBUG(0, ("Failed to find DN for "
1843 "ForeignSecurityPrincipal container\n"));
1844 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1847 /* add core elements to the ldb_message for the alias */
1848 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1849 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1850 return NT_STATUS_NO_MEMORY;
1852 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1854 "foreignSecurityPrincipal");
1856 /* create the alias */
1857 ret = ldb_add(sam_ctx, msg);
1859 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1861 ldb_dn_get_linearized(msg->dn),
1862 ldb_errstring(sam_ctx)));
1863 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1866 return NT_STATUS_OK;
1871 Find the DN of a domain, assuming it to be a dotted.dns name
1874 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1877 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1878 const char *binary_encoded;
1879 const char **split_realm;
1886 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1888 talloc_free(tmp_ctx);
1891 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1892 for (i=0; split_realm[i]; i++) {
1893 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1894 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1895 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1896 binary_encoded, ldb_dn_get_linearized(dn)));
1897 talloc_free(tmp_ctx);
1901 if (!ldb_dn_validate(dn)) {
1902 DEBUG(2, ("Failed to validated DN %s\n",
1903 ldb_dn_get_linearized(dn)));
1909 Find the DN of a domain, be it the netbios or DNS name
1912 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1913 const char *domain_name)
1915 const char * const domain_ref_attrs[] = {
1918 const char * const domain_ref2_attrs[] = {
1921 struct ldb_result *res_domain_ref;
1922 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1923 /* find the domain's DN */
1924 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1926 samdb_partitions_dn(ldb, mem_ctx),
1929 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1931 if (ret_domain != 0) {
1935 if (res_domain_ref->count == 0) {
1936 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1938 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1941 "(objectclass=domain)");
1942 if (ret_domain != 0) {
1946 if (res_domain_ref->count == 1) {
1947 return res_domain_ref->msgs[0]->dn;
1952 if (res_domain_ref->count > 1) {
1953 DEBUG(0,("Found %d records matching domain [%s]\n",
1954 ret_domain, domain_name));
1958 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);