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 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
602 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
603 return samdb_uf2acb(userAccountControl);
607 /* Find an attribute, with a particular value */
609 /* The current callers of this function expect a very specific
610 * behaviour: In particular, objectClass subclass equivilance is not
611 * wanted. This means that we should not lookup the schema for the
612 * comparison function */
613 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
614 const struct ldb_message *msg,
615 const char *name, const char *value)
618 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
624 for (i=0;i<el->num_values;i++) {
625 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
633 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
635 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
636 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
641 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
643 struct ldb_message_element *el;
645 el = ldb_msg_find_element(msg, name);
650 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
656 add a string element to a message
658 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
659 const char *attr_name, const char *str)
661 char *s = talloc_strdup(mem_ctx, str);
662 char *a = talloc_strdup(mem_ctx, attr_name);
663 if (s == NULL || a == NULL) {
664 return LDB_ERR_OPERATIONS_ERROR;
666 return ldb_msg_add_string(msg, a, s);
670 add a dom_sid element to a message
672 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
673 const char *attr_name, struct dom_sid *sid)
676 enum ndr_err_code ndr_err;
678 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
679 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
681 (ndr_push_flags_fn_t)ndr_push_dom_sid);
682 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
685 return ldb_msg_add_value(msg, attr_name, &v, NULL);
690 add a delete element operation to a message
692 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
693 const char *attr_name)
695 /* we use an empty replace rather than a delete, as it allows for
696 samdb_replace() to be used everywhere */
697 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
701 add a add attribute value to a message
703 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
704 const char *attr_name, const char *value)
706 struct ldb_message_element *el;
709 a = talloc_strdup(mem_ctx, attr_name);
712 v = talloc_strdup(mem_ctx, value);
715 ret = ldb_msg_add_string(msg, a, v);
718 el = ldb_msg_find_element(msg, a);
721 el->flags = LDB_FLAG_MOD_ADD;
726 add a delete attribute value to a message
728 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
729 const char *attr_name, const char *value)
731 struct ldb_message_element *el;
734 a = talloc_strdup(mem_ctx, attr_name);
737 v = talloc_strdup(mem_ctx, value);
740 ret = ldb_msg_add_string(msg, a, v);
743 el = ldb_msg_find_element(msg, a);
746 el->flags = LDB_FLAG_MOD_DELETE;
751 add a int element to a message
753 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
754 const char *attr_name, int v)
756 const char *s = talloc_asprintf(mem_ctx, "%d", v);
757 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
761 add a uint_t element to a message
763 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
764 const char *attr_name, uint_t v)
766 const char *s = talloc_asprintf(mem_ctx, "%u", v);
767 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
771 add a (signed) int64_t element to a message
773 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
774 const char *attr_name, int64_t v)
776 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
777 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
781 add a uint64_t element to a message
783 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, uint64_t v)
786 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
787 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
791 add a samr_Password element to a message
793 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794 const char *attr_name, struct samr_Password *hash)
797 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
802 return ldb_msg_add_value(msg, attr_name, &val, NULL);
806 add a samr_Password array to a message
808 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
809 const char *attr_name, struct samr_Password *hashes, uint_t count)
813 val.data = talloc_array_size(mem_ctx, 16, count);
814 val.length = count*16;
818 for (i=0;i<count;i++) {
819 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
821 return ldb_msg_add_value(msg, attr_name, &val, NULL);
825 add a acct_flags element to a message
827 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
828 const char *attr_name, uint32_t v)
830 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
834 add a logon_hours element to a message
836 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
837 const char *attr_name, struct samr_LogonHours *hours)
840 val.length = hours->units_per_week / 8;
841 val.data = hours->bits;
842 return ldb_msg_add_value(msg, attr_name, &val, NULL);
846 add a general value element to a message
848 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849 const char *attr_name, const struct ldb_val *val)
851 return ldb_msg_add_value(msg, attr_name, val, NULL);
855 sets a general value element to a message
857 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
858 const char *attr_name, const struct ldb_val *val)
860 struct ldb_message_element *el;
862 el = ldb_msg_find_element(msg, attr_name);
866 return ldb_msg_add_value(msg, attr_name, val, NULL);
870 set a string element in a message
872 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
873 const char *attr_name, const char *str)
875 struct ldb_message_element *el;
877 el = ldb_msg_find_element(msg, attr_name);
881 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
885 replace elements in a record
887 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
891 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
892 for (i=0;i<msg->num_elements;i++) {
893 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
896 /* modify the samdb record */
897 return ldb_modify(sam_ldb, msg);
901 return a default security descriptor
903 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
905 struct security_descriptor *sd;
907 sd = security_descriptor_initialise(mem_ctx);
912 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
914 return ldb_get_default_basedn(sam_ctx);
917 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
919 return ldb_get_config_basedn(sam_ctx);
922 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
924 return ldb_get_schema_basedn(sam_ctx);
927 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
929 return ldb_get_root_basedn(sam_ctx);
932 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
934 struct ldb_dn *new_dn;
936 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
937 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
944 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
946 struct ldb_dn *new_dn;
948 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
949 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
957 work out the domain sid for the current open ldb
959 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
962 struct dom_sid *domain_sid;
964 /* see if we have a cached copy */
965 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
970 tmp_ctx = talloc_new(ldb);
971 if (tmp_ctx == NULL) {
975 /* find the domain_sid */
976 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
977 "objectSid", "objectClass=domainDNS");
978 if (domain_sid == NULL) {
982 /* cache the domain_sid in the ldb */
983 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
987 talloc_steal(ldb, domain_sid);
988 talloc_free(tmp_ctx);
993 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
994 talloc_free(tmp_ctx);
998 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1000 TALLOC_CTX *tmp_ctx;
1001 struct dom_sid *dom_sid_new;
1002 struct dom_sid *dom_sid_old;
1004 /* see if we have a cached copy */
1005 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1006 "cache.domain_sid"), struct dom_sid);
1008 tmp_ctx = talloc_new(ldb);
1009 if (tmp_ctx == NULL) {
1013 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1018 /* cache the domain_sid in the ldb */
1019 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1023 talloc_steal(ldb, dom_sid_new);
1024 talloc_free(tmp_ctx);
1025 talloc_free(dom_sid_old);
1030 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1031 talloc_free(tmp_ctx);
1035 /* Obtain the short name of the flexible single master operator
1036 * (FSMO), such as the PDC Emulator */
1037 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1040 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1041 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1042 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1043 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1045 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1046 /* Ensure this matches the format. This gives us a
1047 * bit more confidence that a 'cn' value will be a
1052 return (char *)val->data;
1058 work out the ntds settings dn for the current open ldb
1060 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1062 TALLOC_CTX *tmp_ctx;
1063 const char *root_attrs[] = { "dsServiceName", NULL };
1065 struct ldb_result *root_res;
1066 struct ldb_dn *settings_dn;
1068 /* see if we have a cached copy */
1069 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1074 tmp_ctx = talloc_new(ldb);
1075 if (tmp_ctx == NULL) {
1080 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1082 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1083 ldb_errstring(ldb)));
1086 talloc_steal(tmp_ctx, root_res);
1088 if (root_res->count != 1) {
1092 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1094 /* cache the domain_sid in the ldb */
1095 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1099 talloc_steal(ldb, settings_dn);
1100 talloc_free(tmp_ctx);
1105 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1106 talloc_free(tmp_ctx);
1111 work out the ntds settings invocationId for the current open ldb
1113 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1115 TALLOC_CTX *tmp_ctx;
1116 const char *attrs[] = { "invocationId", NULL };
1118 struct ldb_result *res;
1119 struct GUID *invocation_id;
1121 /* see if we have a cached copy */
1122 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1123 if (invocation_id) {
1124 return invocation_id;
1127 tmp_ctx = talloc_new(ldb);
1128 if (tmp_ctx == NULL) {
1132 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1136 talloc_steal(tmp_ctx, res);
1138 if (res->count != 1) {
1142 invocation_id = talloc(tmp_ctx, struct GUID);
1143 if (!invocation_id) {
1147 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1149 /* cache the domain_sid in the ldb */
1150 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1154 talloc_steal(ldb, invocation_id);
1155 talloc_free(tmp_ctx);
1157 return invocation_id;
1160 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1161 talloc_free(tmp_ctx);
1165 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1167 TALLOC_CTX *tmp_ctx;
1168 struct GUID *invocation_id_new;
1169 struct GUID *invocation_id_old;
1171 /* see if we have a cached copy */
1172 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1173 "cache.invocation_id");
1175 tmp_ctx = talloc_new(ldb);
1176 if (tmp_ctx == NULL) {
1180 invocation_id_new = talloc(tmp_ctx, struct GUID);
1181 if (!invocation_id_new) {
1185 *invocation_id_new = *invocation_id_in;
1187 /* cache the domain_sid in the ldb */
1188 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1192 talloc_steal(ldb, invocation_id_new);
1193 talloc_free(tmp_ctx);
1194 talloc_free(invocation_id_old);
1199 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1200 talloc_free(tmp_ctx);
1205 work out the ntds settings objectGUID for the current open ldb
1207 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1209 TALLOC_CTX *tmp_ctx;
1210 const char *attrs[] = { "objectGUID", NULL };
1212 struct ldb_result *res;
1213 struct GUID *ntds_guid;
1215 /* see if we have a cached copy */
1216 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1221 tmp_ctx = talloc_new(ldb);
1222 if (tmp_ctx == NULL) {
1226 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1230 talloc_steal(tmp_ctx, res);
1232 if (res->count != 1) {
1236 ntds_guid = talloc(tmp_ctx, struct GUID);
1241 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1243 /* cache the domain_sid in the ldb */
1244 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1248 talloc_steal(ldb, ntds_guid);
1249 talloc_free(tmp_ctx);
1254 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1255 talloc_free(tmp_ctx);
1259 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1261 TALLOC_CTX *tmp_ctx;
1262 struct GUID *ntds_guid_new;
1263 struct GUID *ntds_guid_old;
1265 /* see if we have a cached copy */
1266 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1268 tmp_ctx = talloc_new(ldb);
1269 if (tmp_ctx == NULL) {
1273 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1274 if (!ntds_guid_new) {
1278 *ntds_guid_new = *ntds_guid_in;
1280 /* cache the domain_sid in the ldb */
1281 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1285 talloc_steal(ldb, ntds_guid_new);
1286 talloc_free(tmp_ctx);
1287 talloc_free(ntds_guid_old);
1292 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1293 talloc_free(tmp_ctx);
1298 work out the server dn for the current open ldb
1300 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1302 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1306 work out the server dn for the current open ldb
1308 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1310 struct ldb_dn *server_dn;
1311 struct ldb_dn *server_site_dn;
1313 server_dn = samdb_server_dn(ldb, mem_ctx);
1314 if (!server_dn) return NULL;
1316 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1318 talloc_free(server_dn);
1319 return server_site_dn;
1323 work out if we are the PDC for the domain of the current open ldb
1325 bool samdb_is_pdc(struct ldb_context *ldb)
1327 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1329 struct ldb_result *dom_res;
1330 TALLOC_CTX *tmp_ctx;
1334 tmp_ctx = talloc_new(ldb);
1335 if (tmp_ctx == NULL) {
1336 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1340 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1342 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1343 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1344 ldb_errstring(ldb)));
1347 talloc_steal(tmp_ctx, dom_res);
1348 if (dom_res->count != 1) {
1352 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1354 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1360 talloc_free(tmp_ctx);
1365 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1366 talloc_free(tmp_ctx);
1371 work out if we are a Global Catalog server for the domain of the current open ldb
1373 bool samdb_is_gc(struct ldb_context *ldb)
1375 const char *attrs[] = { "options", NULL };
1377 struct ldb_result *res;
1378 TALLOC_CTX *tmp_ctx;
1380 tmp_ctx = talloc_new(ldb);
1381 if (tmp_ctx == NULL) {
1382 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1386 /* Query cn=ntds settings,.... */
1387 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1391 if (res->count != 1) {
1396 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1398 talloc_free(tmp_ctx);
1400 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1401 if (options & 0x000000001) {
1407 /* Find a domain object in the parents of a particular DN. */
1408 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1409 struct ldb_dn **parent_dn, const char **errstring)
1411 TALLOC_CTX *local_ctx;
1412 struct ldb_dn *sdn = dn;
1413 struct ldb_result *res = NULL;
1415 const char *attrs[] = { NULL };
1417 local_ctx = talloc_new(mem_ctx);
1418 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1420 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1421 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1422 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1423 if (ret == LDB_SUCCESS) {
1424 talloc_steal(local_ctx, res);
1425 if (res->count == 1) {
1433 if (ret != LDB_SUCCESS) {
1434 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1435 ldb_dn_get_linearized(dn),
1436 ldb_dn_get_linearized(sdn),
1437 ldb_errstring(ldb));
1438 talloc_free(local_ctx);
1441 if (res->count != 1) {
1442 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1443 ldb_dn_get_linearized(dn));
1444 talloc_free(local_ctx);
1445 return LDB_ERR_CONSTRAINT_VIOLATION;
1448 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1449 talloc_free(local_ctx);
1454 check that a password is sufficiently complex
1456 static bool samdb_password_complexity_ok(const char *pass)
1458 return check_password_quality(pass);
1464 set the user password using plaintext, obeying any user or domain
1465 password restrictions
1467 note that this function doesn't actually store the result in the
1468 database, it just fills in the "mod" structure with ldb modify
1469 elements to setup the correct change when samdb_replace() is
1470 called. This allows the caller to combine the change with other
1471 changes (as is needed by some of the set user info levels)
1473 The caller should probably have a transaction wrapping this
1475 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1476 struct ldb_dn *user_dn,
1477 struct ldb_dn *domain_dn,
1478 struct ldb_message *mod,
1479 const char *new_pass,
1480 struct samr_Password *lmNewHash,
1481 struct samr_Password *ntNewHash,
1483 enum samr_RejectReason *reject_reason,
1484 struct samr_DomInfo1 **_dominfo)
1486 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1488 "dBCSPwd", "unicodePwd",
1490 "pwdLastSet", NULL };
1491 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1492 "maxPwdAge", "minPwdAge",
1493 "minPwdLength", NULL };
1496 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1497 uint_t userAccountControl;
1498 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1499 struct samr_Password local_lmNewHash, local_ntNewHash;
1500 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1501 struct dom_sid *domain_sid;
1502 struct ldb_message **res;
1505 time_t now = time(NULL);
1509 /* we need to know the time to compute password age */
1510 unix_to_nt_time(&now_nt, now);
1512 /* pull all the user parameters */
1513 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1515 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1517 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1518 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1519 "lmPwdHistory", &sambaLMPwdHistory);
1520 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1521 "ntPwdHistory", &sambaNTPwdHistory);
1522 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1523 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1524 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1526 /* Only non-trust accounts have restrictions (possibly this
1527 * test is the wrong way around, but I like to be restrictive
1529 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1530 |UF_WORKSTATION_TRUST_ACCOUNT
1531 |UF_SERVER_TRUST_ACCOUNT));
1534 /* pull the domain parameters */
1535 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1537 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1538 ldb_dn_get_linearized(domain_dn),
1539 ldb_dn_get_linearized(user_dn)));
1540 return NT_STATUS_NO_SUCH_DOMAIN;
1543 /* work out the domain sid, and pull the domain from there */
1544 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1545 if (domain_sid == NULL) {
1546 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1549 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1551 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1553 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1554 dom_sid_string(mem_ctx, domain_sid),
1555 ldb_dn_get_linearized(user_dn)));
1556 return NT_STATUS_NO_SUCH_DOMAIN;
1560 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1561 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1562 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1563 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1566 struct samr_DomInfo1 *dominfo;
1567 /* on failure we need to fill in the reject reasons */
1568 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1569 if (dominfo == NULL) {
1570 return NT_STATUS_NO_MEMORY;
1572 dominfo->min_password_length = minPwdLength;
1573 dominfo->password_properties = pwdProperties;
1574 dominfo->password_history_length = pwdHistoryLength;
1575 dominfo->max_password_age = minPwdAge;
1576 dominfo->min_password_age = minPwdAge;
1577 *_dominfo = dominfo;
1580 if (restrictions && new_pass) {
1582 /* check the various password restrictions */
1583 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1584 if (reject_reason) {
1585 *reject_reason = SAMR_REJECT_TOO_SHORT;
1587 return NT_STATUS_PASSWORD_RESTRICTION;
1590 /* possibly check password complexity */
1591 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1592 !samdb_password_complexity_ok(new_pass)) {
1593 if (reject_reason) {
1594 *reject_reason = SAMR_REJECT_COMPLEXITY;
1596 return NT_STATUS_PASSWORD_RESTRICTION;
1599 /* compute the new nt and lm hashes */
1600 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1601 lmNewHash = &local_lmNewHash;
1603 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1604 /* If we can't convert this password to UCS2, then we should not accept it */
1605 if (reject_reason) {
1606 *reject_reason = SAMR_REJECT_OTHER;
1608 return NT_STATUS_PASSWORD_RESTRICTION;
1610 ntNewHash = &local_ntNewHash;
1614 /* are all password changes disallowed? */
1615 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1616 if (reject_reason) {
1617 *reject_reason = SAMR_REJECT_OTHER;
1619 return NT_STATUS_PASSWORD_RESTRICTION;
1622 /* can this user change password? */
1623 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1624 if (reject_reason) {
1625 *reject_reason = SAMR_REJECT_OTHER;
1627 return NT_STATUS_PASSWORD_RESTRICTION;
1630 /* yes, this is a minus. The ages are in negative 100nsec units! */
1631 if (pwdLastSet - minPwdAge > now_nt) {
1632 if (reject_reason) {
1633 *reject_reason = SAMR_REJECT_OTHER;
1635 return NT_STATUS_PASSWORD_RESTRICTION;
1638 /* check the immediately past password */
1639 if (pwdHistoryLength > 0) {
1640 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1641 if (reject_reason) {
1642 *reject_reason = SAMR_REJECT_IN_HISTORY;
1644 return NT_STATUS_PASSWORD_RESTRICTION;
1646 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1647 if (reject_reason) {
1648 *reject_reason = SAMR_REJECT_IN_HISTORY;
1650 return NT_STATUS_PASSWORD_RESTRICTION;
1654 /* check the password history */
1655 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1656 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1658 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1659 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1660 if (reject_reason) {
1661 *reject_reason = SAMR_REJECT_IN_HISTORY;
1663 return NT_STATUS_PASSWORD_RESTRICTION;
1666 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1667 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1668 if (reject_reason) {
1669 *reject_reason = SAMR_REJECT_IN_HISTORY;
1671 return NT_STATUS_PASSWORD_RESTRICTION;
1676 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1678 /* the password is acceptable. Start forming the new fields */
1680 /* if we know the cleartext, then only set it.
1681 * Modules in ldb will set all the appropriate
1683 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1684 "sambaPassword", new_pass));
1686 /* We don't have the cleartext, so delete the old one
1687 * and set what we have of the hashes */
1688 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1691 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1693 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1697 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1699 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1703 return NT_STATUS_OK;
1708 set the user password using plaintext, obeying any user or domain
1709 password restrictions
1711 This wrapper function takes a SID as input, rather than a user DN,
1712 and actually performs the password change
1715 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1716 const struct dom_sid *user_sid,
1717 const char *new_pass,
1718 struct samr_Password *lmNewHash,
1719 struct samr_Password *ntNewHash,
1721 enum samr_RejectReason *reject_reason,
1722 struct samr_DomInfo1 **_dominfo)
1725 struct ldb_dn *user_dn;
1726 struct ldb_message *msg;
1729 ret = ldb_transaction_start(ctx);
1731 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1732 return NT_STATUS_TRANSACTION_ABORTED;
1735 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1736 "(&(objectSid=%s)(objectClass=user))",
1737 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1739 ldb_transaction_cancel(ctx);
1740 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1741 dom_sid_string(mem_ctx, user_sid)));
1742 return NT_STATUS_NO_SUCH_USER;
1745 msg = ldb_msg_new(mem_ctx);
1747 ldb_transaction_cancel(ctx);
1748 return NT_STATUS_NO_MEMORY;
1751 msg->dn = ldb_dn_copy(msg, user_dn);
1753 ldb_transaction_cancel(ctx);
1754 return NT_STATUS_NO_MEMORY;
1757 nt_status = samdb_set_password(ctx, mem_ctx,
1760 lmNewHash, ntNewHash,
1761 user_change, /* This is a password set, not change */
1762 reject_reason, _dominfo);
1763 if (!NT_STATUS_IS_OK(nt_status)) {
1764 ldb_transaction_cancel(ctx);
1768 /* modify the samdb record */
1769 ret = samdb_replace(ctx, mem_ctx, msg);
1771 ldb_transaction_cancel(ctx);
1772 return NT_STATUS_ACCESS_DENIED;
1775 ret = ldb_transaction_commit(ctx);
1777 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1778 ldb_dn_get_linearized(msg->dn),
1779 ldb_errstring(ctx)));
1780 return NT_STATUS_TRANSACTION_ABORTED;
1782 return NT_STATUS_OK;
1787 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1788 struct dom_sid *sid, struct ldb_dn **ret_dn)
1790 struct ldb_message *msg;
1791 struct ldb_dn *basedn;
1795 sidstr = dom_sid_string(mem_ctx, sid);
1796 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1798 /* We might have to create a ForeignSecurityPrincipal, even if this user
1799 * is in our own domain */
1801 msg = ldb_msg_new(mem_ctx);
1803 return NT_STATUS_NO_MEMORY;
1806 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1807 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1808 * not work, this is wrong for the Builtin domain, there's no
1809 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1812 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1813 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1815 if (basedn == NULL) {
1816 DEBUG(0, ("Failed to find DN for "
1817 "ForeignSecurityPrincipal container\n"));
1818 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1821 /* add core elements to the ldb_message for the alias */
1822 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1823 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1824 return NT_STATUS_NO_MEMORY;
1826 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1828 "foreignSecurityPrincipal");
1830 /* create the alias */
1831 ret = ldb_add(sam_ctx, msg);
1833 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1835 ldb_dn_get_linearized(msg->dn),
1836 ldb_errstring(sam_ctx)));
1837 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1840 return NT_STATUS_OK;
1845 Find the DN of a domain, assuming it to be a dotted.dns name
1848 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1851 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1852 const char *binary_encoded;
1853 const char **split_realm;
1860 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1862 talloc_free(tmp_ctx);
1865 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1866 for (i=0; split_realm[i]; i++) {
1867 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1868 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1869 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1870 binary_encoded, ldb_dn_get_linearized(dn)));
1871 talloc_free(tmp_ctx);
1875 if (!ldb_dn_validate(dn)) {
1876 DEBUG(2, ("Failed to validated DN %s\n",
1877 ldb_dn_get_linearized(dn)));
1883 Find the DN of a domain, be it the netbios or DNS name
1886 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1887 const char *domain_name)
1889 const char * const domain_ref_attrs[] = {
1892 const char * const domain_ref2_attrs[] = {
1895 struct ldb_result *res_domain_ref;
1896 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1897 /* find the domain's DN */
1898 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1900 samdb_partitions_dn(ldb, mem_ctx),
1903 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1905 if (ret_domain != 0) {
1909 if (res_domain_ref->count == 0) {
1910 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1912 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1915 "(objectclass=domain)");
1916 if (ret_domain != 0) {
1920 if (res_domain_ref->count == 1) {
1921 return res_domain_ref->msgs[0]->dn;
1926 if (res_domain_ref->count > 1) {
1927 DEBUG(0,("Found %d records matching domain [%s]\n",
1928 ret_domain, domain_name));
1932 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);