2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "ldb_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../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 "dsdb/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);
112 search the sam for a single string attribute in exactly 1 record
114 const char *samdb_search_string(struct ldb_context *sam_ldb,
116 struct ldb_dn *basedn,
117 const char *attr_name,
118 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
123 va_start(ap, format);
124 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
132 struct ldb_dn *basedn,
133 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
137 struct ldb_message **res = NULL;
140 va_start(ap, format);
141 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
144 if (count != 1) return NULL;
146 ret = talloc_steal(mem_ctx, res[0]->dn);
153 search the sam for a dom_sid attribute in exactly 1 record
155 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
157 struct ldb_dn *basedn,
158 const char *attr_name,
159 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
163 struct ldb_message **res;
164 const char *attrs[2] = { NULL, NULL };
167 attrs[0] = attr_name;
169 va_start(ap, format);
170 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174 attr_name, format, count));
180 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
186 return the count of the number of records in the sam matching the query
188 int samdb_search_count(struct ldb_context *sam_ldb,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
194 struct ldb_message **res;
195 const char * const attrs[] = { NULL };
198 va_start(ap, format);
199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
207 search the sam for a single integer attribute in exactly 1 record
209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
211 uint_t default_value,
212 struct ldb_dn *basedn,
213 const char *attr_name,
214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
218 struct ldb_message **res;
219 const char *attrs[2] = { NULL, NULL };
221 attrs[0] = attr_name;
223 va_start(ap, format);
224 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
228 return default_value;
231 return samdb_result_uint(res[0], attr_name, default_value);
235 search the sam for a single signed 64 bit integer attribute in exactly 1 record
237 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
239 int64_t default_value,
240 struct ldb_dn *basedn,
241 const char *attr_name,
242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
246 struct ldb_message **res;
247 const char *attrs[2] = { NULL, NULL };
249 attrs[0] = attr_name;
251 va_start(ap, format);
252 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
256 return default_value;
259 return samdb_result_int64(res[0], attr_name, default_value);
263 search the sam for multipe records each giving a single string attribute
264 return the number of matches, or -1 on error
266 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
268 struct ldb_dn *basedn,
270 const char *attr_name,
271 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
275 const char *attrs[2] = { NULL, NULL };
276 struct ldb_message **res = NULL;
278 attrs[0] = attr_name;
280 va_start(ap, format);
281 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
288 /* make sure its single valued */
289 for (i=0;i<count;i++) {
290 if (res[i]->num_elements != 1) {
291 DEBUG(1,("samdb: search for %s %s not single valued\n",
298 *strs = talloc_array(mem_ctx, const char *, count+1);
304 for (i=0;i<count;i++) {
305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
307 (*strs)[count] = NULL;
313 pull a uint from a result set.
315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
317 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
321 pull a (signed) int64 from a result set.
323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
325 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
329 pull a string from a result set.
331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
332 const char *default_value)
334 return ldb_msg_find_attr_as_string(msg, attr, default_value);
337 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
338 const char *attr, struct ldb_dn *default_value)
340 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
342 return default_value;
348 pull a rid from a objectSid in a result set.
350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
351 const char *attr, uint32_t default_value)
356 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
358 return default_value;
360 rid = sid->sub_auths[sid->num_auths-1];
366 pull a dom_sid structure from a objectSid in a result set.
368 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
371 const struct ldb_val *v;
373 enum ndr_err_code ndr_err;
374 v = ldb_msg_find_ldb_val(msg, attr);
378 sid = talloc(mem_ctx, struct dom_sid);
382 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
383 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
392 pull a guid structure from a objectGUID in a result set.
394 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
396 const struct ldb_val *v;
397 enum ndr_err_code ndr_err;
403 v = ldb_msg_find_ldb_val(msg, attr);
406 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
407 if (!mem_ctx) return guid;
408 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
409 (ndr_pull_flags_fn_t)ndr_pull_GUID);
410 talloc_free(mem_ctx);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
419 pull a sid prefix from a objectSid in a result set.
420 this is used to find the domain sid for a user
422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426 if (!sid || sid->num_auths < 1) return NULL;
432 pull a NTTIME in a result set.
434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
436 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
440 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
441 * indicate an account doesn't expire.
443 * When Windows initially creates an account, it sets
444 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
445 * when changing from an account having a specific expiration date to
446 * that account never expiring, it sets accountExpires = 0.
448 * Consolidate that logic here to allow clearer logic for account expiry in
449 * the rest of the code.
451 NTTIME samdb_result_account_expires(struct ldb_message *msg)
453 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
457 ret = 0x7FFFFFFFFFFFFFFFULL;
463 pull a uint64_t from a result set.
465 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
467 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
472 construct the allow_password_change field from the PwdLastSet attribute and the
473 domain password settings
475 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
477 struct ldb_dn *domain_dn,
478 struct ldb_message *msg,
481 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
484 if (attr_time == 0) {
488 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
490 /* yes, this is a -= not a += as minPwdAge is stored as the negative
491 of the number of 100-nano-seconds */
492 attr_time -= minPwdAge;
498 construct the force_password_change field from the PwdLastSet
499 attribute, the userAccountControl and the domain password settings
501 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
503 struct ldb_dn *domain_dn,
504 struct ldb_message *msg)
506 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
507 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
510 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
511 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
512 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
513 return 0x7FFFFFFFFFFFFFFFULL;
516 if (attr_time == 0) {
520 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
521 if (maxPwdAge == 0) {
522 return 0x7FFFFFFFFFFFFFFFULL;
524 attr_time -= maxPwdAge;
531 pull a samr_Password structutre from a result set.
533 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
535 struct samr_Password *hash = NULL;
536 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
537 if (val && (val->length >= sizeof(hash->hash))) {
538 hash = talloc(mem_ctx, struct samr_Password);
539 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
545 pull an array of samr_Password structutres from a result set.
547 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
548 const char *attr, struct samr_Password **hashes)
551 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
558 count = val->length / 16;
563 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
568 for (i=0;i<count;i++) {
569 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
575 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
576 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
578 struct samr_Password *lmPwdHash, *ntPwdHash;
581 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
584 } else if (num_nt > 1) {
585 return NT_STATUS_INTERNAL_DB_CORRUPTION;
587 *nt_pwd = &ntPwdHash[0];
591 /* Ensure that if we have turned off LM
592 * authentication, that we never use the LM hash, even
594 if (lp_lanman_auth(lp_ctx)) {
596 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
599 } else if (num_lm > 1) {
600 return NT_STATUS_INTERNAL_DB_CORRUPTION;
602 *lm_pwd = &lmPwdHash[0];
612 pull a samr_LogonHours structutre from a result set.
614 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
616 struct samr_LogonHours hours;
617 const int units_per_week = 168;
618 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
620 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
624 hours.units_per_week = units_per_week;
625 memset(hours.bits, 0xFF, units_per_week);
627 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
633 pull a set of account_flags from a result set.
635 This requires that the attributes:
640 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
641 struct ldb_message *msg, struct ldb_dn *domain_dn)
643 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
644 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
645 NTTIME must_change_time;
648 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
651 /* Test account expire time */
652 unix_to_nt_time(&now, time(NULL));
653 /* check for expired password */
654 if (must_change_time < now) {
655 acct_flags |= ACB_PW_EXPIRED;
661 /* Find an attribute, with a particular value */
663 /* The current callers of this function expect a very specific
664 * behaviour: In particular, objectClass subclass equivilance is not
665 * wanted. This means that we should not lookup the schema for the
666 * comparison function */
667 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
668 const struct ldb_message *msg,
669 const char *name, const char *value)
672 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
678 for (i=0;i<el->num_values;i++) {
679 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
687 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
689 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
690 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
695 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
697 struct ldb_message_element *el;
699 el = ldb_msg_find_element(msg, name);
704 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
710 add a string element to a message
712 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
713 const char *attr_name, const char *str)
715 char *s = talloc_strdup(mem_ctx, str);
716 char *a = talloc_strdup(mem_ctx, attr_name);
717 if (s == NULL || a == NULL) {
718 return LDB_ERR_OPERATIONS_ERROR;
720 return ldb_msg_add_string(msg, a, s);
724 add a dom_sid element to a message
726 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
727 const char *attr_name, struct dom_sid *sid)
730 enum ndr_err_code ndr_err;
732 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
733 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
735 (ndr_push_flags_fn_t)ndr_push_dom_sid);
736 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
739 return ldb_msg_add_value(msg, attr_name, &v, NULL);
744 add a delete element operation to a message
746 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
747 const char *attr_name)
749 /* we use an empty replace rather than a delete, as it allows for
750 samdb_replace() to be used everywhere */
751 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
755 add a add attribute value to a message
757 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758 const char *attr_name, const char *value)
760 struct ldb_message_element *el;
763 a = talloc_strdup(mem_ctx, attr_name);
766 v = talloc_strdup(mem_ctx, value);
769 ret = ldb_msg_add_string(msg, a, v);
772 el = ldb_msg_find_element(msg, a);
775 el->flags = LDB_FLAG_MOD_ADD;
780 add a delete attribute value to a message
782 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
783 const char *attr_name, const char *value)
785 struct ldb_message_element *el;
788 a = talloc_strdup(mem_ctx, attr_name);
791 v = talloc_strdup(mem_ctx, value);
794 ret = ldb_msg_add_string(msg, a, v);
797 el = ldb_msg_find_element(msg, a);
800 el->flags = LDB_FLAG_MOD_DELETE;
805 add a int element to a message
807 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
808 const char *attr_name, int v)
810 const char *s = talloc_asprintf(mem_ctx, "%d", v);
811 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
815 add a uint_t element to a message
817 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
818 const char *attr_name, uint_t v)
820 const char *s = talloc_asprintf(mem_ctx, "%u", v);
821 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
825 add a (signed) int64_t element to a message
827 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
828 const char *attr_name, int64_t v)
830 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
831 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
835 add a uint64_t element to a message
837 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
838 const char *attr_name, uint64_t v)
840 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
841 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
845 add a samr_Password element to a message
847 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
848 const char *attr_name, struct samr_Password *hash)
851 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
856 return ldb_msg_add_value(msg, attr_name, &val, NULL);
860 add a samr_Password array to a message
862 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
863 const char *attr_name, struct samr_Password *hashes, uint_t count)
867 val.data = talloc_array_size(mem_ctx, 16, count);
868 val.length = count*16;
872 for (i=0;i<count;i++) {
873 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
875 return ldb_msg_add_value(msg, attr_name, &val, NULL);
879 add a acct_flags element to a message
881 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
882 const char *attr_name, uint32_t v)
884 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
888 add a logon_hours element to a message
890 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891 const char *attr_name, struct samr_LogonHours *hours)
894 val.length = hours->units_per_week / 8;
895 val.data = hours->bits;
896 return ldb_msg_add_value(msg, attr_name, &val, NULL);
900 add a general value element to a message
902 int samdb_msg_add_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 return ldb_msg_add_value(msg, attr_name, val, NULL);
909 sets a general value element to a message
911 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912 const char *attr_name, const struct ldb_val *val)
914 struct ldb_message_element *el;
916 el = ldb_msg_find_element(msg, attr_name);
920 return ldb_msg_add_value(msg, attr_name, val, NULL);
924 set a string element in a message
926 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927 const char *attr_name, const char *str)
929 struct ldb_message_element *el;
931 el = ldb_msg_find_element(msg, attr_name);
935 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
939 replace elements in a record
941 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
945 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
946 for (i=0;i<msg->num_elements;i++) {
947 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
950 /* modify the samdb record */
951 return ldb_modify(sam_ldb, msg);
955 return a default security descriptor
957 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
959 struct security_descriptor *sd;
961 sd = security_descriptor_initialise(mem_ctx);
966 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
968 return ldb_get_default_basedn(sam_ctx);
971 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
973 return ldb_get_config_basedn(sam_ctx);
976 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
978 return ldb_get_schema_basedn(sam_ctx);
981 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
983 return ldb_get_root_basedn(sam_ctx);
986 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
988 struct ldb_dn *new_dn;
990 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
991 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
998 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1000 struct ldb_dn *new_dn;
1002 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1003 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1004 talloc_free(new_dn);
1011 work out the domain sid for the current open ldb
1013 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1015 TALLOC_CTX *tmp_ctx;
1016 const struct dom_sid *domain_sid;
1017 const char *attrs[] = {
1021 struct ldb_result *res;
1024 /* see if we have a cached copy */
1025 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1030 tmp_ctx = talloc_new(ldb);
1031 if (tmp_ctx == NULL) {
1035 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1037 if (ret != LDB_SUCCESS) {
1041 if (res->count != 1) {
1045 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1046 if (domain_sid == NULL) {
1050 /* cache the domain_sid in the ldb */
1051 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1055 talloc_steal(ldb, domain_sid);
1056 talloc_free(tmp_ctx);
1061 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1062 talloc_free(tmp_ctx);
1066 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1068 TALLOC_CTX *tmp_ctx;
1069 struct dom_sid *dom_sid_new;
1070 struct dom_sid *dom_sid_old;
1072 /* see if we have a cached copy */
1073 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1074 "cache.domain_sid"), struct dom_sid);
1076 tmp_ctx = talloc_new(ldb);
1077 if (tmp_ctx == NULL) {
1081 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1086 /* cache the domain_sid in the ldb */
1087 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1091 talloc_steal(ldb, dom_sid_new);
1092 talloc_free(tmp_ctx);
1093 talloc_free(dom_sid_old);
1098 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1099 talloc_free(tmp_ctx);
1103 /* Obtain the short name of the flexible single master operator
1104 * (FSMO), such as the PDC Emulator */
1105 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1108 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1109 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1110 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1111 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1113 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1114 /* Ensure this matches the format. This gives us a
1115 * bit more confidence that a 'cn' value will be a
1120 return (char *)val->data;
1126 work out the ntds settings dn for the current open ldb
1128 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1130 TALLOC_CTX *tmp_ctx;
1131 const char *root_attrs[] = { "dsServiceName", NULL };
1133 struct ldb_result *root_res;
1134 struct ldb_dn *settings_dn;
1136 /* see if we have a cached copy */
1137 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1142 tmp_ctx = talloc_new(ldb);
1143 if (tmp_ctx == NULL) {
1148 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1150 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1151 ldb_errstring(ldb)));
1155 if (root_res->count != 1) {
1159 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1161 /* cache the domain_sid in the ldb */
1162 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1166 talloc_steal(ldb, settings_dn);
1167 talloc_free(tmp_ctx);
1172 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1173 talloc_free(tmp_ctx);
1178 work out the ntds settings invocationId for the current open ldb
1180 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1182 TALLOC_CTX *tmp_ctx;
1183 const char *attrs[] = { "invocationId", NULL };
1185 struct ldb_result *res;
1186 struct GUID *invocation_id;
1188 /* see if we have a cached copy */
1189 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1190 if (invocation_id) {
1191 return invocation_id;
1194 tmp_ctx = talloc_new(ldb);
1195 if (tmp_ctx == NULL) {
1199 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1204 if (res->count != 1) {
1208 invocation_id = talloc(tmp_ctx, struct GUID);
1209 if (!invocation_id) {
1213 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1215 /* cache the domain_sid in the ldb */
1216 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1220 talloc_steal(ldb, invocation_id);
1221 talloc_free(tmp_ctx);
1223 return invocation_id;
1226 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1227 talloc_free(tmp_ctx);
1231 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1233 TALLOC_CTX *tmp_ctx;
1234 struct GUID *invocation_id_new;
1235 struct GUID *invocation_id_old;
1237 /* see if we have a cached copy */
1238 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1239 "cache.invocation_id");
1241 tmp_ctx = talloc_new(ldb);
1242 if (tmp_ctx == NULL) {
1246 invocation_id_new = talloc(tmp_ctx, struct GUID);
1247 if (!invocation_id_new) {
1251 *invocation_id_new = *invocation_id_in;
1253 /* cache the domain_sid in the ldb */
1254 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1258 talloc_steal(ldb, invocation_id_new);
1259 talloc_free(tmp_ctx);
1260 talloc_free(invocation_id_old);
1265 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1266 talloc_free(tmp_ctx);
1271 work out the ntds settings objectGUID for the current open ldb
1273 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1275 TALLOC_CTX *tmp_ctx;
1276 const char *attrs[] = { "objectGUID", NULL };
1278 struct ldb_result *res;
1279 struct GUID *ntds_guid;
1281 /* see if we have a cached copy */
1282 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1287 tmp_ctx = talloc_new(ldb);
1288 if (tmp_ctx == NULL) {
1292 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1297 if (res->count != 1) {
1301 ntds_guid = talloc(tmp_ctx, struct GUID);
1306 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1308 /* cache the domain_sid in the ldb */
1309 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1313 talloc_steal(ldb, ntds_guid);
1314 talloc_free(tmp_ctx);
1319 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1320 talloc_free(tmp_ctx);
1324 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1326 TALLOC_CTX *tmp_ctx;
1327 struct GUID *ntds_guid_new;
1328 struct GUID *ntds_guid_old;
1330 /* see if we have a cached copy */
1331 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1333 tmp_ctx = talloc_new(ldb);
1334 if (tmp_ctx == NULL) {
1338 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1339 if (!ntds_guid_new) {
1343 *ntds_guid_new = *ntds_guid_in;
1345 /* cache the domain_sid in the ldb */
1346 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1350 talloc_steal(ldb, ntds_guid_new);
1351 talloc_free(tmp_ctx);
1352 talloc_free(ntds_guid_old);
1357 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1358 talloc_free(tmp_ctx);
1363 work out the server dn for the current open ldb
1365 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1367 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1371 work out the server dn for the current open ldb
1373 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1375 struct ldb_dn *server_dn;
1376 struct ldb_dn *server_site_dn;
1378 server_dn = samdb_server_dn(ldb, mem_ctx);
1379 if (!server_dn) return NULL;
1381 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1383 talloc_free(server_dn);
1384 return server_site_dn;
1388 work out if we are the PDC for the domain of the current open ldb
1390 bool samdb_is_pdc(struct ldb_context *ldb)
1392 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1394 struct ldb_result *dom_res;
1395 TALLOC_CTX *tmp_ctx;
1399 tmp_ctx = talloc_new(ldb);
1400 if (tmp_ctx == NULL) {
1401 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1405 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1407 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1408 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1409 ldb_errstring(ldb)));
1412 if (dom_res->count != 1) {
1416 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1418 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1424 talloc_free(tmp_ctx);
1429 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1430 talloc_free(tmp_ctx);
1435 work out if we are a Global Catalog server for the domain of the current open ldb
1437 bool samdb_is_gc(struct ldb_context *ldb)
1439 const char *attrs[] = { "options", NULL };
1441 struct ldb_result *res;
1442 TALLOC_CTX *tmp_ctx;
1444 tmp_ctx = talloc_new(ldb);
1445 if (tmp_ctx == NULL) {
1446 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1450 /* Query cn=ntds settings,.... */
1451 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1453 talloc_free(tmp_ctx);
1456 if (res->count != 1) {
1457 talloc_free(tmp_ctx);
1461 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1462 talloc_free(tmp_ctx);
1464 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1465 if (options & 0x000000001) {
1471 /* Find a domain object in the parents of a particular DN. */
1472 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1473 struct ldb_dn **parent_dn, const char **errstring)
1475 TALLOC_CTX *local_ctx;
1476 struct ldb_dn *sdn = dn;
1477 struct ldb_result *res = NULL;
1479 const char *attrs[] = { NULL };
1481 local_ctx = talloc_new(mem_ctx);
1482 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1484 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1485 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1486 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1487 if (ret == LDB_SUCCESS) {
1488 if (res->count == 1) {
1496 if (ret != LDB_SUCCESS) {
1497 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1498 ldb_dn_get_linearized(dn),
1499 ldb_dn_get_linearized(sdn),
1500 ldb_errstring(ldb));
1501 talloc_free(local_ctx);
1504 if (res->count != 1) {
1505 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1506 ldb_dn_get_linearized(dn));
1507 talloc_free(local_ctx);
1508 return LDB_ERR_CONSTRAINT_VIOLATION;
1511 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1512 talloc_free(local_ctx);
1517 check that a password is sufficiently complex
1519 static bool samdb_password_complexity_ok(const char *pass)
1521 return check_password_quality(pass);
1527 set the user password using plaintext, obeying any user or domain
1528 password restrictions
1530 note that this function doesn't actually store the result in the
1531 database, it just fills in the "mod" structure with ldb modify
1532 elements to setup the correct change when samdb_replace() is
1533 called. This allows the caller to combine the change with other
1534 changes (as is needed by some of the set user info levels)
1536 The caller should probably have a transaction wrapping this
1538 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1539 struct ldb_dn *user_dn,
1540 struct ldb_dn *domain_dn,
1541 struct ldb_message *mod,
1542 const DATA_BLOB *new_password,
1543 struct samr_Password *lmNewHash,
1544 struct samr_Password *ntNewHash,
1546 enum samr_RejectReason *reject_reason,
1547 struct samr_DomInfo1 **_dominfo)
1549 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1551 "dBCSPwd", "unicodePwd",
1553 "pwdLastSet", NULL };
1554 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1555 "maxPwdAge", "minPwdAge",
1556 "minPwdLength", NULL };
1559 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1560 uint_t userAccountControl;
1561 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1562 struct samr_Password local_lmNewHash, local_ntNewHash;
1563 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1564 struct dom_sid *domain_sid;
1565 struct ldb_message **res;
1568 time_t now = time(NULL);
1572 /* we need to know the time to compute password age */
1573 unix_to_nt_time(&now_nt, now);
1575 /* pull all the user parameters */
1576 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1578 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1580 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1581 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1582 "lmPwdHistory", &sambaLMPwdHistory);
1583 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1584 "ntPwdHistory", &sambaNTPwdHistory);
1585 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1586 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1587 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1589 /* Only non-trust accounts have restrictions (possibly this
1590 * test is the wrong way around, but I like to be restrictive
1592 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1593 |UF_WORKSTATION_TRUST_ACCOUNT
1594 |UF_SERVER_TRUST_ACCOUNT));
1597 /* pull the domain parameters */
1598 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1600 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1601 ldb_dn_get_linearized(domain_dn),
1602 ldb_dn_get_linearized(user_dn)));
1603 return NT_STATUS_NO_SUCH_DOMAIN;
1606 /* work out the domain sid, and pull the domain from there */
1607 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1608 if (domain_sid == NULL) {
1609 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1612 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1614 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1616 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1617 dom_sid_string(mem_ctx, domain_sid),
1618 ldb_dn_get_linearized(user_dn)));
1619 return NT_STATUS_NO_SUCH_DOMAIN;
1623 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1624 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1625 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1626 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1629 struct samr_DomInfo1 *dominfo;
1630 /* on failure we need to fill in the reject reasons */
1631 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1632 if (dominfo == NULL) {
1633 return NT_STATUS_NO_MEMORY;
1635 dominfo->min_password_length = minPwdLength;
1636 dominfo->password_properties = pwdProperties;
1637 dominfo->password_history_length = pwdHistoryLength;
1638 dominfo->max_password_age = minPwdAge;
1639 dominfo->min_password_age = minPwdAge;
1640 *_dominfo = dominfo;
1643 if (restrictions && new_password) {
1646 /* check the various password restrictions */
1647 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1648 if (reject_reason) {
1649 *reject_reason = SAMR_REJECT_TOO_SHORT;
1651 return NT_STATUS_PASSWORD_RESTRICTION;
1654 /* Create the NT hash */
1655 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1657 ntNewHash = &local_ntNewHash;
1659 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1660 if (convert_string_talloc(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1662 new_password->data, new_password->length,
1663 (void **)&new_pass) != -1) {
1666 /* possibly check password complexity */
1667 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1668 !samdb_password_complexity_ok(new_pass)) {
1669 if (reject_reason) {
1670 *reject_reason = SAMR_REJECT_COMPLEXITY;
1672 return NT_STATUS_PASSWORD_RESTRICTION;
1675 /* compute the new lm hashes (for checking history - case insenitivly!) */
1676 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1677 lmNewHash = &local_lmNewHash;
1683 if (restrictions && user_change) {
1684 /* are all password changes disallowed? */
1685 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1686 if (reject_reason) {
1687 *reject_reason = SAMR_REJECT_OTHER;
1689 return NT_STATUS_PASSWORD_RESTRICTION;
1692 /* can this user change password? */
1693 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1694 if (reject_reason) {
1695 *reject_reason = SAMR_REJECT_OTHER;
1697 return NT_STATUS_PASSWORD_RESTRICTION;
1700 /* yes, this is a minus. The ages are in negative 100nsec units! */
1701 if (pwdLastSet - minPwdAge > now_nt) {
1702 if (reject_reason) {
1703 *reject_reason = SAMR_REJECT_OTHER;
1705 return NT_STATUS_PASSWORD_RESTRICTION;
1708 /* check the immediately past password */
1709 if (pwdHistoryLength > 0) {
1710 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1711 if (reject_reason) {
1712 *reject_reason = SAMR_REJECT_IN_HISTORY;
1714 return NT_STATUS_PASSWORD_RESTRICTION;
1716 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1717 if (reject_reason) {
1718 *reject_reason = SAMR_REJECT_IN_HISTORY;
1720 return NT_STATUS_PASSWORD_RESTRICTION;
1724 /* check the password history */
1725 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1726 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1728 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1729 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1730 if (reject_reason) {
1731 *reject_reason = SAMR_REJECT_IN_HISTORY;
1733 return NT_STATUS_PASSWORD_RESTRICTION;
1736 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1737 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1738 if (reject_reason) {
1739 *reject_reason = SAMR_REJECT_IN_HISTORY;
1741 return NT_STATUS_PASSWORD_RESTRICTION;
1746 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1748 /* the password is acceptable. Start forming the new fields */
1750 /* if we know the cleartext UTF16 password, then set it.
1751 * Modules in ldb will set all the appropriate
1753 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1755 /* We don't have the cleartext, so delete the old one
1756 * and set what we have of the hashes */
1757 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1760 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1762 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1766 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1768 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1772 return NT_STATUS_OK;
1777 set the user password using plaintext, obeying any user or domain
1778 password restrictions
1780 This wrapper function takes a SID as input, rather than a user DN,
1781 and actually performs the password change
1784 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1785 const struct dom_sid *user_sid,
1786 const DATA_BLOB *new_pass,
1787 struct samr_Password *lmNewHash,
1788 struct samr_Password *ntNewHash,
1790 enum samr_RejectReason *reject_reason,
1791 struct samr_DomInfo1 **_dominfo)
1794 struct ldb_dn *user_dn;
1795 struct ldb_message *msg;
1798 ret = ldb_transaction_start(ctx);
1800 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1801 return NT_STATUS_TRANSACTION_ABORTED;
1804 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1805 "(&(objectSid=%s)(objectClass=user))",
1806 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1808 ldb_transaction_cancel(ctx);
1809 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1810 dom_sid_string(mem_ctx, user_sid)));
1811 return NT_STATUS_NO_SUCH_USER;
1814 msg = ldb_msg_new(mem_ctx);
1816 ldb_transaction_cancel(ctx);
1817 return NT_STATUS_NO_MEMORY;
1820 msg->dn = ldb_dn_copy(msg, user_dn);
1822 ldb_transaction_cancel(ctx);
1823 return NT_STATUS_NO_MEMORY;
1826 nt_status = samdb_set_password(ctx, mem_ctx,
1829 lmNewHash, ntNewHash,
1830 user_change, /* This is a password set, not change */
1831 reject_reason, _dominfo);
1832 if (!NT_STATUS_IS_OK(nt_status)) {
1833 ldb_transaction_cancel(ctx);
1837 /* modify the samdb record */
1838 ret = samdb_replace(ctx, mem_ctx, msg);
1840 ldb_transaction_cancel(ctx);
1841 return NT_STATUS_ACCESS_DENIED;
1844 ret = ldb_transaction_commit(ctx);
1846 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1847 ldb_dn_get_linearized(msg->dn),
1848 ldb_errstring(ctx)));
1849 return NT_STATUS_TRANSACTION_ABORTED;
1851 return NT_STATUS_OK;
1856 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1857 struct dom_sid *sid, struct ldb_dn **ret_dn)
1859 struct ldb_message *msg;
1860 struct ldb_dn *basedn;
1864 sidstr = dom_sid_string(mem_ctx, sid);
1865 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1867 /* We might have to create a ForeignSecurityPrincipal, even if this user
1868 * is in our own domain */
1870 msg = ldb_msg_new(mem_ctx);
1872 return NT_STATUS_NO_MEMORY;
1875 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1876 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1877 * not work, this is wrong for the Builtin domain, there's no
1878 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1881 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1882 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1884 if (basedn == NULL) {
1885 DEBUG(0, ("Failed to find DN for "
1886 "ForeignSecurityPrincipal container\n"));
1887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1890 /* add core elements to the ldb_message for the alias */
1891 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1892 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1893 return NT_STATUS_NO_MEMORY;
1895 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1897 "foreignSecurityPrincipal");
1899 /* create the alias */
1900 ret = ldb_add(sam_ctx, msg);
1902 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1904 ldb_dn_get_linearized(msg->dn),
1905 ldb_errstring(sam_ctx)));
1906 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1909 return NT_STATUS_OK;
1914 Find the DN of a domain, assuming it to be a dotted.dns name
1917 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1920 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1921 const char *binary_encoded;
1922 const char **split_realm;
1929 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1931 talloc_free(tmp_ctx);
1934 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1935 for (i=0; split_realm[i]; i++) {
1936 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1937 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1938 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1939 binary_encoded, ldb_dn_get_linearized(dn)));
1940 talloc_free(tmp_ctx);
1944 if (!ldb_dn_validate(dn)) {
1945 DEBUG(2, ("Failed to validated DN %s\n",
1946 ldb_dn_get_linearized(dn)));
1952 Find the DN of a domain, be it the netbios or DNS name
1955 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1956 const char *domain_name)
1958 const char * const domain_ref_attrs[] = {
1961 const char * const domain_ref2_attrs[] = {
1964 struct ldb_result *res_domain_ref;
1965 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1966 /* find the domain's DN */
1967 int ret_domain = ldb_search(ldb, mem_ctx,
1969 samdb_partitions_dn(ldb, mem_ctx),
1972 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1974 if (ret_domain != 0) {
1978 if (res_domain_ref->count == 0) {
1979 ret_domain = ldb_search(ldb, mem_ctx,
1981 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1984 "(objectclass=domain)");
1985 if (ret_domain != 0) {
1989 if (res_domain_ref->count == 1) {
1990 return res_domain_ref->msgs[0]->dn;
1995 if (res_domain_ref->count > 1) {
1996 DEBUG(0,("Found %d records matching domain [%s]\n",
1997 ret_domain, domain_name));
2001 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);