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 "librpc/gen_ndr/ndr_misc.h"
32 #include "dsdb/common/flags.h"
33 #include "dsdb/common/proto.h"
34 #include "libcli/ldap/ldap_ndr.h"
35 #include "param/param.h"
36 #include "libcli/auth/libcli_auth.h"
39 search the sam for the specified attributes in a specific domain, filter on
40 objectSid being in domain_sid.
42 int samdb_search_domain(struct ldb_context *sam_ldb,
44 struct ldb_dn *basedn,
45 struct ldb_message ***res,
46 const char * const *attrs,
47 const struct dom_sid *domain_sid,
48 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
54 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
55 res, attrs, format, ap);
61 struct dom_sid *entry_sid;
63 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
65 if ((entry_sid == NULL) ||
66 (!dom_sid_in_domain(domain_sid, entry_sid))) {
67 /* Delete that entry from the result set */
68 (*res)[i] = (*res)[count-1];
70 talloc_free(entry_sid);
73 talloc_free(entry_sid);
81 search the sam for a single string attribute in exactly 1 record
83 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
85 struct ldb_dn *basedn,
86 const char *attr_name,
87 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
90 const char *attrs[2] = { NULL, NULL };
91 struct ldb_message **res = NULL;
95 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
97 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
98 attr_name, format, count));
105 return samdb_result_string(res[0], attr_name, NULL);
110 search the sam for a single string attribute in exactly 1 record
112 const char *samdb_search_string(struct ldb_context *sam_ldb,
114 struct ldb_dn *basedn,
115 const char *attr_name,
116 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
121 va_start(ap, format);
122 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
128 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
130 struct ldb_dn *basedn,
131 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
135 struct ldb_message **res = NULL;
138 va_start(ap, format);
139 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
142 if (count != 1) return NULL;
144 ret = talloc_steal(mem_ctx, res[0]->dn);
151 search the sam for a dom_sid attribute in exactly 1 record
153 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
155 struct ldb_dn *basedn,
156 const char *attr_name,
157 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
161 struct ldb_message **res;
162 const char *attrs[2] = { NULL, NULL };
165 attrs[0] = attr_name;
167 va_start(ap, format);
168 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
171 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
172 attr_name, format, count));
178 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
184 return the count of the number of records in the sam matching the query
186 int samdb_search_count(struct ldb_context *sam_ldb,
188 struct ldb_dn *basedn,
189 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
192 struct ldb_message **res;
193 const char * const attrs[] = { NULL };
196 va_start(ap, format);
197 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
205 search the sam for a single integer attribute in exactly 1 record
207 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
209 uint_t default_value,
210 struct ldb_dn *basedn,
211 const char *attr_name,
212 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
216 struct ldb_message **res;
217 const char *attrs[2] = { NULL, NULL };
219 attrs[0] = attr_name;
221 va_start(ap, format);
222 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
226 return default_value;
229 return samdb_result_uint(res[0], attr_name, default_value);
233 search the sam for a single signed 64 bit integer attribute in exactly 1 record
235 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
237 int64_t default_value,
238 struct ldb_dn *basedn,
239 const char *attr_name,
240 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
244 struct ldb_message **res;
245 const char *attrs[2] = { NULL, NULL };
247 attrs[0] = attr_name;
249 va_start(ap, format);
250 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
254 return default_value;
257 return samdb_result_int64(res[0], attr_name, default_value);
261 search the sam for multipe records each giving a single string attribute
262 return the number of matches, or -1 on error
264 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
266 struct ldb_dn *basedn,
268 const char *attr_name,
269 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
273 const char *attrs[2] = { NULL, NULL };
274 struct ldb_message **res = NULL;
276 attrs[0] = attr_name;
278 va_start(ap, format);
279 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
286 /* make sure its single valued */
287 for (i=0;i<count;i++) {
288 if (res[i]->num_elements != 1) {
289 DEBUG(1,("samdb: search for %s %s not single valued\n",
296 *strs = talloc_array(mem_ctx, const char *, count+1);
302 for (i=0;i<count;i++) {
303 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
305 (*strs)[count] = NULL;
311 pull a uint from a result set.
313 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
315 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
319 pull a (signed) int64 from a result set.
321 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
323 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
327 pull a string from a result set.
329 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
330 const char *default_value)
332 return ldb_msg_find_attr_as_string(msg, attr, default_value);
335 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
336 const char *attr, struct ldb_dn *default_value)
338 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
340 return default_value;
346 pull a rid from a objectSid in a result set.
348 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
349 const char *attr, uint32_t default_value)
354 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
356 return default_value;
358 rid = sid->sub_auths[sid->num_auths-1];
364 pull a dom_sid structure from a objectSid in a result set.
366 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
369 const struct ldb_val *v;
371 enum ndr_err_code ndr_err;
372 v = ldb_msg_find_ldb_val(msg, attr);
376 sid = talloc(mem_ctx, struct dom_sid);
380 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
381 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
382 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
390 pull a guid structure from a objectGUID in a result set.
392 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
394 const struct ldb_val *v;
395 enum ndr_err_code ndr_err;
401 v = ldb_msg_find_ldb_val(msg, attr);
404 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
405 if (!mem_ctx) return guid;
406 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
407 (ndr_pull_flags_fn_t)ndr_pull_GUID);
408 talloc_free(mem_ctx);
409 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
417 pull a sid prefix from a objectSid in a result set.
418 this is used to find the domain sid for a user
420 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
423 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
424 if (!sid || sid->num_auths < 1) return NULL;
430 pull a NTTIME in a result set.
432 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
434 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
438 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
439 * indicate an account doesn't expire.
441 * When Windows initially creates an account, it sets
442 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
443 * when changing from an account having a specific expiration date to
444 * that account never expiring, it sets accountExpires = 0.
446 * Consolidate that logic here to allow clearer logic for account expiry in
447 * the rest of the code.
449 NTTIME samdb_result_account_expires(struct ldb_message *msg)
451 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
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 const struct dom_sid *domain_sid;
1008 const char *attrs[] = {
1012 struct ldb_result *res;
1015 /* see if we have a cached copy */
1016 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1021 tmp_ctx = talloc_new(ldb);
1022 if (tmp_ctx == NULL) {
1026 ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1028 if (ret != LDB_SUCCESS) {
1032 if (res->count != 1) {
1036 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1037 if (domain_sid == NULL) {
1041 /* cache the domain_sid in the ldb */
1042 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1046 talloc_steal(ldb, domain_sid);
1047 talloc_free(tmp_ctx);
1052 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1053 talloc_free(tmp_ctx);
1057 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1059 TALLOC_CTX *tmp_ctx;
1060 struct dom_sid *dom_sid_new;
1061 struct dom_sid *dom_sid_old;
1063 /* see if we have a cached copy */
1064 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1065 "cache.domain_sid"), struct dom_sid);
1067 tmp_ctx = talloc_new(ldb);
1068 if (tmp_ctx == NULL) {
1072 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1077 /* cache the domain_sid in the ldb */
1078 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1082 talloc_steal(ldb, dom_sid_new);
1083 talloc_free(tmp_ctx);
1084 talloc_free(dom_sid_old);
1089 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1090 talloc_free(tmp_ctx);
1094 /* Obtain the short name of the flexible single master operator
1095 * (FSMO), such as the PDC Emulator */
1096 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1099 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1100 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1101 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1102 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1104 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1105 /* Ensure this matches the format. This gives us a
1106 * bit more confidence that a 'cn' value will be a
1111 return (char *)val->data;
1117 work out the ntds settings dn for the current open ldb
1119 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1121 TALLOC_CTX *tmp_ctx;
1122 const char *root_attrs[] = { "dsServiceName", NULL };
1124 struct ldb_result *root_res;
1125 struct ldb_dn *settings_dn;
1127 /* see if we have a cached copy */
1128 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1133 tmp_ctx = talloc_new(ldb);
1134 if (tmp_ctx == NULL) {
1139 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1141 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1142 ldb_errstring(ldb)));
1145 talloc_steal(tmp_ctx, root_res);
1147 if (root_res->count != 1) {
1151 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1153 /* cache the domain_sid in the ldb */
1154 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1158 talloc_steal(ldb, settings_dn);
1159 talloc_free(tmp_ctx);
1164 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1165 talloc_free(tmp_ctx);
1170 work out the ntds settings invocationId for the current open ldb
1172 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1174 TALLOC_CTX *tmp_ctx;
1175 const char *attrs[] = { "invocationId", NULL };
1177 struct ldb_result *res;
1178 struct GUID *invocation_id;
1180 /* see if we have a cached copy */
1181 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1182 if (invocation_id) {
1183 return invocation_id;
1186 tmp_ctx = talloc_new(ldb);
1187 if (tmp_ctx == NULL) {
1191 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1195 talloc_steal(tmp_ctx, res);
1197 if (res->count != 1) {
1201 invocation_id = talloc(tmp_ctx, struct GUID);
1202 if (!invocation_id) {
1206 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1208 /* cache the domain_sid in the ldb */
1209 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1213 talloc_steal(ldb, invocation_id);
1214 talloc_free(tmp_ctx);
1216 return invocation_id;
1219 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1220 talloc_free(tmp_ctx);
1224 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1226 TALLOC_CTX *tmp_ctx;
1227 struct GUID *invocation_id_new;
1228 struct GUID *invocation_id_old;
1230 /* see if we have a cached copy */
1231 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1232 "cache.invocation_id");
1234 tmp_ctx = talloc_new(ldb);
1235 if (tmp_ctx == NULL) {
1239 invocation_id_new = talloc(tmp_ctx, struct GUID);
1240 if (!invocation_id_new) {
1244 *invocation_id_new = *invocation_id_in;
1246 /* cache the domain_sid in the ldb */
1247 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1251 talloc_steal(ldb, invocation_id_new);
1252 talloc_free(tmp_ctx);
1253 talloc_free(invocation_id_old);
1258 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1259 talloc_free(tmp_ctx);
1264 work out the ntds settings objectGUID for the current open ldb
1266 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1268 TALLOC_CTX *tmp_ctx;
1269 const char *attrs[] = { "objectGUID", NULL };
1271 struct ldb_result *res;
1272 struct GUID *ntds_guid;
1274 /* see if we have a cached copy */
1275 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1280 tmp_ctx = talloc_new(ldb);
1281 if (tmp_ctx == NULL) {
1285 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1289 talloc_steal(tmp_ctx, res);
1291 if (res->count != 1) {
1295 ntds_guid = talloc(tmp_ctx, struct GUID);
1300 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1302 /* cache the domain_sid in the ldb */
1303 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1307 talloc_steal(ldb, ntds_guid);
1308 talloc_free(tmp_ctx);
1313 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1314 talloc_free(tmp_ctx);
1318 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1320 TALLOC_CTX *tmp_ctx;
1321 struct GUID *ntds_guid_new;
1322 struct GUID *ntds_guid_old;
1324 /* see if we have a cached copy */
1325 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1327 tmp_ctx = talloc_new(ldb);
1328 if (tmp_ctx == NULL) {
1332 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1333 if (!ntds_guid_new) {
1337 *ntds_guid_new = *ntds_guid_in;
1339 /* cache the domain_sid in the ldb */
1340 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1344 talloc_steal(ldb, ntds_guid_new);
1345 talloc_free(tmp_ctx);
1346 talloc_free(ntds_guid_old);
1351 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1352 talloc_free(tmp_ctx);
1357 work out the server dn for the current open ldb
1359 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1361 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1365 work out the server dn for the current open ldb
1367 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1369 struct ldb_dn *server_dn;
1370 struct ldb_dn *server_site_dn;
1372 server_dn = samdb_server_dn(ldb, mem_ctx);
1373 if (!server_dn) return NULL;
1375 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1377 talloc_free(server_dn);
1378 return server_site_dn;
1382 work out if we are the PDC for the domain of the current open ldb
1384 bool samdb_is_pdc(struct ldb_context *ldb)
1386 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1388 struct ldb_result *dom_res;
1389 TALLOC_CTX *tmp_ctx;
1393 tmp_ctx = talloc_new(ldb);
1394 if (tmp_ctx == NULL) {
1395 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1399 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1401 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1402 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1403 ldb_errstring(ldb)));
1406 talloc_steal(tmp_ctx, dom_res);
1407 if (dom_res->count != 1) {
1411 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1413 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1419 talloc_free(tmp_ctx);
1424 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1425 talloc_free(tmp_ctx);
1430 work out if we are a Global Catalog server for the domain of the current open ldb
1432 bool samdb_is_gc(struct ldb_context *ldb)
1434 const char *attrs[] = { "options", NULL };
1436 struct ldb_result *res;
1437 TALLOC_CTX *tmp_ctx;
1439 tmp_ctx = talloc_new(ldb);
1440 if (tmp_ctx == NULL) {
1441 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1445 /* Query cn=ntds settings,.... */
1446 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1450 if (res->count != 1) {
1455 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1457 talloc_free(tmp_ctx);
1459 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1460 if (options & 0x000000001) {
1466 /* Find a domain object in the parents of a particular DN. */
1467 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1468 struct ldb_dn **parent_dn, const char **errstring)
1470 TALLOC_CTX *local_ctx;
1471 struct ldb_dn *sdn = dn;
1472 struct ldb_result *res = NULL;
1474 const char *attrs[] = { NULL };
1476 local_ctx = talloc_new(mem_ctx);
1477 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1479 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1480 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1481 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))", attrs, &res);
1482 if (ret == LDB_SUCCESS) {
1483 talloc_steal(local_ctx, res);
1484 if (res->count == 1) {
1492 if (ret != LDB_SUCCESS) {
1493 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1494 ldb_dn_get_linearized(dn),
1495 ldb_dn_get_linearized(sdn),
1496 ldb_errstring(ldb));
1497 talloc_free(local_ctx);
1500 if (res->count != 1) {
1501 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1502 ldb_dn_get_linearized(dn));
1503 talloc_free(local_ctx);
1504 return LDB_ERR_CONSTRAINT_VIOLATION;
1507 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1508 talloc_free(local_ctx);
1513 check that a password is sufficiently complex
1515 static bool samdb_password_complexity_ok(const char *pass)
1517 return check_password_quality(pass);
1523 set the user password using plaintext, obeying any user or domain
1524 password restrictions
1526 note that this function doesn't actually store the result in the
1527 database, it just fills in the "mod" structure with ldb modify
1528 elements to setup the correct change when samdb_replace() is
1529 called. This allows the caller to combine the change with other
1530 changes (as is needed by some of the set user info levels)
1532 The caller should probably have a transaction wrapping this
1534 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1535 struct ldb_dn *user_dn,
1536 struct ldb_dn *domain_dn,
1537 struct ldb_message *mod,
1538 const char *new_pass,
1539 struct samr_Password *lmNewHash,
1540 struct samr_Password *ntNewHash,
1542 enum samr_RejectReason *reject_reason,
1543 struct samr_DomInfo1 **_dominfo)
1545 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1547 "dBCSPwd", "unicodePwd",
1549 "pwdLastSet", NULL };
1550 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1551 "maxPwdAge", "minPwdAge",
1552 "minPwdLength", NULL };
1555 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1556 uint_t userAccountControl;
1557 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1558 struct samr_Password local_lmNewHash, local_ntNewHash;
1559 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1560 struct dom_sid *domain_sid;
1561 struct ldb_message **res;
1564 time_t now = time(NULL);
1568 /* we need to know the time to compute password age */
1569 unix_to_nt_time(&now_nt, now);
1571 /* pull all the user parameters */
1572 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1574 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1576 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1577 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1578 "lmPwdHistory", &sambaLMPwdHistory);
1579 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1580 "ntPwdHistory", &sambaNTPwdHistory);
1581 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1582 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1583 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1585 /* Only non-trust accounts have restrictions (possibly this
1586 * test is the wrong way around, but I like to be restrictive
1588 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1589 |UF_WORKSTATION_TRUST_ACCOUNT
1590 |UF_SERVER_TRUST_ACCOUNT));
1593 /* pull the domain parameters */
1594 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1596 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1597 ldb_dn_get_linearized(domain_dn),
1598 ldb_dn_get_linearized(user_dn)));
1599 return NT_STATUS_NO_SUCH_DOMAIN;
1602 /* work out the domain sid, and pull the domain from there */
1603 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1604 if (domain_sid == NULL) {
1605 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1608 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1610 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1612 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1613 dom_sid_string(mem_ctx, domain_sid),
1614 ldb_dn_get_linearized(user_dn)));
1615 return NT_STATUS_NO_SUCH_DOMAIN;
1619 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1620 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1621 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1622 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1625 struct samr_DomInfo1 *dominfo;
1626 /* on failure we need to fill in the reject reasons */
1627 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1628 if (dominfo == NULL) {
1629 return NT_STATUS_NO_MEMORY;
1631 dominfo->min_password_length = minPwdLength;
1632 dominfo->password_properties = pwdProperties;
1633 dominfo->password_history_length = pwdHistoryLength;
1634 dominfo->max_password_age = minPwdAge;
1635 dominfo->min_password_age = minPwdAge;
1636 *_dominfo = dominfo;
1639 if (restrictions && new_pass) {
1641 /* check the various password restrictions */
1642 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1643 if (reject_reason) {
1644 *reject_reason = SAMR_REJECT_TOO_SHORT;
1646 return NT_STATUS_PASSWORD_RESTRICTION;
1649 /* possibly check password complexity */
1650 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1651 !samdb_password_complexity_ok(new_pass)) {
1652 if (reject_reason) {
1653 *reject_reason = SAMR_REJECT_COMPLEXITY;
1655 return NT_STATUS_PASSWORD_RESTRICTION;
1658 /* compute the new nt and lm hashes */
1659 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1660 lmNewHash = &local_lmNewHash;
1662 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1663 /* If we can't convert this password to UCS2, then we should not accept it */
1664 if (reject_reason) {
1665 *reject_reason = SAMR_REJECT_OTHER;
1667 return NT_STATUS_PASSWORD_RESTRICTION;
1669 ntNewHash = &local_ntNewHash;
1673 /* are all password changes disallowed? */
1674 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1675 if (reject_reason) {
1676 *reject_reason = SAMR_REJECT_OTHER;
1678 return NT_STATUS_PASSWORD_RESTRICTION;
1681 /* can this user change password? */
1682 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1683 if (reject_reason) {
1684 *reject_reason = SAMR_REJECT_OTHER;
1686 return NT_STATUS_PASSWORD_RESTRICTION;
1689 /* yes, this is a minus. The ages are in negative 100nsec units! */
1690 if (pwdLastSet - minPwdAge > now_nt) {
1691 if (reject_reason) {
1692 *reject_reason = SAMR_REJECT_OTHER;
1694 return NT_STATUS_PASSWORD_RESTRICTION;
1697 /* check the immediately past password */
1698 if (pwdHistoryLength > 0) {
1699 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1700 if (reject_reason) {
1701 *reject_reason = SAMR_REJECT_IN_HISTORY;
1703 return NT_STATUS_PASSWORD_RESTRICTION;
1705 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1706 if (reject_reason) {
1707 *reject_reason = SAMR_REJECT_IN_HISTORY;
1709 return NT_STATUS_PASSWORD_RESTRICTION;
1713 /* check the password history */
1714 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1715 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1717 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1718 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1719 if (reject_reason) {
1720 *reject_reason = SAMR_REJECT_IN_HISTORY;
1722 return NT_STATUS_PASSWORD_RESTRICTION;
1725 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1726 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1727 if (reject_reason) {
1728 *reject_reason = SAMR_REJECT_IN_HISTORY;
1730 return NT_STATUS_PASSWORD_RESTRICTION;
1735 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1737 /* the password is acceptable. Start forming the new fields */
1739 /* if we know the cleartext, then only set it.
1740 * Modules in ldb will set all the appropriate
1742 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1743 "sambaPassword", new_pass));
1745 /* We don't have the cleartext, so delete the old one
1746 * and set what we have of the hashes */
1747 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1750 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1752 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1756 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1758 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1762 return NT_STATUS_OK;
1767 set the user password using plaintext, obeying any user or domain
1768 password restrictions
1770 This wrapper function takes a SID as input, rather than a user DN,
1771 and actually performs the password change
1774 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1775 const struct dom_sid *user_sid,
1776 const char *new_pass,
1777 struct samr_Password *lmNewHash,
1778 struct samr_Password *ntNewHash,
1780 enum samr_RejectReason *reject_reason,
1781 struct samr_DomInfo1 **_dominfo)
1784 struct ldb_dn *user_dn;
1785 struct ldb_message *msg;
1788 ret = ldb_transaction_start(ctx);
1790 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1791 return NT_STATUS_TRANSACTION_ABORTED;
1794 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1795 "(&(objectSid=%s)(objectClass=user))",
1796 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1798 ldb_transaction_cancel(ctx);
1799 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1800 dom_sid_string(mem_ctx, user_sid)));
1801 return NT_STATUS_NO_SUCH_USER;
1804 msg = ldb_msg_new(mem_ctx);
1806 ldb_transaction_cancel(ctx);
1807 return NT_STATUS_NO_MEMORY;
1810 msg->dn = ldb_dn_copy(msg, user_dn);
1812 ldb_transaction_cancel(ctx);
1813 return NT_STATUS_NO_MEMORY;
1816 nt_status = samdb_set_password(ctx, mem_ctx,
1819 lmNewHash, ntNewHash,
1820 user_change, /* This is a password set, not change */
1821 reject_reason, _dominfo);
1822 if (!NT_STATUS_IS_OK(nt_status)) {
1823 ldb_transaction_cancel(ctx);
1827 /* modify the samdb record */
1828 ret = samdb_replace(ctx, mem_ctx, msg);
1830 ldb_transaction_cancel(ctx);
1831 return NT_STATUS_ACCESS_DENIED;
1834 ret = ldb_transaction_commit(ctx);
1836 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1837 ldb_dn_get_linearized(msg->dn),
1838 ldb_errstring(ctx)));
1839 return NT_STATUS_TRANSACTION_ABORTED;
1841 return NT_STATUS_OK;
1846 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1847 struct dom_sid *sid, struct ldb_dn **ret_dn)
1849 struct ldb_message *msg;
1850 struct ldb_dn *basedn;
1854 sidstr = dom_sid_string(mem_ctx, sid);
1855 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1857 /* We might have to create a ForeignSecurityPrincipal, even if this user
1858 * is in our own domain */
1860 msg = ldb_msg_new(mem_ctx);
1862 return NT_STATUS_NO_MEMORY;
1865 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1866 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1867 * not work, this is wrong for the Builtin domain, there's no
1868 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1871 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1872 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1874 if (basedn == NULL) {
1875 DEBUG(0, ("Failed to find DN for "
1876 "ForeignSecurityPrincipal container\n"));
1877 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1880 /* add core elements to the ldb_message for the alias */
1881 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1882 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1883 return NT_STATUS_NO_MEMORY;
1885 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1887 "foreignSecurityPrincipal");
1889 /* create the alias */
1890 ret = ldb_add(sam_ctx, msg);
1892 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1894 ldb_dn_get_linearized(msg->dn),
1895 ldb_errstring(sam_ctx)));
1896 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1899 return NT_STATUS_OK;
1904 Find the DN of a domain, assuming it to be a dotted.dns name
1907 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1910 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1911 const char *binary_encoded;
1912 const char **split_realm;
1919 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1921 talloc_free(tmp_ctx);
1924 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1925 for (i=0; split_realm[i]; i++) {
1926 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1927 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1928 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1929 binary_encoded, ldb_dn_get_linearized(dn)));
1930 talloc_free(tmp_ctx);
1934 if (!ldb_dn_validate(dn)) {
1935 DEBUG(2, ("Failed to validated DN %s\n",
1936 ldb_dn_get_linearized(dn)));
1942 Find the DN of a domain, be it the netbios or DNS name
1945 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1946 const char *domain_name)
1948 const char * const domain_ref_attrs[] = {
1951 const char * const domain_ref2_attrs[] = {
1954 struct ldb_result *res_domain_ref;
1955 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1956 /* find the domain's DN */
1957 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1959 samdb_partitions_dn(ldb, mem_ctx),
1962 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1964 if (ret_domain != 0) {
1968 if (res_domain_ref->count == 0) {
1969 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1971 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1974 "(objectclass=domain)");
1975 if (ret_domain != 0) {
1979 if (res_domain_ref->count == 1) {
1980 return res_domain_ref->msgs[0]->dn;
1985 if (res_domain_ref->count > 1) {
1986 DEBUG(0,("Found %d records matching domain [%s]\n",
1987 ret_domain, domain_name));
1991 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);