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/>.
25 #include "events/events.h"
27 #include "ldb_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
41 search the sam for the specified attributes in a specific domain, filter on
42 objectSid being in domain_sid.
44 int samdb_search_domain(struct ldb_context *sam_ldb,
46 struct ldb_dn *basedn,
47 struct ldb_message ***res,
48 const char * const *attrs,
49 const struct dom_sid *domain_sid,
50 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
56 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
57 res, attrs, format, ap);
63 struct dom_sid *entry_sid;
65 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
67 if ((entry_sid == NULL) ||
68 (!dom_sid_in_domain(domain_sid, entry_sid))) {
69 /* Delete that entry from the result set */
70 (*res)[i] = (*res)[count-1];
72 talloc_free(entry_sid);
75 talloc_free(entry_sid);
83 search the sam for a single string attribute in exactly 1 record
85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
87 struct ldb_dn *basedn,
88 const char *attr_name,
89 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
92 const char *attrs[2] = { NULL, NULL };
93 struct ldb_message **res = NULL;
97 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
99 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
100 attr_name, format, count));
107 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, const 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, const 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 loadparm_context *lp_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];
590 /* Ensure that if we have turned off LM
591 * authentication, that we never use the LM hash, even
593 if (lp_lanman_auth(lp_ctx)) {
595 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
598 } else if (num_lm > 1) {
599 return NT_STATUS_INTERNAL_DB_CORRUPTION;
601 *lm_pwd = &lmPwdHash[0];
611 pull a samr_LogonHours structutre from a result set.
613 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
615 struct samr_LogonHours hours;
616 const int units_per_week = 168;
617 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
619 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
623 hours.units_per_week = units_per_week;
624 memset(hours.bits, 0xFF, units_per_week);
626 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
632 pull a set of account_flags from a result set.
634 This requires that the attributes:
639 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
640 struct ldb_message *msg, struct ldb_dn *domain_dn)
642 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
643 uint32_t acct_flags = ds_uf2acb(userAccountControl);
644 NTTIME must_change_time;
647 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
650 /* Test account expire time */
651 unix_to_nt_time(&now, time(NULL));
652 /* check for expired password */
653 if (must_change_time < now) {
654 acct_flags |= ACB_PW_EXPIRED;
659 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
660 struct ldb_message *msg,
663 struct lsa_BinaryString s;
664 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
672 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
676 s.length = s.size = val->length/2;
677 memcpy(s.array, val->data, val->length);
682 /* Find an attribute, with a particular value */
684 /* The current callers of this function expect a very specific
685 * behaviour: In particular, objectClass subclass equivilance is not
686 * wanted. This means that we should not lookup the schema for the
687 * comparison function */
688 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
689 const struct ldb_message *msg,
690 const char *name, const char *value)
693 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
699 for (i=0;i<el->num_values;i++) {
700 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
708 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
710 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
711 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
716 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
718 struct ldb_message_element *el;
720 el = ldb_msg_find_element(msg, name);
725 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
731 add a string element to a message
733 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
734 const char *attr_name, const char *str)
736 char *s = talloc_strdup(mem_ctx, str);
737 char *a = talloc_strdup(mem_ctx, attr_name);
738 if (s == NULL || a == NULL) {
739 return LDB_ERR_OPERATIONS_ERROR;
741 return ldb_msg_add_string(msg, a, s);
745 add a dom_sid element to a message
747 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
748 const char *attr_name, struct dom_sid *sid)
751 enum ndr_err_code ndr_err;
753 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
754 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
756 (ndr_push_flags_fn_t)ndr_push_dom_sid);
757 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
760 return ldb_msg_add_value(msg, attr_name, &v, NULL);
765 add a delete element operation to a message
767 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
768 const char *attr_name)
770 /* we use an empty replace rather than a delete, as it allows for
771 samdb_replace() to be used everywhere */
772 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
776 add a add attribute value to a message
778 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
779 const char *attr_name, const char *value)
781 struct ldb_message_element *el;
784 a = talloc_strdup(mem_ctx, attr_name);
787 v = talloc_strdup(mem_ctx, value);
790 ret = ldb_msg_add_string(msg, a, v);
793 el = ldb_msg_find_element(msg, a);
796 el->flags = LDB_FLAG_MOD_ADD;
801 add a delete attribute value to a message
803 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
804 const char *attr_name, const char *value)
806 struct ldb_message_element *el;
809 a = talloc_strdup(mem_ctx, attr_name);
812 v = talloc_strdup(mem_ctx, value);
815 ret = ldb_msg_add_string(msg, a, v);
818 el = ldb_msg_find_element(msg, a);
821 el->flags = LDB_FLAG_MOD_DELETE;
826 add a int element to a message
828 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
829 const char *attr_name, int v)
831 const char *s = talloc_asprintf(mem_ctx, "%d", v);
832 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
836 add a uint_t element to a message
838 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
839 const char *attr_name, uint_t v)
841 const char *s = talloc_asprintf(mem_ctx, "%u", v);
842 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
846 add a (signed) int64_t element to a message
848 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849 const char *attr_name, int64_t v)
851 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
852 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
856 add a uint64_t element to a message
858 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
859 const char *attr_name, uint64_t v)
861 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
862 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
866 add a samr_Password element to a message
868 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
869 const char *attr_name, struct samr_Password *hash)
872 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
877 return ldb_msg_add_value(msg, attr_name, &val, NULL);
881 add a samr_Password array to a message
883 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
884 const char *attr_name, struct samr_Password *hashes, uint_t count)
888 val.data = talloc_array_size(mem_ctx, 16, count);
889 val.length = count*16;
893 for (i=0;i<count;i++) {
894 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
896 return ldb_msg_add_value(msg, attr_name, &val, NULL);
900 add a acct_flags element to a message
902 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
903 const char *attr_name, uint32_t v)
905 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
909 add a logon_hours element to a message
911 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912 const char *attr_name, struct samr_LogonHours *hours)
915 val.length = hours->units_per_week / 8;
916 val.data = hours->bits;
917 return ldb_msg_add_value(msg, attr_name, &val, NULL);
921 add a parameters element to a message
923 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
924 const char *attr_name, struct lsa_BinaryString *parameters)
927 val.length = parameters->length * 2;
928 val.data = (uint8_t *)parameters->array;
929 return ldb_msg_add_value(msg, attr_name, &val, NULL);
932 add a general value element to a message
934 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
935 const char *attr_name, const struct ldb_val *val)
937 return ldb_msg_add_value(msg, attr_name, val, NULL);
941 sets a general value element to a message
943 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
944 const char *attr_name, const struct ldb_val *val)
946 struct ldb_message_element *el;
948 el = ldb_msg_find_element(msg, attr_name);
952 return ldb_msg_add_value(msg, attr_name, val, NULL);
956 set a string element in a message
958 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
959 const char *attr_name, const char *str)
961 struct ldb_message_element *el;
963 el = ldb_msg_find_element(msg, attr_name);
967 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
971 replace elements in a record
973 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
977 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
978 for (i=0;i<msg->num_elements;i++) {
979 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
982 /* modify the samdb record */
983 return ldb_modify(sam_ldb, msg);
987 return a default security descriptor
989 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
991 struct security_descriptor *sd;
993 sd = security_descriptor_initialise(mem_ctx);
998 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1000 return ldb_get_default_basedn(sam_ctx);
1003 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1005 return ldb_get_config_basedn(sam_ctx);
1008 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1010 return ldb_get_schema_basedn(sam_ctx);
1013 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1015 return ldb_get_root_basedn(sam_ctx);
1018 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1020 struct ldb_dn *new_dn;
1022 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1023 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1024 talloc_free(new_dn);
1030 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1032 struct ldb_dn *new_dn;
1034 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1035 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1036 talloc_free(new_dn);
1043 work out the domain sid for the current open ldb
1045 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1047 TALLOC_CTX *tmp_ctx;
1048 const struct dom_sid *domain_sid;
1049 const char *attrs[] = {
1053 struct ldb_result *res;
1056 /* see if we have a cached copy */
1057 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1062 tmp_ctx = talloc_new(ldb);
1063 if (tmp_ctx == NULL) {
1067 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1069 if (ret != LDB_SUCCESS) {
1073 if (res->count != 1) {
1077 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1078 if (domain_sid == NULL) {
1082 /* cache the domain_sid in the ldb */
1083 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1087 talloc_steal(ldb, domain_sid);
1088 talloc_free(tmp_ctx);
1093 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1094 talloc_free(tmp_ctx);
1098 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1100 TALLOC_CTX *tmp_ctx;
1101 struct dom_sid *dom_sid_new;
1102 struct dom_sid *dom_sid_old;
1104 /* see if we have a cached copy */
1105 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1106 "cache.domain_sid"), struct dom_sid);
1108 tmp_ctx = talloc_new(ldb);
1109 if (tmp_ctx == NULL) {
1113 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1118 /* cache the domain_sid in the ldb */
1119 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1123 talloc_steal(ldb, dom_sid_new);
1124 talloc_free(tmp_ctx);
1125 talloc_free(dom_sid_old);
1130 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1131 talloc_free(tmp_ctx);
1135 /* Obtain the short name of the flexible single master operator
1136 * (FSMO), such as the PDC Emulator */
1137 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1140 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1141 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1142 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1143 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1145 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1146 /* Ensure this matches the format. This gives us a
1147 * bit more confidence that a 'cn' value will be a
1152 return (char *)val->data;
1158 work out the ntds settings dn for the current open ldb
1160 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1162 TALLOC_CTX *tmp_ctx;
1163 const char *root_attrs[] = { "dsServiceName", NULL };
1165 struct ldb_result *root_res;
1166 struct ldb_dn *settings_dn;
1168 /* see if we have a cached copy */
1169 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1174 tmp_ctx = talloc_new(ldb);
1175 if (tmp_ctx == NULL) {
1179 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1181 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1182 ldb_errstring(ldb)));
1186 if (root_res->count != 1) {
1190 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1192 /* cache the domain_sid in the ldb */
1193 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1197 talloc_steal(ldb, settings_dn);
1198 talloc_free(tmp_ctx);
1203 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1204 talloc_free(tmp_ctx);
1209 work out the ntds settings invocationId for the current open ldb
1211 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1213 TALLOC_CTX *tmp_ctx;
1214 const char *attrs[] = { "invocationId", NULL };
1216 struct ldb_result *res;
1217 struct GUID *invocation_id;
1219 /* see if we have a cached copy */
1220 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1221 if (invocation_id) {
1222 return invocation_id;
1225 tmp_ctx = talloc_new(ldb);
1226 if (tmp_ctx == NULL) {
1230 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1235 if (res->count != 1) {
1239 invocation_id = talloc(tmp_ctx, struct GUID);
1240 if (!invocation_id) {
1244 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1246 /* cache the domain_sid in the ldb */
1247 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1251 talloc_steal(ldb, invocation_id);
1252 talloc_free(tmp_ctx);
1254 return invocation_id;
1257 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1258 talloc_free(tmp_ctx);
1262 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1264 TALLOC_CTX *tmp_ctx;
1265 struct GUID *invocation_id_new;
1266 struct GUID *invocation_id_old;
1268 /* see if we have a cached copy */
1269 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1270 "cache.invocation_id");
1272 tmp_ctx = talloc_new(ldb);
1273 if (tmp_ctx == NULL) {
1277 invocation_id_new = talloc(tmp_ctx, struct GUID);
1278 if (!invocation_id_new) {
1282 *invocation_id_new = *invocation_id_in;
1284 /* cache the domain_sid in the ldb */
1285 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1289 talloc_steal(ldb, invocation_id_new);
1290 talloc_free(tmp_ctx);
1291 talloc_free(invocation_id_old);
1296 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1297 talloc_free(tmp_ctx);
1302 work out the ntds settings objectGUID for the current open ldb
1304 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1306 TALLOC_CTX *tmp_ctx;
1307 const char *attrs[] = { "objectGUID", NULL };
1309 struct ldb_result *res;
1310 struct GUID *ntds_guid;
1312 /* see if we have a cached copy */
1313 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1318 tmp_ctx = talloc_new(ldb);
1319 if (tmp_ctx == NULL) {
1323 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1328 if (res->count != 1) {
1332 ntds_guid = talloc(tmp_ctx, struct GUID);
1337 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1339 /* cache the domain_sid in the ldb */
1340 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1344 talloc_steal(ldb, ntds_guid);
1345 talloc_free(tmp_ctx);
1350 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1351 talloc_free(tmp_ctx);
1355 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1357 TALLOC_CTX *tmp_ctx;
1358 struct GUID *ntds_guid_new;
1359 struct GUID *ntds_guid_old;
1361 /* see if we have a cached copy */
1362 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1364 tmp_ctx = talloc_new(ldb);
1365 if (tmp_ctx == NULL) {
1369 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1370 if (!ntds_guid_new) {
1374 *ntds_guid_new = *ntds_guid_in;
1376 /* cache the domain_sid in the ldb */
1377 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1381 talloc_steal(ldb, ntds_guid_new);
1382 talloc_free(tmp_ctx);
1383 talloc_free(ntds_guid_old);
1388 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1389 talloc_free(tmp_ctx);
1394 work out the server dn for the current open ldb
1396 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1398 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1402 work out the server dn for the current open ldb
1404 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1406 struct ldb_dn *server_dn;
1407 struct ldb_dn *server_site_dn;
1409 server_dn = samdb_server_dn(ldb, mem_ctx);
1410 if (!server_dn) return NULL;
1412 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1414 talloc_free(server_dn);
1415 return server_site_dn;
1419 work out if we are the PDC for the domain of the current open ldb
1421 bool samdb_is_pdc(struct ldb_context *ldb)
1423 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1425 struct ldb_result *dom_res;
1426 TALLOC_CTX *tmp_ctx;
1430 tmp_ctx = talloc_new(ldb);
1431 if (tmp_ctx == NULL) {
1432 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1436 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1438 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1439 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1440 ldb_errstring(ldb)));
1443 if (dom_res->count != 1) {
1447 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1449 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1455 talloc_free(tmp_ctx);
1460 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1461 talloc_free(tmp_ctx);
1466 work out if we are a Global Catalog server for the domain of the current open ldb
1468 bool samdb_is_gc(struct ldb_context *ldb)
1470 const char *attrs[] = { "options", NULL };
1472 struct ldb_result *res;
1473 TALLOC_CTX *tmp_ctx;
1475 tmp_ctx = talloc_new(ldb);
1476 if (tmp_ctx == NULL) {
1477 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1481 /* Query cn=ntds settings,.... */
1482 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1484 talloc_free(tmp_ctx);
1487 if (res->count != 1) {
1488 talloc_free(tmp_ctx);
1492 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1493 talloc_free(tmp_ctx);
1495 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1496 if (options & 0x000000001) {
1502 /* Find a domain object in the parents of a particular DN. */
1503 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1504 struct ldb_dn **parent_dn, const char **errstring)
1506 TALLOC_CTX *local_ctx;
1507 struct ldb_dn *sdn = dn;
1508 struct ldb_result *res = NULL;
1510 const char *attrs[] = { NULL };
1512 local_ctx = talloc_new(mem_ctx);
1513 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1515 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1516 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1517 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1518 if (ret == LDB_SUCCESS) {
1519 if (res->count == 1) {
1527 if (ret != LDB_SUCCESS) {
1528 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1529 ldb_dn_get_linearized(dn),
1530 ldb_dn_get_linearized(sdn),
1531 ldb_errstring(ldb));
1532 talloc_free(local_ctx);
1535 if (res->count != 1) {
1536 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1537 ldb_dn_get_linearized(dn));
1538 talloc_free(local_ctx);
1539 return LDB_ERR_CONSTRAINT_VIOLATION;
1542 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1543 talloc_free(local_ctx);
1548 check that a password is sufficiently complex
1550 static bool samdb_password_complexity_ok(const char *pass)
1552 return check_password_quality(pass);
1558 set the user password using plaintext, obeying any user or domain
1559 password restrictions
1561 note that this function doesn't actually store the result in the
1562 database, it just fills in the "mod" structure with ldb modify
1563 elements to setup the correct change when samdb_replace() is
1564 called. This allows the caller to combine the change with other
1565 changes (as is needed by some of the set user info levels)
1567 The caller should probably have a transaction wrapping this
1569 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1570 struct ldb_dn *user_dn,
1571 struct ldb_dn *domain_dn,
1572 struct ldb_message *mod,
1573 const DATA_BLOB *new_password,
1574 struct samr_Password *lmNewHash,
1575 struct samr_Password *ntNewHash,
1577 enum samr_RejectReason *reject_reason,
1578 struct samr_DomInfo1 **_dominfo)
1580 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1582 "dBCSPwd", "unicodePwd",
1584 "pwdLastSet", NULL };
1585 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1586 "maxPwdAge", "minPwdAge",
1587 "minPwdLength", NULL };
1590 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1591 uint_t userAccountControl;
1592 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1593 struct samr_Password local_lmNewHash, local_ntNewHash;
1594 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1595 struct dom_sid *domain_sid;
1596 struct ldb_message **res;
1599 time_t now = time(NULL);
1603 /* we need to know the time to compute password age */
1604 unix_to_nt_time(&now_nt, now);
1606 /* pull all the user parameters */
1607 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1611 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1612 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1613 "lmPwdHistory", &sambaLMPwdHistory);
1614 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1615 "ntPwdHistory", &sambaNTPwdHistory);
1616 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1617 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1618 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1620 /* Only non-trust accounts have restrictions (possibly this
1621 * test is the wrong way around, but I like to be restrictive
1623 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1624 |UF_WORKSTATION_TRUST_ACCOUNT
1625 |UF_SERVER_TRUST_ACCOUNT));
1628 /* pull the domain parameters */
1629 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1631 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1632 ldb_dn_get_linearized(domain_dn),
1633 ldb_dn_get_linearized(user_dn)));
1634 return NT_STATUS_NO_SUCH_DOMAIN;
1637 /* work out the domain sid, and pull the domain from there */
1638 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1639 if (domain_sid == NULL) {
1640 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1643 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1645 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1647 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1648 dom_sid_string(mem_ctx, domain_sid),
1649 ldb_dn_get_linearized(user_dn)));
1650 return NT_STATUS_NO_SUCH_DOMAIN;
1654 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1655 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1656 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1657 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1659 if (userAccountControl & UF_PASSWD_NOTREQD) {
1660 /* see [MS-ADTS] 2.2.15 */
1665 struct samr_DomInfo1 *dominfo;
1666 /* on failure we need to fill in the reject reasons */
1667 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1668 if (dominfo == NULL) {
1669 return NT_STATUS_NO_MEMORY;
1671 dominfo->min_password_length = minPwdLength;
1672 dominfo->password_properties = pwdProperties;
1673 dominfo->password_history_length = pwdHistoryLength;
1674 dominfo->max_password_age = minPwdAge;
1675 dominfo->min_password_age = minPwdAge;
1676 *_dominfo = dominfo;
1679 if (restrictions && new_password) {
1682 /* check the various password restrictions */
1683 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1684 if (reject_reason) {
1685 *reject_reason = SAMR_REJECT_TOO_SHORT;
1687 return NT_STATUS_PASSWORD_RESTRICTION;
1690 /* Create the NT hash */
1691 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1693 ntNewHash = &local_ntNewHash;
1695 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1696 if (convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1698 new_password->data, new_password->length,
1699 (void **)&new_pass, NULL, false)) {
1701 /* possibly check password complexity */
1702 if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
1703 !samdb_password_complexity_ok(new_pass)) {
1704 if (reject_reason) {
1705 *reject_reason = SAMR_REJECT_COMPLEXITY;
1707 return NT_STATUS_PASSWORD_RESTRICTION;
1710 /* compute the new lm hashes (for checking history - case insenitivly!) */
1711 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1712 lmNewHash = &local_lmNewHash;
1717 if (restrictions && user_change) {
1718 /* are all password changes disallowed? */
1719 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1720 if (reject_reason) {
1721 *reject_reason = SAMR_REJECT_OTHER;
1723 return NT_STATUS_PASSWORD_RESTRICTION;
1726 /* can this user change password? */
1727 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1728 if (reject_reason) {
1729 *reject_reason = SAMR_REJECT_OTHER;
1731 return NT_STATUS_PASSWORD_RESTRICTION;
1734 /* yes, this is a minus. The ages are in negative 100nsec units! */
1735 if (pwdLastSet - minPwdAge > now_nt) {
1736 if (reject_reason) {
1737 *reject_reason = SAMR_REJECT_OTHER;
1739 return NT_STATUS_PASSWORD_RESTRICTION;
1742 /* check the immediately past password */
1743 if (pwdHistoryLength > 0) {
1744 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1745 if (reject_reason) {
1746 *reject_reason = SAMR_REJECT_IN_HISTORY;
1748 return NT_STATUS_PASSWORD_RESTRICTION;
1750 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1751 if (reject_reason) {
1752 *reject_reason = SAMR_REJECT_IN_HISTORY;
1754 return NT_STATUS_PASSWORD_RESTRICTION;
1758 /* check the password history */
1759 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1760 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1762 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1763 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1764 if (reject_reason) {
1765 *reject_reason = SAMR_REJECT_IN_HISTORY;
1767 return NT_STATUS_PASSWORD_RESTRICTION;
1770 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1771 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1772 if (reject_reason) {
1773 *reject_reason = SAMR_REJECT_IN_HISTORY;
1775 return NT_STATUS_PASSWORD_RESTRICTION;
1780 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1782 /* the password is acceptable. Start forming the new fields */
1784 /* if we know the cleartext UTF16 password, then set it.
1785 * Modules in ldb will set all the appropriate
1787 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1789 /* We don't have the cleartext, so delete the old one
1790 * and set what we have of the hashes */
1791 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1794 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1796 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1800 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1802 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1806 return NT_STATUS_OK;
1811 set the user password using plaintext, obeying any user or domain
1812 password restrictions
1814 This wrapper function takes a SID as input, rather than a user DN,
1815 and actually performs the password change
1818 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1819 const struct dom_sid *user_sid,
1820 const DATA_BLOB *new_pass,
1821 struct samr_Password *lmNewHash,
1822 struct samr_Password *ntNewHash,
1824 enum samr_RejectReason *reject_reason,
1825 struct samr_DomInfo1 **_dominfo)
1828 struct ldb_dn *user_dn;
1829 struct ldb_message *msg;
1832 ret = ldb_transaction_start(ctx);
1834 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1835 return NT_STATUS_TRANSACTION_ABORTED;
1838 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1839 "(&(objectSid=%s)(objectClass=user))",
1840 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1842 ldb_transaction_cancel(ctx);
1843 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1844 dom_sid_string(mem_ctx, user_sid)));
1845 return NT_STATUS_NO_SUCH_USER;
1848 msg = ldb_msg_new(mem_ctx);
1850 ldb_transaction_cancel(ctx);
1851 return NT_STATUS_NO_MEMORY;
1854 msg->dn = ldb_dn_copy(msg, user_dn);
1856 ldb_transaction_cancel(ctx);
1857 return NT_STATUS_NO_MEMORY;
1860 nt_status = samdb_set_password(ctx, mem_ctx,
1863 lmNewHash, ntNewHash,
1864 user_change, /* This is a password set, not change */
1865 reject_reason, _dominfo);
1866 if (!NT_STATUS_IS_OK(nt_status)) {
1867 ldb_transaction_cancel(ctx);
1871 /* modify the samdb record */
1872 ret = samdb_replace(ctx, mem_ctx, msg);
1874 ldb_transaction_cancel(ctx);
1875 return NT_STATUS_ACCESS_DENIED;
1878 ret = ldb_transaction_commit(ctx);
1880 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1881 ldb_dn_get_linearized(msg->dn),
1882 ldb_errstring(ctx)));
1883 return NT_STATUS_TRANSACTION_ABORTED;
1885 return NT_STATUS_OK;
1890 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1891 struct dom_sid *sid, struct ldb_dn **ret_dn)
1893 struct ldb_message *msg;
1894 struct ldb_dn *basedn;
1898 sidstr = dom_sid_string(mem_ctx, sid);
1899 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1901 /* We might have to create a ForeignSecurityPrincipal, even if this user
1902 * is in our own domain */
1904 msg = ldb_msg_new(mem_ctx);
1906 return NT_STATUS_NO_MEMORY;
1909 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1910 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1911 * not work, this is wrong for the Builtin domain, there's no
1912 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1915 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1916 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1918 if (basedn == NULL) {
1919 DEBUG(0, ("Failed to find DN for "
1920 "ForeignSecurityPrincipal container\n"));
1921 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1924 /* add core elements to the ldb_message for the alias */
1925 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1926 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1927 return NT_STATUS_NO_MEMORY;
1929 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1931 "foreignSecurityPrincipal");
1933 /* create the alias */
1934 ret = ldb_add(sam_ctx, msg);
1936 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1938 ldb_dn_get_linearized(msg->dn),
1939 ldb_errstring(sam_ctx)));
1940 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1943 return NT_STATUS_OK;
1948 Find the DN of a domain, assuming it to be a dotted.dns name
1951 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1954 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1955 const char *binary_encoded;
1956 const char **split_realm;
1963 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1965 talloc_free(tmp_ctx);
1968 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1969 for (i=0; split_realm[i]; i++) {
1970 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1971 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1972 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1973 binary_encoded, ldb_dn_get_linearized(dn)));
1974 talloc_free(tmp_ctx);
1978 if (!ldb_dn_validate(dn)) {
1979 DEBUG(2, ("Failed to validated DN %s\n",
1980 ldb_dn_get_linearized(dn)));
1986 Find the DN of a domain, be it the netbios or DNS name
1989 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1990 const char *domain_name)
1992 const char * const domain_ref_attrs[] = {
1995 const char * const domain_ref2_attrs[] = {
1998 struct ldb_result *res_domain_ref;
1999 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2000 /* find the domain's DN */
2001 int ret_domain = ldb_search(ldb, mem_ctx,
2003 samdb_partitions_dn(ldb, mem_ctx),
2006 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2008 if (ret_domain != 0) {
2012 if (res_domain_ref->count == 0) {
2013 ret_domain = ldb_search(ldb, mem_ctx,
2015 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2018 "(objectclass=domain)");
2019 if (ret_domain != 0) {
2023 if (res_domain_ref->count == 1) {
2024 return res_domain_ref->msgs[0]->dn;
2029 if (res_domain_ref->count > 1) {
2030 DEBUG(0,("Found %d records matching domain [%s]\n",
2031 ret_domain, domain_name));
2035 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);