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 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
438 * indicate an account doesn't expire.
440 * When Windows initially creates an account, it sets
441 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
442 * when changing from an account having a specific expiration date to
443 * that account never expiring, it sets accountExpires = 0.
445 * Consolidate that logic here to allow clearer logic for account expiry in
446 * the rest of the code.
448 NTTIME samdb_result_account_expires(struct ldb_message *msg,
449 NTTIME default_value)
451 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
454 if (ret == (NTTIME)0)
455 ret = 0x7FFFFFFFFFFFFFFFULL;
461 pull a uint64_t from a result set.
463 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
465 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
470 construct the allow_password_change field from the PwdLastSet attribute and the
471 domain password settings
473 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
475 struct ldb_dn *domain_dn,
476 struct ldb_message *msg,
479 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
482 if (attr_time == 0) {
486 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
488 /* yes, this is a -= not a += as minPwdAge is stored as the negative
489 of the number of 100-nano-seconds */
490 attr_time -= minPwdAge;
496 construct the force_password_change field from the PwdLastSet
497 attribute, the userAccountControl and the domain password settings
499 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
501 struct ldb_dn *domain_dn,
502 struct ldb_message *msg)
504 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
505 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
508 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
509 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
510 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
511 return 0x7FFFFFFFFFFFFFFFULL;
514 if (attr_time == 0) {
518 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
519 if (maxPwdAge == 0) {
520 return 0x7FFFFFFFFFFFFFFFULL;
522 attr_time -= maxPwdAge;
529 pull a samr_Password structutre from a result set.
531 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
533 struct samr_Password *hash = NULL;
534 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
535 if (val && (val->length >= sizeof(hash->hash))) {
536 hash = talloc(mem_ctx, struct samr_Password);
537 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
543 pull an array of samr_Password structutres from a result set.
545 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
546 const char *attr, struct samr_Password **hashes)
549 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
556 count = val->length / 16;
561 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
566 for (i=0;i<count;i++) {
567 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
573 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
574 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
576 struct samr_Password *lmPwdHash, *ntPwdHash;
579 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
582 } else if (num_nt > 1) {
583 return NT_STATUS_INTERNAL_DB_CORRUPTION;
585 *nt_pwd = &ntPwdHash[0];
590 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
593 } else if (num_lm > 1) {
594 return NT_STATUS_INTERNAL_DB_CORRUPTION;
596 *lm_pwd = &lmPwdHash[0];
603 pull a samr_LogonHours structutre from a result set.
605 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
607 struct samr_LogonHours hours;
608 const int units_per_week = 168;
609 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
611 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
615 hours.units_per_week = units_per_week;
616 memset(hours.bits, 0xFF, units_per_week);
618 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
624 pull a set of account_flags from a result set.
626 This requires that the attributes:
631 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
632 struct ldb_message *msg, struct ldb_dn *domain_dn)
634 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
635 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
636 NTTIME must_change_time;
639 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
642 /* Test account expire time */
643 unix_to_nt_time(&now, time(NULL));
644 /* check for expired password */
645 if (must_change_time < now) {
646 acct_flags |= ACB_PW_EXPIRED;
652 /* Find an attribute, with a particular value */
654 /* The current callers of this function expect a very specific
655 * behaviour: In particular, objectClass subclass equivilance is not
656 * wanted. This means that we should not lookup the schema for the
657 * comparison function */
658 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
659 const struct ldb_message *msg,
660 const char *name, const char *value)
663 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
669 for (i=0;i<el->num_values;i++) {
670 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
678 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
680 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
681 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
686 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
688 struct ldb_message_element *el;
690 el = ldb_msg_find_element(msg, name);
695 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
701 add a string element to a message
703 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
704 const char *attr_name, const char *str)
706 char *s = talloc_strdup(mem_ctx, str);
707 char *a = talloc_strdup(mem_ctx, attr_name);
708 if (s == NULL || a == NULL) {
709 return LDB_ERR_OPERATIONS_ERROR;
711 return ldb_msg_add_string(msg, a, s);
715 add a dom_sid element to a message
717 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
718 const char *attr_name, struct dom_sid *sid)
721 enum ndr_err_code ndr_err;
723 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
724 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
726 (ndr_push_flags_fn_t)ndr_push_dom_sid);
727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
730 return ldb_msg_add_value(msg, attr_name, &v, NULL);
735 add a delete element operation to a message
737 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
738 const char *attr_name)
740 /* we use an empty replace rather than a delete, as it allows for
741 samdb_replace() to be used everywhere */
742 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
746 add a add attribute value to a message
748 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
749 const char *attr_name, const char *value)
751 struct ldb_message_element *el;
754 a = talloc_strdup(mem_ctx, attr_name);
757 v = talloc_strdup(mem_ctx, value);
760 ret = ldb_msg_add_string(msg, a, v);
763 el = ldb_msg_find_element(msg, a);
766 el->flags = LDB_FLAG_MOD_ADD;
771 add a delete attribute value to a message
773 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
774 const char *attr_name, const char *value)
776 struct ldb_message_element *el;
779 a = talloc_strdup(mem_ctx, attr_name);
782 v = talloc_strdup(mem_ctx, value);
785 ret = ldb_msg_add_string(msg, a, v);
788 el = ldb_msg_find_element(msg, a);
791 el->flags = LDB_FLAG_MOD_DELETE;
796 add a int element to a message
798 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
799 const char *attr_name, int v)
801 const char *s = talloc_asprintf(mem_ctx, "%d", v);
802 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
806 add a uint_t element to a message
808 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
809 const char *attr_name, uint_t v)
811 const char *s = talloc_asprintf(mem_ctx, "%u", v);
812 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
816 add a (signed) int64_t element to a message
818 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
819 const char *attr_name, int64_t v)
821 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
822 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
826 add a uint64_t element to a message
828 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
829 const char *attr_name, uint64_t v)
831 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
832 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
836 add a samr_Password element to a message
838 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
839 const char *attr_name, struct samr_Password *hash)
842 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
847 return ldb_msg_add_value(msg, attr_name, &val, NULL);
851 add a samr_Password array to a message
853 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
854 const char *attr_name, struct samr_Password *hashes, uint_t count)
858 val.data = talloc_array_size(mem_ctx, 16, count);
859 val.length = count*16;
863 for (i=0;i<count;i++) {
864 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
866 return ldb_msg_add_value(msg, attr_name, &val, NULL);
870 add a acct_flags element to a message
872 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
873 const char *attr_name, uint32_t v)
875 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
879 add a logon_hours element to a message
881 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
882 const char *attr_name, struct samr_LogonHours *hours)
885 val.length = hours->units_per_week / 8;
886 val.data = hours->bits;
887 return ldb_msg_add_value(msg, attr_name, &val, NULL);
891 add a general value element to a message
893 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
894 const char *attr_name, const struct ldb_val *val)
896 return ldb_msg_add_value(msg, attr_name, val, NULL);
900 sets a general value element to a message
902 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
903 const char *attr_name, const struct ldb_val *val)
905 struct ldb_message_element *el;
907 el = ldb_msg_find_element(msg, attr_name);
911 return ldb_msg_add_value(msg, attr_name, val, NULL);
915 set a string element in a message
917 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
918 const char *attr_name, const char *str)
920 struct ldb_message_element *el;
922 el = ldb_msg_find_element(msg, attr_name);
926 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
930 replace elements in a record
932 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
936 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
937 for (i=0;i<msg->num_elements;i++) {
938 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
941 /* modify the samdb record */
942 return ldb_modify(sam_ldb, msg);
946 return a default security descriptor
948 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
950 struct security_descriptor *sd;
952 sd = security_descriptor_initialise(mem_ctx);
957 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
959 return ldb_get_default_basedn(sam_ctx);
962 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
964 return ldb_get_config_basedn(sam_ctx);
967 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
969 return ldb_get_schema_basedn(sam_ctx);
972 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
974 return ldb_get_root_basedn(sam_ctx);
977 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
979 struct ldb_dn *new_dn;
981 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
982 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
989 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
991 struct ldb_dn *new_dn;
993 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
994 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1002 work out the domain sid for the current open ldb
1004 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1006 TALLOC_CTX *tmp_ctx;
1007 struct dom_sid *domain_sid;
1009 /* see if we have a cached copy */
1010 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1015 tmp_ctx = talloc_new(ldb);
1016 if (tmp_ctx == NULL) {
1020 /* find the domain_sid */
1021 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1022 "objectSid", "objectClass=domainDNS");
1023 if (domain_sid == NULL) {
1027 /* cache the domain_sid in the ldb */
1028 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1032 talloc_steal(ldb, domain_sid);
1033 talloc_free(tmp_ctx);
1038 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1039 talloc_free(tmp_ctx);
1043 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1045 TALLOC_CTX *tmp_ctx;
1046 struct dom_sid *dom_sid_new;
1047 struct dom_sid *dom_sid_old;
1049 /* see if we have a cached copy */
1050 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1051 "cache.domain_sid"), struct dom_sid);
1053 tmp_ctx = talloc_new(ldb);
1054 if (tmp_ctx == NULL) {
1058 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1063 /* cache the domain_sid in the ldb */
1064 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1068 talloc_steal(ldb, dom_sid_new);
1069 talloc_free(tmp_ctx);
1070 talloc_free(dom_sid_old);
1075 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1076 talloc_free(tmp_ctx);
1080 /* Obtain the short name of the flexible single master operator
1081 * (FSMO), such as the PDC Emulator */
1082 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1085 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1086 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1087 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1088 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1090 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1091 /* Ensure this matches the format. This gives us a
1092 * bit more confidence that a 'cn' value will be a
1097 return (char *)val->data;
1103 work out the ntds settings dn for the current open ldb
1105 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1107 TALLOC_CTX *tmp_ctx;
1108 const char *root_attrs[] = { "dsServiceName", NULL };
1110 struct ldb_result *root_res;
1111 struct ldb_dn *settings_dn;
1113 /* see if we have a cached copy */
1114 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1119 tmp_ctx = talloc_new(ldb);
1120 if (tmp_ctx == NULL) {
1125 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1127 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1128 ldb_errstring(ldb)));
1131 talloc_steal(tmp_ctx, root_res);
1133 if (root_res->count != 1) {
1137 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1139 /* cache the domain_sid in the ldb */
1140 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1144 talloc_steal(ldb, settings_dn);
1145 talloc_free(tmp_ctx);
1150 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1151 talloc_free(tmp_ctx);
1156 work out the ntds settings invocationId for the current open ldb
1158 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1160 TALLOC_CTX *tmp_ctx;
1161 const char *attrs[] = { "invocationId", NULL };
1163 struct ldb_result *res;
1164 struct GUID *invocation_id;
1166 /* see if we have a cached copy */
1167 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1168 if (invocation_id) {
1169 return invocation_id;
1172 tmp_ctx = talloc_new(ldb);
1173 if (tmp_ctx == NULL) {
1177 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1181 talloc_steal(tmp_ctx, res);
1183 if (res->count != 1) {
1187 invocation_id = talloc(tmp_ctx, struct GUID);
1188 if (!invocation_id) {
1192 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1194 /* cache the domain_sid in the ldb */
1195 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1199 talloc_steal(ldb, invocation_id);
1200 talloc_free(tmp_ctx);
1202 return invocation_id;
1205 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1206 talloc_free(tmp_ctx);
1210 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1212 TALLOC_CTX *tmp_ctx;
1213 struct GUID *invocation_id_new;
1214 struct GUID *invocation_id_old;
1216 /* see if we have a cached copy */
1217 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1218 "cache.invocation_id");
1220 tmp_ctx = talloc_new(ldb);
1221 if (tmp_ctx == NULL) {
1225 invocation_id_new = talloc(tmp_ctx, struct GUID);
1226 if (!invocation_id_new) {
1230 *invocation_id_new = *invocation_id_in;
1232 /* cache the domain_sid in the ldb */
1233 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1237 talloc_steal(ldb, invocation_id_new);
1238 talloc_free(tmp_ctx);
1239 talloc_free(invocation_id_old);
1244 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1245 talloc_free(tmp_ctx);
1250 work out the ntds settings objectGUID for the current open ldb
1252 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1254 TALLOC_CTX *tmp_ctx;
1255 const char *attrs[] = { "objectGUID", NULL };
1257 struct ldb_result *res;
1258 struct GUID *ntds_guid;
1260 /* see if we have a cached copy */
1261 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1266 tmp_ctx = talloc_new(ldb);
1267 if (tmp_ctx == NULL) {
1271 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1275 talloc_steal(tmp_ctx, res);
1277 if (res->count != 1) {
1281 ntds_guid = talloc(tmp_ctx, struct GUID);
1286 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1288 /* cache the domain_sid in the ldb */
1289 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1293 talloc_steal(ldb, ntds_guid);
1294 talloc_free(tmp_ctx);
1299 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1300 talloc_free(tmp_ctx);
1304 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1306 TALLOC_CTX *tmp_ctx;
1307 struct GUID *ntds_guid_new;
1308 struct GUID *ntds_guid_old;
1310 /* see if we have a cached copy */
1311 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1313 tmp_ctx = talloc_new(ldb);
1314 if (tmp_ctx == NULL) {
1318 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1319 if (!ntds_guid_new) {
1323 *ntds_guid_new = *ntds_guid_in;
1325 /* cache the domain_sid in the ldb */
1326 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1330 talloc_steal(ldb, ntds_guid_new);
1331 talloc_free(tmp_ctx);
1332 talloc_free(ntds_guid_old);
1337 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1338 talloc_free(tmp_ctx);
1343 work out the server dn for the current open ldb
1345 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1347 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1351 work out the server dn for the current open ldb
1353 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1355 struct ldb_dn *server_dn;
1356 struct ldb_dn *server_site_dn;
1358 server_dn = samdb_server_dn(ldb, mem_ctx);
1359 if (!server_dn) return NULL;
1361 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1363 talloc_free(server_dn);
1364 return server_site_dn;
1368 work out if we are the PDC for the domain of the current open ldb
1370 bool samdb_is_pdc(struct ldb_context *ldb)
1372 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1374 struct ldb_result *dom_res;
1375 TALLOC_CTX *tmp_ctx;
1379 tmp_ctx = talloc_new(ldb);
1380 if (tmp_ctx == NULL) {
1381 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1385 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1387 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1388 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1389 ldb_errstring(ldb)));
1392 talloc_steal(tmp_ctx, dom_res);
1393 if (dom_res->count != 1) {
1397 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1399 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1405 talloc_free(tmp_ctx);
1410 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1411 talloc_free(tmp_ctx);
1416 work out if we are a Global Catalog server for the domain of the current open ldb
1418 bool samdb_is_gc(struct ldb_context *ldb)
1420 const char *attrs[] = { "options", NULL };
1422 struct ldb_result *res;
1423 TALLOC_CTX *tmp_ctx;
1425 tmp_ctx = talloc_new(ldb);
1426 if (tmp_ctx == NULL) {
1427 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1431 /* Query cn=ntds settings,.... */
1432 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1436 if (res->count != 1) {
1441 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1443 talloc_free(tmp_ctx);
1445 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1446 if (options & 0x000000001) {
1452 /* Find a domain object in the parents of a particular DN. */
1453 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1454 struct ldb_dn **parent_dn, const char **errstring)
1456 TALLOC_CTX *local_ctx;
1457 struct ldb_dn *sdn = dn;
1458 struct ldb_result *res = NULL;
1460 const char *attrs[] = { NULL };
1462 local_ctx = talloc_new(mem_ctx);
1463 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1465 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1466 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1467 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))", attrs, &res);
1468 if (ret == LDB_SUCCESS) {
1469 talloc_steal(local_ctx, res);
1470 if (res->count == 1) {
1478 if (ret != LDB_SUCCESS) {
1479 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1480 ldb_dn_get_linearized(dn),
1481 ldb_dn_get_linearized(sdn),
1482 ldb_errstring(ldb));
1483 talloc_free(local_ctx);
1486 if (res->count != 1) {
1487 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1488 ldb_dn_get_linearized(dn));
1489 talloc_free(local_ctx);
1490 return LDB_ERR_CONSTRAINT_VIOLATION;
1493 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1494 talloc_free(local_ctx);
1499 check that a password is sufficiently complex
1501 static bool samdb_password_complexity_ok(const char *pass)
1503 return check_password_quality(pass);
1509 set the user password using plaintext, obeying any user or domain
1510 password restrictions
1512 note that this function doesn't actually store the result in the
1513 database, it just fills in the "mod" structure with ldb modify
1514 elements to setup the correct change when samdb_replace() is
1515 called. This allows the caller to combine the change with other
1516 changes (as is needed by some of the set user info levels)
1518 The caller should probably have a transaction wrapping this
1520 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1521 struct ldb_dn *user_dn,
1522 struct ldb_dn *domain_dn,
1523 struct ldb_message *mod,
1524 const char *new_pass,
1525 struct samr_Password *lmNewHash,
1526 struct samr_Password *ntNewHash,
1528 enum samr_RejectReason *reject_reason,
1529 struct samr_DomInfo1 **_dominfo)
1531 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1533 "dBCSPwd", "unicodePwd",
1535 "pwdLastSet", NULL };
1536 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1537 "maxPwdAge", "minPwdAge",
1538 "minPwdLength", NULL };
1541 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1542 uint_t userAccountControl;
1543 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1544 struct samr_Password local_lmNewHash, local_ntNewHash;
1545 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1546 struct dom_sid *domain_sid;
1547 struct ldb_message **res;
1550 time_t now = time(NULL);
1554 /* we need to know the time to compute password age */
1555 unix_to_nt_time(&now_nt, now);
1557 /* pull all the user parameters */
1558 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1560 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1562 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1563 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1564 "lmPwdHistory", &sambaLMPwdHistory);
1565 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1566 "ntPwdHistory", &sambaNTPwdHistory);
1567 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1568 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1569 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1571 /* Only non-trust accounts have restrictions (possibly this
1572 * test is the wrong way around, but I like to be restrictive
1574 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1575 |UF_WORKSTATION_TRUST_ACCOUNT
1576 |UF_SERVER_TRUST_ACCOUNT));
1579 /* pull the domain parameters */
1580 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1582 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1583 ldb_dn_get_linearized(domain_dn),
1584 ldb_dn_get_linearized(user_dn)));
1585 return NT_STATUS_NO_SUCH_DOMAIN;
1588 /* work out the domain sid, and pull the domain from there */
1589 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1590 if (domain_sid == NULL) {
1591 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1594 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1596 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1598 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1599 dom_sid_string(mem_ctx, domain_sid),
1600 ldb_dn_get_linearized(user_dn)));
1601 return NT_STATUS_NO_SUCH_DOMAIN;
1605 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1606 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1607 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1608 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1611 struct samr_DomInfo1 *dominfo;
1612 /* on failure we need to fill in the reject reasons */
1613 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1614 if (dominfo == NULL) {
1615 return NT_STATUS_NO_MEMORY;
1617 dominfo->min_password_length = minPwdLength;
1618 dominfo->password_properties = pwdProperties;
1619 dominfo->password_history_length = pwdHistoryLength;
1620 dominfo->max_password_age = minPwdAge;
1621 dominfo->min_password_age = minPwdAge;
1622 *_dominfo = dominfo;
1625 if (restrictions && new_pass) {
1627 /* check the various password restrictions */
1628 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1629 if (reject_reason) {
1630 *reject_reason = SAMR_REJECT_TOO_SHORT;
1632 return NT_STATUS_PASSWORD_RESTRICTION;
1635 /* possibly check password complexity */
1636 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1637 !samdb_password_complexity_ok(new_pass)) {
1638 if (reject_reason) {
1639 *reject_reason = SAMR_REJECT_COMPLEXITY;
1641 return NT_STATUS_PASSWORD_RESTRICTION;
1644 /* compute the new nt and lm hashes */
1645 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1646 lmNewHash = &local_lmNewHash;
1648 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1649 /* If we can't convert this password to UCS2, then we should not accept it */
1650 if (reject_reason) {
1651 *reject_reason = SAMR_REJECT_OTHER;
1653 return NT_STATUS_PASSWORD_RESTRICTION;
1655 ntNewHash = &local_ntNewHash;
1659 /* are all password changes disallowed? */
1660 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1661 if (reject_reason) {
1662 *reject_reason = SAMR_REJECT_OTHER;
1664 return NT_STATUS_PASSWORD_RESTRICTION;
1667 /* can this user change password? */
1668 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1669 if (reject_reason) {
1670 *reject_reason = SAMR_REJECT_OTHER;
1672 return NT_STATUS_PASSWORD_RESTRICTION;
1675 /* yes, this is a minus. The ages are in negative 100nsec units! */
1676 if (pwdLastSet - minPwdAge > now_nt) {
1677 if (reject_reason) {
1678 *reject_reason = SAMR_REJECT_OTHER;
1680 return NT_STATUS_PASSWORD_RESTRICTION;
1683 /* check the immediately past password */
1684 if (pwdHistoryLength > 0) {
1685 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1686 if (reject_reason) {
1687 *reject_reason = SAMR_REJECT_IN_HISTORY;
1689 return NT_STATUS_PASSWORD_RESTRICTION;
1691 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1692 if (reject_reason) {
1693 *reject_reason = SAMR_REJECT_IN_HISTORY;
1695 return NT_STATUS_PASSWORD_RESTRICTION;
1699 /* check the password history */
1700 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1701 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1703 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1704 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1705 if (reject_reason) {
1706 *reject_reason = SAMR_REJECT_IN_HISTORY;
1708 return NT_STATUS_PASSWORD_RESTRICTION;
1711 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1712 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1713 if (reject_reason) {
1714 *reject_reason = SAMR_REJECT_IN_HISTORY;
1716 return NT_STATUS_PASSWORD_RESTRICTION;
1721 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1723 /* the password is acceptable. Start forming the new fields */
1725 /* if we know the cleartext, then only set it.
1726 * Modules in ldb will set all the appropriate
1728 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1729 "sambaPassword", new_pass));
1731 /* We don't have the cleartext, so delete the old one
1732 * and set what we have of the hashes */
1733 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1736 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1738 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1742 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1744 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1748 return NT_STATUS_OK;
1753 set the user password using plaintext, obeying any user or domain
1754 password restrictions
1756 This wrapper function takes a SID as input, rather than a user DN,
1757 and actually performs the password change
1760 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1761 const struct dom_sid *user_sid,
1762 const char *new_pass,
1763 struct samr_Password *lmNewHash,
1764 struct samr_Password *ntNewHash,
1766 enum samr_RejectReason *reject_reason,
1767 struct samr_DomInfo1 **_dominfo)
1770 struct ldb_dn *user_dn;
1771 struct ldb_message *msg;
1774 ret = ldb_transaction_start(ctx);
1776 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1777 return NT_STATUS_TRANSACTION_ABORTED;
1780 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1781 "(&(objectSid=%s)(objectClass=user))",
1782 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1784 ldb_transaction_cancel(ctx);
1785 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1786 dom_sid_string(mem_ctx, user_sid)));
1787 return NT_STATUS_NO_SUCH_USER;
1790 msg = ldb_msg_new(mem_ctx);
1792 ldb_transaction_cancel(ctx);
1793 return NT_STATUS_NO_MEMORY;
1796 msg->dn = ldb_dn_copy(msg, user_dn);
1798 ldb_transaction_cancel(ctx);
1799 return NT_STATUS_NO_MEMORY;
1802 nt_status = samdb_set_password(ctx, mem_ctx,
1805 lmNewHash, ntNewHash,
1806 user_change, /* This is a password set, not change */
1807 reject_reason, _dominfo);
1808 if (!NT_STATUS_IS_OK(nt_status)) {
1809 ldb_transaction_cancel(ctx);
1813 /* modify the samdb record */
1814 ret = samdb_replace(ctx, mem_ctx, msg);
1816 ldb_transaction_cancel(ctx);
1817 return NT_STATUS_ACCESS_DENIED;
1820 ret = ldb_transaction_commit(ctx);
1822 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1823 ldb_dn_get_linearized(msg->dn),
1824 ldb_errstring(ctx)));
1825 return NT_STATUS_TRANSACTION_ABORTED;
1827 return NT_STATUS_OK;
1832 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1833 struct dom_sid *sid, struct ldb_dn **ret_dn)
1835 struct ldb_message *msg;
1836 struct ldb_dn *basedn;
1840 sidstr = dom_sid_string(mem_ctx, sid);
1841 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1843 /* We might have to create a ForeignSecurityPrincipal, even if this user
1844 * is in our own domain */
1846 msg = ldb_msg_new(mem_ctx);
1848 return NT_STATUS_NO_MEMORY;
1851 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1852 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1853 * not work, this is wrong for the Builtin domain, there's no
1854 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1857 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1858 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1860 if (basedn == NULL) {
1861 DEBUG(0, ("Failed to find DN for "
1862 "ForeignSecurityPrincipal container\n"));
1863 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1866 /* add core elements to the ldb_message for the alias */
1867 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1868 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1869 return NT_STATUS_NO_MEMORY;
1871 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1873 "foreignSecurityPrincipal");
1875 /* create the alias */
1876 ret = ldb_add(sam_ctx, msg);
1878 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1880 ldb_dn_get_linearized(msg->dn),
1881 ldb_errstring(sam_ctx)));
1882 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1885 return NT_STATUS_OK;
1890 Find the DN of a domain, assuming it to be a dotted.dns name
1893 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1896 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1897 const char *binary_encoded;
1898 const char **split_realm;
1905 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1907 talloc_free(tmp_ctx);
1910 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1911 for (i=0; split_realm[i]; i++) {
1912 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1913 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1914 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1915 binary_encoded, ldb_dn_get_linearized(dn)));
1916 talloc_free(tmp_ctx);
1920 if (!ldb_dn_validate(dn)) {
1921 DEBUG(2, ("Failed to validated DN %s\n",
1922 ldb_dn_get_linearized(dn)));
1928 Find the DN of a domain, be it the netbios or DNS name
1931 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1932 const char *domain_name)
1934 const char * const domain_ref_attrs[] = {
1937 const char * const domain_ref2_attrs[] = {
1940 struct ldb_result *res_domain_ref;
1941 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1942 /* find the domain's DN */
1943 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1945 samdb_partitions_dn(ldb, mem_ctx),
1948 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1950 if (ret_domain != 0) {
1954 if (res_domain_ref->count == 0) {
1955 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1957 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1960 "(objectclass=domain)");
1961 if (ret_domain != 0) {
1965 if (res_domain_ref->count == 1) {
1966 return res_domain_ref->msgs[0]->dn;
1971 if (res_domain_ref->count > 1) {
1972 DEBUG(0,("Found %d records matching domain [%s]\n",
1973 ret_domain, domain_name));
1977 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);