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/>.
27 #include "ldb_errors.h"
28 #include "lib/util/util_ldb.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "libcli/security/security.h"
31 #include "librpc/gen_ndr/ndr_security.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "dsdb/common/flags.h"
34 #include "dsdb/common/proto.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "param/param.h"
37 #include "libcli/auth/libcli_auth.h"
40 search the sam for the specified attributes in a specific domain, filter on
41 objectSid being in domain_sid.
43 int samdb_search_domain(struct ldb_context *sam_ldb,
45 struct ldb_dn *basedn,
46 struct ldb_message ***res,
47 const char * const *attrs,
48 const struct dom_sid *domain_sid,
49 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
55 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
56 res, attrs, format, ap);
62 struct dom_sid *entry_sid;
64 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
66 if ((entry_sid == NULL) ||
67 (!dom_sid_in_domain(domain_sid, entry_sid))) {
68 /* Delete that entry from the result set */
69 (*res)[i] = (*res)[count-1];
71 talloc_free(entry_sid);
74 talloc_free(entry_sid);
82 search the sam for a single string attribute in exactly 1 record
84 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
86 struct ldb_dn *basedn,
87 const char *attr_name,
88 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
91 const char *attrs[2] = { NULL, NULL };
92 struct ldb_message **res = NULL;
96 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
98 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
99 attr_name, format, count));
106 return samdb_result_string(res[0], attr_name, NULL);
111 search the sam for a single string attribute in exactly 1 record
113 const char *samdb_search_string(struct ldb_context *sam_ldb,
115 struct ldb_dn *basedn,
116 const char *attr_name,
117 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
122 va_start(ap, format);
123 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
129 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
131 struct ldb_dn *basedn,
132 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
136 struct ldb_message **res = NULL;
139 va_start(ap, format);
140 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
143 if (count != 1) return NULL;
145 ret = talloc_steal(mem_ctx, res[0]->dn);
152 search the sam for a dom_sid attribute in exactly 1 record
154 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
156 struct ldb_dn *basedn,
157 const char *attr_name,
158 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
162 struct ldb_message **res;
163 const char *attrs[2] = { NULL, NULL };
166 attrs[0] = attr_name;
168 va_start(ap, format);
169 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
172 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
173 attr_name, format, count));
179 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
185 return the count of the number of records in the sam matching the query
187 int samdb_search_count(struct ldb_context *sam_ldb,
189 struct ldb_dn *basedn,
190 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
193 struct ldb_message **res;
194 const char * const attrs[] = { NULL };
197 va_start(ap, format);
198 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
206 search the sam for a single integer attribute in exactly 1 record
208 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
210 uint_t default_value,
211 struct ldb_dn *basedn,
212 const char *attr_name,
213 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
217 struct ldb_message **res;
218 const char *attrs[2] = { NULL, NULL };
220 attrs[0] = attr_name;
222 va_start(ap, format);
223 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
227 return default_value;
230 return samdb_result_uint(res[0], attr_name, default_value);
234 search the sam for a single signed 64 bit integer attribute in exactly 1 record
236 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
238 int64_t default_value,
239 struct ldb_dn *basedn,
240 const char *attr_name,
241 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
245 struct ldb_message **res;
246 const char *attrs[2] = { NULL, NULL };
248 attrs[0] = attr_name;
250 va_start(ap, format);
251 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
255 return default_value;
258 return samdb_result_int64(res[0], attr_name, default_value);
262 search the sam for multipe records each giving a single string attribute
263 return the number of matches, or -1 on error
265 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
267 struct ldb_dn *basedn,
269 const char *attr_name,
270 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
274 const char *attrs[2] = { NULL, NULL };
275 struct ldb_message **res = NULL;
277 attrs[0] = attr_name;
279 va_start(ap, format);
280 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
287 /* make sure its single valued */
288 for (i=0;i<count;i++) {
289 if (res[i]->num_elements != 1) {
290 DEBUG(1,("samdb: search for %s %s not single valued\n",
297 *strs = talloc_array(mem_ctx, const char *, count+1);
303 for (i=0;i<count;i++) {
304 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
306 (*strs)[count] = NULL;
312 pull a uint from a result set.
314 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
316 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
320 pull a (signed) int64 from a result set.
322 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
324 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
328 pull a string from a result set.
330 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
331 const char *default_value)
333 return ldb_msg_find_attr_as_string(msg, attr, default_value);
336 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
337 const char *attr, struct ldb_dn *default_value)
339 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
341 return default_value;
347 pull a rid from a objectSid in a result set.
349 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
350 const char *attr, uint32_t default_value)
355 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
357 return default_value;
359 rid = sid->sub_auths[sid->num_auths-1];
365 pull a dom_sid structure from a objectSid in a result set.
367 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
370 const struct ldb_val *v;
372 enum ndr_err_code ndr_err;
373 v = ldb_msg_find_ldb_val(msg, attr);
377 sid = talloc(mem_ctx, struct dom_sid);
381 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
382 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
391 pull a guid structure from a objectGUID in a result set.
393 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
395 const struct ldb_val *v;
396 enum ndr_err_code ndr_err;
402 v = ldb_msg_find_ldb_val(msg, attr);
405 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
406 if (!mem_ctx) return guid;
407 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
408 (ndr_pull_flags_fn_t)ndr_pull_GUID);
409 talloc_free(mem_ctx);
410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418 pull a sid prefix from a objectSid in a result set.
419 this is used to find the domain sid for a user
421 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
424 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
425 if (!sid || sid->num_auths < 1) return NULL;
431 pull a NTTIME in a result set.
433 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
435 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
439 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
440 * indicate an account doesn't expire.
442 * When Windows initially creates an account, it sets
443 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
444 * when changing from an account having a specific expiration date to
445 * that account never expiring, it sets accountExpires = 0.
447 * Consolidate that logic here to allow clearer logic for account expiry in
448 * the rest of the code.
450 NTTIME samdb_result_account_expires(struct ldb_message *msg)
452 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
456 ret = 0x7FFFFFFFFFFFFFFFULL;
462 pull a uint64_t from a result set.
464 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
466 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
471 construct the allow_password_change field from the PwdLastSet attribute and the
472 domain password settings
474 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
476 struct ldb_dn *domain_dn,
477 struct ldb_message *msg,
480 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
483 if (attr_time == 0) {
487 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
489 /* yes, this is a -= not a += as minPwdAge is stored as the negative
490 of the number of 100-nano-seconds */
491 attr_time -= minPwdAge;
497 construct the force_password_change field from the PwdLastSet
498 attribute, the userAccountControl and the domain password settings
500 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
502 struct ldb_dn *domain_dn,
503 struct ldb_message *msg)
505 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
506 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
509 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
510 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
511 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
512 return 0x7FFFFFFFFFFFFFFFULL;
515 if (attr_time == 0) {
519 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
520 if (maxPwdAge == 0) {
521 return 0x7FFFFFFFFFFFFFFFULL;
523 attr_time -= maxPwdAge;
530 pull a samr_Password structutre from a result set.
532 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
534 struct samr_Password *hash = NULL;
535 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
536 if (val && (val->length >= sizeof(hash->hash))) {
537 hash = talloc(mem_ctx, struct samr_Password);
538 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
544 pull an array of samr_Password structutres from a result set.
546 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
547 const char *attr, struct samr_Password **hashes)
550 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
557 count = val->length / 16;
562 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
567 for (i=0;i<count;i++) {
568 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
574 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
575 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
577 struct samr_Password *lmPwdHash, *ntPwdHash;
580 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
583 } else if (num_nt > 1) {
584 return NT_STATUS_INTERNAL_DB_CORRUPTION;
586 *nt_pwd = &ntPwdHash[0];
591 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
594 } else if (num_lm > 1) {
595 return NT_STATUS_INTERNAL_DB_CORRUPTION;
597 *lm_pwd = &lmPwdHash[0];
604 pull a samr_LogonHours structutre from a result set.
606 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
608 struct samr_LogonHours hours;
609 const int units_per_week = 168;
610 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
612 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
616 hours.units_per_week = units_per_week;
617 memset(hours.bits, 0xFF, units_per_week);
619 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
625 pull a set of account_flags from a result set.
627 This requires that the attributes:
632 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
633 struct ldb_message *msg, struct ldb_dn *domain_dn)
635 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
636 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
637 NTTIME must_change_time;
640 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
643 /* Test account expire time */
644 unix_to_nt_time(&now, time(NULL));
645 /* check for expired password */
646 if (must_change_time < now) {
647 acct_flags |= ACB_PW_EXPIRED;
653 /* Find an attribute, with a particular value */
655 /* The current callers of this function expect a very specific
656 * behaviour: In particular, objectClass subclass equivilance is not
657 * wanted. This means that we should not lookup the schema for the
658 * comparison function */
659 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
660 const struct ldb_message *msg,
661 const char *name, const char *value)
664 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
670 for (i=0;i<el->num_values;i++) {
671 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
679 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
681 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
682 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
687 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
689 struct ldb_message_element *el;
691 el = ldb_msg_find_element(msg, name);
696 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
702 add a string element to a message
704 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
705 const char *attr_name, const char *str)
707 char *s = talloc_strdup(mem_ctx, str);
708 char *a = talloc_strdup(mem_ctx, attr_name);
709 if (s == NULL || a == NULL) {
710 return LDB_ERR_OPERATIONS_ERROR;
712 return ldb_msg_add_string(msg, a, s);
716 add a dom_sid element to a message
718 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
719 const char *attr_name, struct dom_sid *sid)
722 enum ndr_err_code ndr_err;
724 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
725 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
727 (ndr_push_flags_fn_t)ndr_push_dom_sid);
728 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
731 return ldb_msg_add_value(msg, attr_name, &v, NULL);
736 add a delete element operation to a message
738 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
739 const char *attr_name)
741 /* we use an empty replace rather than a delete, as it allows for
742 samdb_replace() to be used everywhere */
743 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
747 add a add attribute value to a message
749 int samdb_msg_add_addval(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_ADD;
772 add a delete attribute value to a message
774 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
775 const char *attr_name, const char *value)
777 struct ldb_message_element *el;
780 a = talloc_strdup(mem_ctx, attr_name);
783 v = talloc_strdup(mem_ctx, value);
786 ret = ldb_msg_add_string(msg, a, v);
789 el = ldb_msg_find_element(msg, a);
792 el->flags = LDB_FLAG_MOD_DELETE;
797 add a int element to a message
799 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
800 const char *attr_name, int v)
802 const char *s = talloc_asprintf(mem_ctx, "%d", v);
803 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
807 add a uint_t element to a message
809 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
810 const char *attr_name, uint_t v)
812 const char *s = talloc_asprintf(mem_ctx, "%u", v);
813 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
817 add a (signed) int64_t element to a message
819 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820 const char *attr_name, int64_t v)
822 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
823 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
827 add a uint64_t element to a message
829 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
830 const char *attr_name, uint64_t v)
832 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
833 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
837 add a samr_Password element to a message
839 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name, struct samr_Password *hash)
843 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
848 return ldb_msg_add_value(msg, attr_name, &val, NULL);
852 add a samr_Password array to a message
854 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
855 const char *attr_name, struct samr_Password *hashes, uint_t count)
859 val.data = talloc_array_size(mem_ctx, 16, count);
860 val.length = count*16;
864 for (i=0;i<count;i++) {
865 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
867 return ldb_msg_add_value(msg, attr_name, &val, NULL);
871 add a acct_flags element to a message
873 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
874 const char *attr_name, uint32_t v)
876 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
880 add a logon_hours element to a message
882 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
883 const char *attr_name, struct samr_LogonHours *hours)
886 val.length = hours->units_per_week / 8;
887 val.data = hours->bits;
888 return ldb_msg_add_value(msg, attr_name, &val, NULL);
892 add a general value element to a message
894 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
895 const char *attr_name, const struct ldb_val *val)
897 return ldb_msg_add_value(msg, attr_name, val, NULL);
901 sets a general value element to a message
903 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
904 const char *attr_name, const struct ldb_val *val)
906 struct ldb_message_element *el;
908 el = ldb_msg_find_element(msg, attr_name);
912 return ldb_msg_add_value(msg, attr_name, val, NULL);
916 set a string element in a message
918 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
919 const char *attr_name, const char *str)
921 struct ldb_message_element *el;
923 el = ldb_msg_find_element(msg, attr_name);
927 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
931 replace elements in a record
933 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
937 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
938 for (i=0;i<msg->num_elements;i++) {
939 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
942 /* modify the samdb record */
943 return ldb_modify(sam_ldb, msg);
947 return a default security descriptor
949 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
951 struct security_descriptor *sd;
953 sd = security_descriptor_initialise(mem_ctx);
958 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
960 return ldb_get_default_basedn(sam_ctx);
963 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
965 return ldb_get_config_basedn(sam_ctx);
968 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
970 return ldb_get_schema_basedn(sam_ctx);
973 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
975 return ldb_get_root_basedn(sam_ctx);
978 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
980 struct ldb_dn *new_dn;
982 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
983 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
990 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
992 struct ldb_dn *new_dn;
994 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
995 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1003 work out the domain sid for the current open ldb
1005 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1007 TALLOC_CTX *tmp_ctx;
1008 const struct dom_sid *domain_sid;
1009 const char *attrs[] = {
1013 struct ldb_result *res;
1016 /* see if we have a cached copy */
1017 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1022 tmp_ctx = talloc_new(ldb);
1023 if (tmp_ctx == NULL) {
1027 ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1029 if (ret != LDB_SUCCESS) {
1033 if (res->count != 1) {
1037 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1038 if (domain_sid == NULL) {
1042 /* cache the domain_sid in the ldb */
1043 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1047 talloc_steal(ldb, domain_sid);
1048 talloc_free(tmp_ctx);
1053 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1054 talloc_free(tmp_ctx);
1058 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1060 TALLOC_CTX *tmp_ctx;
1061 struct dom_sid *dom_sid_new;
1062 struct dom_sid *dom_sid_old;
1064 /* see if we have a cached copy */
1065 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1066 "cache.domain_sid"), struct dom_sid);
1068 tmp_ctx = talloc_new(ldb);
1069 if (tmp_ctx == NULL) {
1073 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1078 /* cache the domain_sid in the ldb */
1079 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1083 talloc_steal(ldb, dom_sid_new);
1084 talloc_free(tmp_ctx);
1085 talloc_free(dom_sid_old);
1090 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1091 talloc_free(tmp_ctx);
1095 /* Obtain the short name of the flexible single master operator
1096 * (FSMO), such as the PDC Emulator */
1097 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1100 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1101 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1102 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1103 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1105 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1106 /* Ensure this matches the format. This gives us a
1107 * bit more confidence that a 'cn' value will be a
1112 return (char *)val->data;
1118 work out the ntds settings dn for the current open ldb
1120 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1122 TALLOC_CTX *tmp_ctx;
1123 const char *root_attrs[] = { "dsServiceName", NULL };
1125 struct ldb_result *root_res;
1126 struct ldb_dn *settings_dn;
1128 /* see if we have a cached copy */
1129 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1134 tmp_ctx = talloc_new(ldb);
1135 if (tmp_ctx == NULL) {
1140 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1142 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1143 ldb_errstring(ldb)));
1146 talloc_steal(tmp_ctx, root_res);
1148 if (root_res->count != 1) {
1152 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1154 /* cache the domain_sid in the ldb */
1155 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1159 talloc_steal(ldb, settings_dn);
1160 talloc_free(tmp_ctx);
1165 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1166 talloc_free(tmp_ctx);
1171 work out the ntds settings invocationId for the current open ldb
1173 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1175 TALLOC_CTX *tmp_ctx;
1176 const char *attrs[] = { "invocationId", NULL };
1178 struct ldb_result *res;
1179 struct GUID *invocation_id;
1181 /* see if we have a cached copy */
1182 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1183 if (invocation_id) {
1184 return invocation_id;
1187 tmp_ctx = talloc_new(ldb);
1188 if (tmp_ctx == NULL) {
1192 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1196 talloc_steal(tmp_ctx, res);
1198 if (res->count != 1) {
1202 invocation_id = talloc(tmp_ctx, struct GUID);
1203 if (!invocation_id) {
1207 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1209 /* cache the domain_sid in the ldb */
1210 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1214 talloc_steal(ldb, invocation_id);
1215 talloc_free(tmp_ctx);
1217 return invocation_id;
1220 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1221 talloc_free(tmp_ctx);
1225 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1227 TALLOC_CTX *tmp_ctx;
1228 struct GUID *invocation_id_new;
1229 struct GUID *invocation_id_old;
1231 /* see if we have a cached copy */
1232 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1233 "cache.invocation_id");
1235 tmp_ctx = talloc_new(ldb);
1236 if (tmp_ctx == NULL) {
1240 invocation_id_new = talloc(tmp_ctx, struct GUID);
1241 if (!invocation_id_new) {
1245 *invocation_id_new = *invocation_id_in;
1247 /* cache the domain_sid in the ldb */
1248 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1252 talloc_steal(ldb, invocation_id_new);
1253 talloc_free(tmp_ctx);
1254 talloc_free(invocation_id_old);
1259 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1260 talloc_free(tmp_ctx);
1265 work out the ntds settings objectGUID for the current open ldb
1267 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1269 TALLOC_CTX *tmp_ctx;
1270 const char *attrs[] = { "objectGUID", NULL };
1272 struct ldb_result *res;
1273 struct GUID *ntds_guid;
1275 /* see if we have a cached copy */
1276 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1281 tmp_ctx = talloc_new(ldb);
1282 if (tmp_ctx == NULL) {
1286 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1290 talloc_steal(tmp_ctx, res);
1292 if (res->count != 1) {
1296 ntds_guid = talloc(tmp_ctx, struct GUID);
1301 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1303 /* cache the domain_sid in the ldb */
1304 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1308 talloc_steal(ldb, ntds_guid);
1309 talloc_free(tmp_ctx);
1314 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1315 talloc_free(tmp_ctx);
1319 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1321 TALLOC_CTX *tmp_ctx;
1322 struct GUID *ntds_guid_new;
1323 struct GUID *ntds_guid_old;
1325 /* see if we have a cached copy */
1326 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1328 tmp_ctx = talloc_new(ldb);
1329 if (tmp_ctx == NULL) {
1333 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1334 if (!ntds_guid_new) {
1338 *ntds_guid_new = *ntds_guid_in;
1340 /* cache the domain_sid in the ldb */
1341 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1345 talloc_steal(ldb, ntds_guid_new);
1346 talloc_free(tmp_ctx);
1347 talloc_free(ntds_guid_old);
1352 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1353 talloc_free(tmp_ctx);
1358 work out the server dn for the current open ldb
1360 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1362 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1366 work out the server dn for the current open ldb
1368 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1370 struct ldb_dn *server_dn;
1371 struct ldb_dn *server_site_dn;
1373 server_dn = samdb_server_dn(ldb, mem_ctx);
1374 if (!server_dn) return NULL;
1376 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1378 talloc_free(server_dn);
1379 return server_site_dn;
1383 work out if we are the PDC for the domain of the current open ldb
1385 bool samdb_is_pdc(struct ldb_context *ldb)
1387 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1389 struct ldb_result *dom_res;
1390 TALLOC_CTX *tmp_ctx;
1394 tmp_ctx = talloc_new(ldb);
1395 if (tmp_ctx == NULL) {
1396 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1400 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1402 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1403 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1404 ldb_errstring(ldb)));
1407 talloc_steal(tmp_ctx, dom_res);
1408 if (dom_res->count != 1) {
1412 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1414 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1420 talloc_free(tmp_ctx);
1425 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1426 talloc_free(tmp_ctx);
1431 work out if we are a Global Catalog server for the domain of the current open ldb
1433 bool samdb_is_gc(struct ldb_context *ldb)
1435 const char *attrs[] = { "options", NULL };
1437 struct ldb_result *res;
1438 TALLOC_CTX *tmp_ctx;
1440 tmp_ctx = talloc_new(ldb);
1441 if (tmp_ctx == NULL) {
1442 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1446 /* Query cn=ntds settings,.... */
1447 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1451 if (res->count != 1) {
1456 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1458 talloc_free(tmp_ctx);
1460 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1461 if (options & 0x000000001) {
1467 /* Find a domain object in the parents of a particular DN. */
1468 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1469 struct ldb_dn **parent_dn, const char **errstring)
1471 TALLOC_CTX *local_ctx;
1472 struct ldb_dn *sdn = dn;
1473 struct ldb_result *res = NULL;
1475 const char *attrs[] = { NULL };
1477 local_ctx = talloc_new(mem_ctx);
1478 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1480 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1481 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1482 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))", attrs, &res);
1483 if (ret == LDB_SUCCESS) {
1484 talloc_steal(local_ctx, res);
1485 if (res->count == 1) {
1493 if (ret != LDB_SUCCESS) {
1494 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1495 ldb_dn_get_linearized(dn),
1496 ldb_dn_get_linearized(sdn),
1497 ldb_errstring(ldb));
1498 talloc_free(local_ctx);
1501 if (res->count != 1) {
1502 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1503 ldb_dn_get_linearized(dn));
1504 talloc_free(local_ctx);
1505 return LDB_ERR_CONSTRAINT_VIOLATION;
1508 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1509 talloc_free(local_ctx);
1514 check that a password is sufficiently complex
1516 static bool samdb_password_complexity_ok(const char *pass)
1518 return check_password_quality(pass);
1524 set the user password using plaintext, obeying any user or domain
1525 password restrictions
1527 note that this function doesn't actually store the result in the
1528 database, it just fills in the "mod" structure with ldb modify
1529 elements to setup the correct change when samdb_replace() is
1530 called. This allows the caller to combine the change with other
1531 changes (as is needed by some of the set user info levels)
1533 The caller should probably have a transaction wrapping this
1535 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1536 struct ldb_dn *user_dn,
1537 struct ldb_dn *domain_dn,
1538 struct ldb_message *mod,
1539 const char *new_pass,
1540 struct samr_Password *lmNewHash,
1541 struct samr_Password *ntNewHash,
1543 enum samr_RejectReason *reject_reason,
1544 struct samr_DomInfo1 **_dominfo)
1546 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1548 "dBCSPwd", "unicodePwd",
1550 "pwdLastSet", NULL };
1551 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1552 "maxPwdAge", "minPwdAge",
1553 "minPwdLength", NULL };
1556 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1557 uint_t userAccountControl;
1558 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1559 struct samr_Password local_lmNewHash, local_ntNewHash;
1560 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1561 struct dom_sid *domain_sid;
1562 struct ldb_message **res;
1565 time_t now = time(NULL);
1569 /* we need to know the time to compute password age */
1570 unix_to_nt_time(&now_nt, now);
1572 /* pull all the user parameters */
1573 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1575 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1577 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1578 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1579 "lmPwdHistory", &sambaLMPwdHistory);
1580 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1581 "ntPwdHistory", &sambaNTPwdHistory);
1582 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1583 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1584 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1586 /* Only non-trust accounts have restrictions (possibly this
1587 * test is the wrong way around, but I like to be restrictive
1589 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1590 |UF_WORKSTATION_TRUST_ACCOUNT
1591 |UF_SERVER_TRUST_ACCOUNT));
1594 /* pull the domain parameters */
1595 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1597 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1598 ldb_dn_get_linearized(domain_dn),
1599 ldb_dn_get_linearized(user_dn)));
1600 return NT_STATUS_NO_SUCH_DOMAIN;
1603 /* work out the domain sid, and pull the domain from there */
1604 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1605 if (domain_sid == NULL) {
1606 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1609 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1611 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1613 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1614 dom_sid_string(mem_ctx, domain_sid),
1615 ldb_dn_get_linearized(user_dn)));
1616 return NT_STATUS_NO_SUCH_DOMAIN;
1620 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1621 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1622 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1623 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1626 struct samr_DomInfo1 *dominfo;
1627 /* on failure we need to fill in the reject reasons */
1628 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1629 if (dominfo == NULL) {
1630 return NT_STATUS_NO_MEMORY;
1632 dominfo->min_password_length = minPwdLength;
1633 dominfo->password_properties = pwdProperties;
1634 dominfo->password_history_length = pwdHistoryLength;
1635 dominfo->max_password_age = minPwdAge;
1636 dominfo->min_password_age = minPwdAge;
1637 *_dominfo = dominfo;
1640 if (restrictions && new_pass) {
1642 /* check the various password restrictions */
1643 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1644 if (reject_reason) {
1645 *reject_reason = SAMR_REJECT_TOO_SHORT;
1647 return NT_STATUS_PASSWORD_RESTRICTION;
1650 /* possibly check password complexity */
1651 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1652 !samdb_password_complexity_ok(new_pass)) {
1653 if (reject_reason) {
1654 *reject_reason = SAMR_REJECT_COMPLEXITY;
1656 return NT_STATUS_PASSWORD_RESTRICTION;
1659 /* compute the new nt and lm hashes */
1660 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1661 lmNewHash = &local_lmNewHash;
1663 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1664 /* If we can't convert this password to UCS2, then we should not accept it */
1665 if (reject_reason) {
1666 *reject_reason = SAMR_REJECT_OTHER;
1668 return NT_STATUS_PASSWORD_RESTRICTION;
1670 ntNewHash = &local_ntNewHash;
1674 /* are all password changes disallowed? */
1675 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1676 if (reject_reason) {
1677 *reject_reason = SAMR_REJECT_OTHER;
1679 return NT_STATUS_PASSWORD_RESTRICTION;
1682 /* can this user change password? */
1683 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1684 if (reject_reason) {
1685 *reject_reason = SAMR_REJECT_OTHER;
1687 return NT_STATUS_PASSWORD_RESTRICTION;
1690 /* yes, this is a minus. The ages are in negative 100nsec units! */
1691 if (pwdLastSet - minPwdAge > now_nt) {
1692 if (reject_reason) {
1693 *reject_reason = SAMR_REJECT_OTHER;
1695 return NT_STATUS_PASSWORD_RESTRICTION;
1698 /* check the immediately past password */
1699 if (pwdHistoryLength > 0) {
1700 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1701 if (reject_reason) {
1702 *reject_reason = SAMR_REJECT_IN_HISTORY;
1704 return NT_STATUS_PASSWORD_RESTRICTION;
1706 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1707 if (reject_reason) {
1708 *reject_reason = SAMR_REJECT_IN_HISTORY;
1710 return NT_STATUS_PASSWORD_RESTRICTION;
1714 /* check the password history */
1715 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1716 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1718 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1719 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1720 if (reject_reason) {
1721 *reject_reason = SAMR_REJECT_IN_HISTORY;
1723 return NT_STATUS_PASSWORD_RESTRICTION;
1726 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1727 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1728 if (reject_reason) {
1729 *reject_reason = SAMR_REJECT_IN_HISTORY;
1731 return NT_STATUS_PASSWORD_RESTRICTION;
1736 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1738 /* the password is acceptable. Start forming the new fields */
1740 /* if we know the cleartext, then only set it.
1741 * Modules in ldb will set all the appropriate
1743 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1744 "userPassword", new_pass));
1746 /* We don't have the cleartext, so delete the old one
1747 * and set what we have of the hashes */
1748 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "userPassword"));
1751 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1753 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1757 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1759 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1763 return NT_STATUS_OK;
1768 set the user password using plaintext, obeying any user or domain
1769 password restrictions
1771 This wrapper function takes a SID as input, rather than a user DN,
1772 and actually performs the password change
1775 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1776 const struct dom_sid *user_sid,
1777 const char *new_pass,
1778 struct samr_Password *lmNewHash,
1779 struct samr_Password *ntNewHash,
1781 enum samr_RejectReason *reject_reason,
1782 struct samr_DomInfo1 **_dominfo)
1785 struct ldb_dn *user_dn;
1786 struct ldb_message *msg;
1789 ret = ldb_transaction_start(ctx);
1791 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1792 return NT_STATUS_TRANSACTION_ABORTED;
1795 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1796 "(&(objectSid=%s)(objectClass=user))",
1797 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1799 ldb_transaction_cancel(ctx);
1800 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1801 dom_sid_string(mem_ctx, user_sid)));
1802 return NT_STATUS_NO_SUCH_USER;
1805 msg = ldb_msg_new(mem_ctx);
1807 ldb_transaction_cancel(ctx);
1808 return NT_STATUS_NO_MEMORY;
1811 msg->dn = ldb_dn_copy(msg, user_dn);
1813 ldb_transaction_cancel(ctx);
1814 return NT_STATUS_NO_MEMORY;
1817 nt_status = samdb_set_password(ctx, mem_ctx,
1820 lmNewHash, ntNewHash,
1821 user_change, /* This is a password set, not change */
1822 reject_reason, _dominfo);
1823 if (!NT_STATUS_IS_OK(nt_status)) {
1824 ldb_transaction_cancel(ctx);
1828 /* modify the samdb record */
1829 ret = samdb_replace(ctx, mem_ctx, msg);
1831 ldb_transaction_cancel(ctx);
1832 return NT_STATUS_ACCESS_DENIED;
1835 ret = ldb_transaction_commit(ctx);
1837 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1838 ldb_dn_get_linearized(msg->dn),
1839 ldb_errstring(ctx)));
1840 return NT_STATUS_TRANSACTION_ABORTED;
1842 return NT_STATUS_OK;
1847 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1848 struct dom_sid *sid, struct ldb_dn **ret_dn)
1850 struct ldb_message *msg;
1851 struct ldb_dn *basedn;
1855 sidstr = dom_sid_string(mem_ctx, sid);
1856 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1858 /* We might have to create a ForeignSecurityPrincipal, even if this user
1859 * is in our own domain */
1861 msg = ldb_msg_new(mem_ctx);
1863 return NT_STATUS_NO_MEMORY;
1866 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1867 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1868 * not work, this is wrong for the Builtin domain, there's no
1869 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1872 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1873 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1875 if (basedn == NULL) {
1876 DEBUG(0, ("Failed to find DN for "
1877 "ForeignSecurityPrincipal container\n"));
1878 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1881 /* add core elements to the ldb_message for the alias */
1882 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1883 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1884 return NT_STATUS_NO_MEMORY;
1886 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1888 "foreignSecurityPrincipal");
1890 /* create the alias */
1891 ret = ldb_add(sam_ctx, msg);
1893 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1895 ldb_dn_get_linearized(msg->dn),
1896 ldb_errstring(sam_ctx)));
1897 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1900 return NT_STATUS_OK;
1905 Find the DN of a domain, assuming it to be a dotted.dns name
1908 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1911 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1912 const char *binary_encoded;
1913 const char **split_realm;
1920 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1922 talloc_free(tmp_ctx);
1925 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1926 for (i=0; split_realm[i]; i++) {
1927 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1928 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1929 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1930 binary_encoded, ldb_dn_get_linearized(dn)));
1931 talloc_free(tmp_ctx);
1935 if (!ldb_dn_validate(dn)) {
1936 DEBUG(2, ("Failed to validated DN %s\n",
1937 ldb_dn_get_linearized(dn)));
1943 Find the DN of a domain, be it the netbios or DNS name
1946 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1947 const char *domain_name)
1949 const char * const domain_ref_attrs[] = {
1952 const char * const domain_ref2_attrs[] = {
1955 struct ldb_result *res_domain_ref;
1956 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1957 /* find the domain's DN */
1958 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1960 samdb_partitions_dn(ldb, mem_ctx),
1963 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1965 if (ret_domain != 0) {
1969 if (res_domain_ref->count == 0) {
1970 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1972 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1975 "(objectclass=domain)");
1976 if (ret_domain != 0) {
1980 if (res_domain_ref->count == 1) {
1981 return res_domain_ref->msgs[0]->dn;
1986 if (res_domain_ref->count > 1) {
1987 DEBUG(0,("Found %d records matching domain [%s]\n",
1988 ret_domain, domain_name));
1992 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);