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
473 attribute, the userAccountControl and the 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 userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
484 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
485 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
486 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
487 return 0x7FFFFFFFFFFFFFFFULL;
490 if (attr_time == 0) {
494 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
495 if (maxPwdAge == 0) {
498 attr_time -= maxPwdAge;
505 pull a samr_Password structutre from a result set.
507 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
509 struct samr_Password *hash = NULL;
510 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
511 if (val && (val->length >= sizeof(hash->hash))) {
512 hash = talloc(mem_ctx, struct samr_Password);
513 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
519 pull an array of samr_Password structutres from a result set.
521 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
522 const char *attr, struct samr_Password **hashes)
525 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
532 count = val->length / 16;
537 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
542 for (i=0;i<count;i++) {
543 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
549 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
550 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
552 struct samr_Password *lmPwdHash, *ntPwdHash;
555 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
558 } else if (num_nt > 1) {
559 return NT_STATUS_INTERNAL_DB_CORRUPTION;
561 *nt_pwd = &ntPwdHash[0];
566 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
569 } else if (num_lm > 1) {
570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
572 *lm_pwd = &lmPwdHash[0];
579 pull a samr_LogonHours structutre from a result set.
581 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
583 struct samr_LogonHours hours;
584 const int units_per_week = 168;
585 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
587 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
591 hours.units_per_week = units_per_week;
592 memset(hours.bits, 0xFF, units_per_week);
594 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
600 pull a set of account_flags from a result set.
602 This requires that the attributes:
607 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
608 struct ldb_message *msg, struct ldb_dn *domain_dn)
610 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
611 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
612 NTTIME must_change_time;
615 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
618 /* Test account expire time */
619 unix_to_nt_time(&now, time(NULL));
620 /* check for expired password */
621 if (must_change_time < now) {
622 acct_flags |= ACB_PW_EXPIRED;
628 /* Find an attribute, with a particular value */
630 /* The current callers of this function expect a very specific
631 * behaviour: In particular, objectClass subclass equivilance is not
632 * wanted. This means that we should not lookup the schema for the
633 * comparison function */
634 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
635 const struct ldb_message *msg,
636 const char *name, const char *value)
639 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
645 for (i=0;i<el->num_values;i++) {
646 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
654 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
656 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
657 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
662 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
664 struct ldb_message_element *el;
666 el = ldb_msg_find_element(msg, name);
671 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
677 add a string element to a message
679 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
680 const char *attr_name, const char *str)
682 char *s = talloc_strdup(mem_ctx, str);
683 char *a = talloc_strdup(mem_ctx, attr_name);
684 if (s == NULL || a == NULL) {
685 return LDB_ERR_OPERATIONS_ERROR;
687 return ldb_msg_add_string(msg, a, s);
691 add a dom_sid element to a message
693 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
694 const char *attr_name, struct dom_sid *sid)
697 enum ndr_err_code ndr_err;
699 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
700 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
702 (ndr_push_flags_fn_t)ndr_push_dom_sid);
703 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
706 return ldb_msg_add_value(msg, attr_name, &v, NULL);
711 add a delete element operation to a message
713 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
714 const char *attr_name)
716 /* we use an empty replace rather than a delete, as it allows for
717 samdb_replace() to be used everywhere */
718 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
722 add a add attribute value to a message
724 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
725 const char *attr_name, const char *value)
727 struct ldb_message_element *el;
730 a = talloc_strdup(mem_ctx, attr_name);
733 v = talloc_strdup(mem_ctx, value);
736 ret = ldb_msg_add_string(msg, a, v);
739 el = ldb_msg_find_element(msg, a);
742 el->flags = LDB_FLAG_MOD_ADD;
747 add a delete attribute value to a message
749 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
750 const char *attr_name, const char *value)
752 struct ldb_message_element *el;
755 a = talloc_strdup(mem_ctx, attr_name);
758 v = talloc_strdup(mem_ctx, value);
761 ret = ldb_msg_add_string(msg, a, v);
764 el = ldb_msg_find_element(msg, a);
767 el->flags = LDB_FLAG_MOD_DELETE;
772 add a int element to a message
774 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
775 const char *attr_name, int v)
777 const char *s = talloc_asprintf(mem_ctx, "%d", v);
778 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
782 add a uint_t element to a message
784 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name, uint_t v)
787 const char *s = talloc_asprintf(mem_ctx, "%u", v);
788 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
792 add a (signed) int64_t element to a message
794 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
795 const char *attr_name, int64_t v)
797 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
798 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
802 add a uint64_t element to a message
804 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
805 const char *attr_name, uint64_t v)
807 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
808 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
812 add a samr_Password element to a message
814 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
815 const char *attr_name, struct samr_Password *hash)
818 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
823 return ldb_msg_add_value(msg, attr_name, &val, NULL);
827 add a samr_Password array to a message
829 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
830 const char *attr_name, struct samr_Password *hashes, uint_t count)
834 val.data = talloc_array_size(mem_ctx, 16, count);
835 val.length = count*16;
839 for (i=0;i<count;i++) {
840 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
842 return ldb_msg_add_value(msg, attr_name, &val, NULL);
846 add a acct_flags element to a message
848 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849 const char *attr_name, uint32_t v)
851 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
855 add a logon_hours element to a message
857 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
858 const char *attr_name, struct samr_LogonHours *hours)
861 val.length = hours->units_per_week / 8;
862 val.data = hours->bits;
863 return ldb_msg_add_value(msg, attr_name, &val, NULL);
867 add a general value element to a message
869 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
870 const char *attr_name, const struct ldb_val *val)
872 return ldb_msg_add_value(msg, attr_name, val, NULL);
876 sets a general value element to a message
878 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
879 const char *attr_name, const struct ldb_val *val)
881 struct ldb_message_element *el;
883 el = ldb_msg_find_element(msg, attr_name);
887 return ldb_msg_add_value(msg, attr_name, val, NULL);
891 set a string element in a message
893 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
894 const char *attr_name, const char *str)
896 struct ldb_message_element *el;
898 el = ldb_msg_find_element(msg, attr_name);
902 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
906 replace elements in a record
908 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
912 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
913 for (i=0;i<msg->num_elements;i++) {
914 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
917 /* modify the samdb record */
918 return ldb_modify(sam_ldb, msg);
922 return a default security descriptor
924 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
926 struct security_descriptor *sd;
928 sd = security_descriptor_initialise(mem_ctx);
933 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
935 return ldb_get_default_basedn(sam_ctx);
938 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
940 return ldb_get_config_basedn(sam_ctx);
943 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
945 return ldb_get_schema_basedn(sam_ctx);
948 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
950 return ldb_get_root_basedn(sam_ctx);
953 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
955 struct ldb_dn *new_dn;
957 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
958 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
965 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
967 struct ldb_dn *new_dn;
969 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
970 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
978 work out the domain sid for the current open ldb
980 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
983 struct dom_sid *domain_sid;
985 /* see if we have a cached copy */
986 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
991 tmp_ctx = talloc_new(ldb);
992 if (tmp_ctx == NULL) {
996 /* find the domain_sid */
997 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
998 "objectSid", "objectClass=domainDNS");
999 if (domain_sid == NULL) {
1003 /* cache the domain_sid in the ldb */
1004 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1008 talloc_steal(ldb, domain_sid);
1009 talloc_free(tmp_ctx);
1014 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1015 talloc_free(tmp_ctx);
1019 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1021 TALLOC_CTX *tmp_ctx;
1022 struct dom_sid *dom_sid_new;
1023 struct dom_sid *dom_sid_old;
1025 /* see if we have a cached copy */
1026 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1027 "cache.domain_sid"), struct dom_sid);
1029 tmp_ctx = talloc_new(ldb);
1030 if (tmp_ctx == NULL) {
1034 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1039 /* cache the domain_sid in the ldb */
1040 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1044 talloc_steal(ldb, dom_sid_new);
1045 talloc_free(tmp_ctx);
1046 talloc_free(dom_sid_old);
1051 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1052 talloc_free(tmp_ctx);
1056 /* Obtain the short name of the flexible single master operator
1057 * (FSMO), such as the PDC Emulator */
1058 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1061 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1062 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1063 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1064 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1066 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1067 /* Ensure this matches the format. This gives us a
1068 * bit more confidence that a 'cn' value will be a
1073 return (char *)val->data;
1079 work out the ntds settings dn for the current open ldb
1081 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1083 TALLOC_CTX *tmp_ctx;
1084 const char *root_attrs[] = { "dsServiceName", NULL };
1086 struct ldb_result *root_res;
1087 struct ldb_dn *settings_dn;
1089 /* see if we have a cached copy */
1090 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1095 tmp_ctx = talloc_new(ldb);
1096 if (tmp_ctx == NULL) {
1101 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1103 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1104 ldb_errstring(ldb)));
1107 talloc_steal(tmp_ctx, root_res);
1109 if (root_res->count != 1) {
1113 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1115 /* cache the domain_sid in the ldb */
1116 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1120 talloc_steal(ldb, settings_dn);
1121 talloc_free(tmp_ctx);
1126 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1127 talloc_free(tmp_ctx);
1132 work out the ntds settings invocationId for the current open ldb
1134 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1136 TALLOC_CTX *tmp_ctx;
1137 const char *attrs[] = { "invocationId", NULL };
1139 struct ldb_result *res;
1140 struct GUID *invocation_id;
1142 /* see if we have a cached copy */
1143 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1144 if (invocation_id) {
1145 return invocation_id;
1148 tmp_ctx = talloc_new(ldb);
1149 if (tmp_ctx == NULL) {
1153 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1157 talloc_steal(tmp_ctx, res);
1159 if (res->count != 1) {
1163 invocation_id = talloc(tmp_ctx, struct GUID);
1164 if (!invocation_id) {
1168 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1170 /* cache the domain_sid in the ldb */
1171 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1175 talloc_steal(ldb, invocation_id);
1176 talloc_free(tmp_ctx);
1178 return invocation_id;
1181 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1182 talloc_free(tmp_ctx);
1186 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1188 TALLOC_CTX *tmp_ctx;
1189 struct GUID *invocation_id_new;
1190 struct GUID *invocation_id_old;
1192 /* see if we have a cached copy */
1193 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1194 "cache.invocation_id");
1196 tmp_ctx = talloc_new(ldb);
1197 if (tmp_ctx == NULL) {
1201 invocation_id_new = talloc(tmp_ctx, struct GUID);
1202 if (!invocation_id_new) {
1206 *invocation_id_new = *invocation_id_in;
1208 /* cache the domain_sid in the ldb */
1209 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1213 talloc_steal(ldb, invocation_id_new);
1214 talloc_free(tmp_ctx);
1215 talloc_free(invocation_id_old);
1220 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1221 talloc_free(tmp_ctx);
1226 work out the ntds settings objectGUID for the current open ldb
1228 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1230 TALLOC_CTX *tmp_ctx;
1231 const char *attrs[] = { "objectGUID", NULL };
1233 struct ldb_result *res;
1234 struct GUID *ntds_guid;
1236 /* see if we have a cached copy */
1237 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1242 tmp_ctx = talloc_new(ldb);
1243 if (tmp_ctx == NULL) {
1247 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1251 talloc_steal(tmp_ctx, res);
1253 if (res->count != 1) {
1257 ntds_guid = talloc(tmp_ctx, struct GUID);
1262 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1264 /* cache the domain_sid in the ldb */
1265 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1269 talloc_steal(ldb, ntds_guid);
1270 talloc_free(tmp_ctx);
1275 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1276 talloc_free(tmp_ctx);
1280 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1282 TALLOC_CTX *tmp_ctx;
1283 struct GUID *ntds_guid_new;
1284 struct GUID *ntds_guid_old;
1286 /* see if we have a cached copy */
1287 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1289 tmp_ctx = talloc_new(ldb);
1290 if (tmp_ctx == NULL) {
1294 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1295 if (!ntds_guid_new) {
1299 *ntds_guid_new = *ntds_guid_in;
1301 /* cache the domain_sid in the ldb */
1302 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1306 talloc_steal(ldb, ntds_guid_new);
1307 talloc_free(tmp_ctx);
1308 talloc_free(ntds_guid_old);
1313 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314 talloc_free(tmp_ctx);
1319 work out the server dn for the current open ldb
1321 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1323 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1327 work out the server dn for the current open ldb
1329 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1331 struct ldb_dn *server_dn;
1332 struct ldb_dn *server_site_dn;
1334 server_dn = samdb_server_dn(ldb, mem_ctx);
1335 if (!server_dn) return NULL;
1337 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1339 talloc_free(server_dn);
1340 return server_site_dn;
1344 work out if we are the PDC for the domain of the current open ldb
1346 bool samdb_is_pdc(struct ldb_context *ldb)
1348 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1350 struct ldb_result *dom_res;
1351 TALLOC_CTX *tmp_ctx;
1355 tmp_ctx = talloc_new(ldb);
1356 if (tmp_ctx == NULL) {
1357 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1361 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1363 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1364 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1365 ldb_errstring(ldb)));
1368 talloc_steal(tmp_ctx, dom_res);
1369 if (dom_res->count != 1) {
1373 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1375 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1381 talloc_free(tmp_ctx);
1386 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1387 talloc_free(tmp_ctx);
1392 work out if we are a Global Catalog server for the domain of the current open ldb
1394 bool samdb_is_gc(struct ldb_context *ldb)
1396 const char *attrs[] = { "options", NULL };
1398 struct ldb_result *res;
1399 TALLOC_CTX *tmp_ctx;
1401 tmp_ctx = talloc_new(ldb);
1402 if (tmp_ctx == NULL) {
1403 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1407 /* Query cn=ntds settings,.... */
1408 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1412 if (res->count != 1) {
1417 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1419 talloc_free(tmp_ctx);
1421 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1422 if (options & 0x000000001) {
1428 /* Find a domain object in the parents of a particular DN. */
1429 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1430 struct ldb_dn **parent_dn, const char **errstring)
1432 TALLOC_CTX *local_ctx;
1433 struct ldb_dn *sdn = dn;
1434 struct ldb_result *res = NULL;
1436 const char *attrs[] = { NULL };
1438 local_ctx = talloc_new(mem_ctx);
1439 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1441 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1442 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1443 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1444 if (ret == LDB_SUCCESS) {
1445 talloc_steal(local_ctx, res);
1446 if (res->count == 1) {
1454 if (ret != LDB_SUCCESS) {
1455 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1456 ldb_dn_get_linearized(dn),
1457 ldb_dn_get_linearized(sdn),
1458 ldb_errstring(ldb));
1459 talloc_free(local_ctx);
1462 if (res->count != 1) {
1463 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1464 ldb_dn_get_linearized(dn));
1465 talloc_free(local_ctx);
1466 return LDB_ERR_CONSTRAINT_VIOLATION;
1469 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1470 talloc_free(local_ctx);
1475 check that a password is sufficiently complex
1477 static bool samdb_password_complexity_ok(const char *pass)
1479 return check_password_quality(pass);
1485 set the user password using plaintext, obeying any user or domain
1486 password restrictions
1488 note that this function doesn't actually store the result in the
1489 database, it just fills in the "mod" structure with ldb modify
1490 elements to setup the correct change when samdb_replace() is
1491 called. This allows the caller to combine the change with other
1492 changes (as is needed by some of the set user info levels)
1494 The caller should probably have a transaction wrapping this
1496 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1497 struct ldb_dn *user_dn,
1498 struct ldb_dn *domain_dn,
1499 struct ldb_message *mod,
1500 const char *new_pass,
1501 struct samr_Password *lmNewHash,
1502 struct samr_Password *ntNewHash,
1504 enum samr_RejectReason *reject_reason,
1505 struct samr_DomInfo1 **_dominfo)
1507 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1509 "dBCSPwd", "unicodePwd",
1511 "pwdLastSet", NULL };
1512 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1513 "maxPwdAge", "minPwdAge",
1514 "minPwdLength", NULL };
1517 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1518 uint_t userAccountControl;
1519 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1520 struct samr_Password local_lmNewHash, local_ntNewHash;
1521 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1522 struct dom_sid *domain_sid;
1523 struct ldb_message **res;
1526 time_t now = time(NULL);
1530 /* we need to know the time to compute password age */
1531 unix_to_nt_time(&now_nt, now);
1533 /* pull all the user parameters */
1534 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1536 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1538 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1539 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1540 "lmPwdHistory", &sambaLMPwdHistory);
1541 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1542 "ntPwdHistory", &sambaNTPwdHistory);
1543 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1544 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1545 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1547 /* Only non-trust accounts have restrictions (possibly this
1548 * test is the wrong way around, but I like to be restrictive
1550 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1551 |UF_WORKSTATION_TRUST_ACCOUNT
1552 |UF_SERVER_TRUST_ACCOUNT));
1555 /* pull the domain parameters */
1556 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1558 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1559 ldb_dn_get_linearized(domain_dn),
1560 ldb_dn_get_linearized(user_dn)));
1561 return NT_STATUS_NO_SUCH_DOMAIN;
1564 /* work out the domain sid, and pull the domain from there */
1565 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1566 if (domain_sid == NULL) {
1567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1570 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1572 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1574 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1575 dom_sid_string(mem_ctx, domain_sid),
1576 ldb_dn_get_linearized(user_dn)));
1577 return NT_STATUS_NO_SUCH_DOMAIN;
1581 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1582 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1583 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1584 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1587 struct samr_DomInfo1 *dominfo;
1588 /* on failure we need to fill in the reject reasons */
1589 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1590 if (dominfo == NULL) {
1591 return NT_STATUS_NO_MEMORY;
1593 dominfo->min_password_length = minPwdLength;
1594 dominfo->password_properties = pwdProperties;
1595 dominfo->password_history_length = pwdHistoryLength;
1596 dominfo->max_password_age = minPwdAge;
1597 dominfo->min_password_age = minPwdAge;
1598 *_dominfo = dominfo;
1601 if (restrictions && new_pass) {
1603 /* check the various password restrictions */
1604 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1605 if (reject_reason) {
1606 *reject_reason = SAMR_REJECT_TOO_SHORT;
1608 return NT_STATUS_PASSWORD_RESTRICTION;
1611 /* possibly check password complexity */
1612 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1613 !samdb_password_complexity_ok(new_pass)) {
1614 if (reject_reason) {
1615 *reject_reason = SAMR_REJECT_COMPLEXITY;
1617 return NT_STATUS_PASSWORD_RESTRICTION;
1620 /* compute the new nt and lm hashes */
1621 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1622 lmNewHash = &local_lmNewHash;
1624 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1625 /* If we can't convert this password to UCS2, then we should not accept it */
1626 if (reject_reason) {
1627 *reject_reason = SAMR_REJECT_OTHER;
1629 return NT_STATUS_PASSWORD_RESTRICTION;
1631 ntNewHash = &local_ntNewHash;
1635 /* are all password changes disallowed? */
1636 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1637 if (reject_reason) {
1638 *reject_reason = SAMR_REJECT_OTHER;
1640 return NT_STATUS_PASSWORD_RESTRICTION;
1643 /* can this user change password? */
1644 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1645 if (reject_reason) {
1646 *reject_reason = SAMR_REJECT_OTHER;
1648 return NT_STATUS_PASSWORD_RESTRICTION;
1651 /* yes, this is a minus. The ages are in negative 100nsec units! */
1652 if (pwdLastSet - minPwdAge > now_nt) {
1653 if (reject_reason) {
1654 *reject_reason = SAMR_REJECT_OTHER;
1656 return NT_STATUS_PASSWORD_RESTRICTION;
1659 /* check the immediately past password */
1660 if (pwdHistoryLength > 0) {
1661 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1662 if (reject_reason) {
1663 *reject_reason = SAMR_REJECT_IN_HISTORY;
1665 return NT_STATUS_PASSWORD_RESTRICTION;
1667 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1668 if (reject_reason) {
1669 *reject_reason = SAMR_REJECT_IN_HISTORY;
1671 return NT_STATUS_PASSWORD_RESTRICTION;
1675 /* check the password history */
1676 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1677 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1679 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1680 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1681 if (reject_reason) {
1682 *reject_reason = SAMR_REJECT_IN_HISTORY;
1684 return NT_STATUS_PASSWORD_RESTRICTION;
1687 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1688 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1689 if (reject_reason) {
1690 *reject_reason = SAMR_REJECT_IN_HISTORY;
1692 return NT_STATUS_PASSWORD_RESTRICTION;
1697 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1699 /* the password is acceptable. Start forming the new fields */
1701 /* if we know the cleartext, then only set it.
1702 * Modules in ldb will set all the appropriate
1704 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1705 "sambaPassword", new_pass));
1707 /* We don't have the cleartext, so delete the old one
1708 * and set what we have of the hashes */
1709 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1712 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1714 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1718 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1720 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1724 return NT_STATUS_OK;
1729 set the user password using plaintext, obeying any user or domain
1730 password restrictions
1732 This wrapper function takes a SID as input, rather than a user DN,
1733 and actually performs the password change
1736 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1737 const struct dom_sid *user_sid,
1738 const char *new_pass,
1739 struct samr_Password *lmNewHash,
1740 struct samr_Password *ntNewHash,
1742 enum samr_RejectReason *reject_reason,
1743 struct samr_DomInfo1 **_dominfo)
1746 struct ldb_dn *user_dn;
1747 struct ldb_message *msg;
1750 ret = ldb_transaction_start(ctx);
1752 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1753 return NT_STATUS_TRANSACTION_ABORTED;
1756 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1757 "(&(objectSid=%s)(objectClass=user))",
1758 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1760 ldb_transaction_cancel(ctx);
1761 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1762 dom_sid_string(mem_ctx, user_sid)));
1763 return NT_STATUS_NO_SUCH_USER;
1766 msg = ldb_msg_new(mem_ctx);
1768 ldb_transaction_cancel(ctx);
1769 return NT_STATUS_NO_MEMORY;
1772 msg->dn = ldb_dn_copy(msg, user_dn);
1774 ldb_transaction_cancel(ctx);
1775 return NT_STATUS_NO_MEMORY;
1778 nt_status = samdb_set_password(ctx, mem_ctx,
1781 lmNewHash, ntNewHash,
1782 user_change, /* This is a password set, not change */
1783 reject_reason, _dominfo);
1784 if (!NT_STATUS_IS_OK(nt_status)) {
1785 ldb_transaction_cancel(ctx);
1789 /* modify the samdb record */
1790 ret = samdb_replace(ctx, mem_ctx, msg);
1792 ldb_transaction_cancel(ctx);
1793 return NT_STATUS_ACCESS_DENIED;
1796 ret = ldb_transaction_commit(ctx);
1798 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1799 ldb_dn_get_linearized(msg->dn),
1800 ldb_errstring(ctx)));
1801 return NT_STATUS_TRANSACTION_ABORTED;
1803 return NT_STATUS_OK;
1808 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1809 struct dom_sid *sid, struct ldb_dn **ret_dn)
1811 struct ldb_message *msg;
1812 struct ldb_dn *basedn;
1816 sidstr = dom_sid_string(mem_ctx, sid);
1817 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1819 /* We might have to create a ForeignSecurityPrincipal, even if this user
1820 * is in our own domain */
1822 msg = ldb_msg_new(mem_ctx);
1824 return NT_STATUS_NO_MEMORY;
1827 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1828 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1829 * not work, this is wrong for the Builtin domain, there's no
1830 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1833 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1834 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1836 if (basedn == NULL) {
1837 DEBUG(0, ("Failed to find DN for "
1838 "ForeignSecurityPrincipal container\n"));
1839 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1842 /* add core elements to the ldb_message for the alias */
1843 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1844 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1845 return NT_STATUS_NO_MEMORY;
1847 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1849 "foreignSecurityPrincipal");
1851 /* create the alias */
1852 ret = ldb_add(sam_ctx, msg);
1854 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1856 ldb_dn_get_linearized(msg->dn),
1857 ldb_errstring(sam_ctx)));
1858 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1861 return NT_STATUS_OK;
1866 Find the DN of a domain, assuming it to be a dotted.dns name
1869 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1872 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1873 const char *binary_encoded;
1874 const char **split_realm;
1881 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1883 talloc_free(tmp_ctx);
1886 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1887 for (i=0; split_realm[i]; i++) {
1888 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1889 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1890 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1891 binary_encoded, ldb_dn_get_linearized(dn)));
1892 talloc_free(tmp_ctx);
1896 if (!ldb_dn_validate(dn)) {
1897 DEBUG(2, ("Failed to validated DN %s\n",
1898 ldb_dn_get_linearized(dn)));
1904 Find the DN of a domain, be it the netbios or DNS name
1907 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1908 const char *domain_name)
1910 const char * const domain_ref_attrs[] = {
1913 const char * const domain_ref2_attrs[] = {
1916 struct ldb_result *res_domain_ref;
1917 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1918 /* find the domain's DN */
1919 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1921 samdb_partitions_dn(ldb, mem_ctx),
1924 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1926 if (ret_domain != 0) {
1930 if (res_domain_ref->count == 0) {
1931 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1933 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1936 "(objectclass=domain)");
1937 if (ret_domain != 0) {
1941 if (res_domain_ref->count == 1) {
1942 return res_domain_ref->msgs[0]->dn;
1947 if (res_domain_ref->count > 1) {
1948 DEBUG(0,("Found %d records matching domain [%s]\n",
1949 ret_domain, domain_name));
1953 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);