2 Unix SMB/CIFS implementation.
4 interface functions for the sam database
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
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 "librpc/gen_ndr/ndr_netlogon.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "libcli/security/security.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "libcli/ldap/ldap.h"
33 #include "system/time.h"
34 #include "system/filesys.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/common/flags.h"
38 #include "param/param.h"
41 connect to the SAM database
42 return an opaque context pointer on success, or NULL on failure
44 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
45 struct auth_session_info *session_info)
47 struct ldb_context *ldb;
48 ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
53 dsdb_make_schema_global(ldb);
58 search the sam for the specified attributes in a specific domain, filter on
59 objectSid being in domain_sid.
61 int samdb_search_domain(struct ldb_context *sam_ldb,
63 struct ldb_dn *basedn,
64 struct ldb_message ***res,
65 const char * const *attrs,
66 const struct dom_sid *domain_sid,
67 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
73 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
74 res, attrs, format, ap);
80 struct dom_sid *entry_sid;
82 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
84 if ((entry_sid == NULL) ||
85 (!dom_sid_in_domain(domain_sid, entry_sid))) {
86 /* Delete that entry from the result set */
87 (*res)[i] = (*res)[count-1];
89 talloc_free(entry_sid);
92 talloc_free(entry_sid);
100 search the sam for a single string attribute in exactly 1 record
102 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
104 struct ldb_dn *basedn,
105 const char *attr_name,
106 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
109 const char *attrs[2] = { NULL, NULL };
110 struct ldb_message **res = NULL;
112 attrs[0] = attr_name;
114 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
116 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
117 attr_name, format, count));
124 return samdb_result_string(res[0], attr_name, NULL);
129 search the sam for a single string attribute in exactly 1 record
131 const char *samdb_search_string(struct ldb_context *sam_ldb,
133 struct ldb_dn *basedn,
134 const char *attr_name,
135 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
140 va_start(ap, format);
141 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
147 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
149 struct ldb_dn *basedn,
150 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
154 struct ldb_message **res = NULL;
157 va_start(ap, format);
158 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
161 if (count != 1) return NULL;
163 ret = talloc_steal(mem_ctx, res[0]->dn);
170 search the sam for a dom_sid attribute in exactly 1 record
172 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
174 struct ldb_dn *basedn,
175 const char *attr_name,
176 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
180 struct ldb_message **res;
181 const char *attrs[2] = { NULL, NULL };
184 attrs[0] = attr_name;
186 va_start(ap, format);
187 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
190 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
191 attr_name, format, count));
197 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
203 return the count of the number of records in the sam matching the query
205 int samdb_search_count(struct ldb_context *sam_ldb,
207 struct ldb_dn *basedn,
208 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
211 struct ldb_message **res;
212 const char * const attrs[] = { NULL };
215 va_start(ap, format);
216 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
224 search the sam for a single integer attribute in exactly 1 record
226 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
228 uint_t default_value,
229 struct ldb_dn *basedn,
230 const char *attr_name,
231 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
235 struct ldb_message **res;
236 const char *attrs[2] = { NULL, NULL };
238 attrs[0] = attr_name;
240 va_start(ap, format);
241 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
245 return default_value;
248 return samdb_result_uint(res[0], attr_name, default_value);
252 search the sam for a single signed 64 bit integer attribute in exactly 1 record
254 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
256 int64_t default_value,
257 struct ldb_dn *basedn,
258 const char *attr_name,
259 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
263 struct ldb_message **res;
264 const char *attrs[2] = { NULL, NULL };
266 attrs[0] = attr_name;
268 va_start(ap, format);
269 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
273 return default_value;
276 return samdb_result_int64(res[0], attr_name, default_value);
280 search the sam for multipe records each giving a single string attribute
281 return the number of matches, or -1 on error
283 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
285 struct ldb_dn *basedn,
287 const char *attr_name,
288 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
292 const char *attrs[2] = { NULL, NULL };
293 struct ldb_message **res = NULL;
295 attrs[0] = attr_name;
297 va_start(ap, format);
298 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
305 /* make sure its single valued */
306 for (i=0;i<count;i++) {
307 if (res[i]->num_elements != 1) {
308 DEBUG(1,("samdb: search for %s %s not single valued\n",
315 *strs = talloc_array(mem_ctx, const char *, count+1);
321 for (i=0;i<count;i++) {
322 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
324 (*strs)[count] = NULL;
330 pull a uint from a result set.
332 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
334 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
338 pull a (signed) int64 from a result set.
340 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
342 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
346 pull a string from a result set.
348 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
349 const char *default_value)
351 return ldb_msg_find_attr_as_string(msg, attr, default_value);
354 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
355 const char *attr, struct ldb_dn *default_value)
357 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
359 return default_value;
365 pull a rid from a objectSid in a result set.
367 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
368 const char *attr, uint32_t default_value)
373 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
375 return default_value;
377 rid = sid->sub_auths[sid->num_auths-1];
383 pull a dom_sid structure from a objectSid in a result set.
385 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
388 const struct ldb_val *v;
391 v = ldb_msg_find_ldb_val(msg, attr);
395 sid = talloc(mem_ctx, struct dom_sid);
399 status = ndr_pull_struct_blob(v, sid, sid,
400 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
401 if (!NT_STATUS_IS_OK(status)) {
409 pull a guid structure from a objectGUID in a result set.
411 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
413 const struct ldb_val *v;
420 v = ldb_msg_find_ldb_val(msg, attr);
423 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
424 if (!mem_ctx) return guid;
425 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
426 (ndr_pull_flags_fn_t)ndr_pull_GUID);
427 talloc_free(mem_ctx);
428 if (!NT_STATUS_IS_OK(status)) {
436 pull a sid prefix from a objectSid in a result set.
437 this is used to find the domain sid for a user
439 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
442 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
443 if (!sid || sid->num_auths < 1) return NULL;
449 pull a NTTIME in a result set.
451 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
453 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
457 pull a uint64_t from a result set.
459 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
461 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
466 construct the allow_password_change field from the PwdLastSet attribute and the
467 domain password settings
469 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
471 struct ldb_dn *domain_dn,
472 struct ldb_message *msg,
475 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
478 if (attr_time == 0) {
482 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
484 /* yes, this is a -= not a += as minPwdAge is stored as the negative
485 of the number of 100-nano-seconds */
486 attr_time -= minPwdAge;
492 construct the force_password_change field from the PwdLastSet attribute and the
493 domain password settings
495 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
497 struct ldb_dn *domain_dn,
498 struct ldb_message *msg)
500 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
501 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
504 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
505 return 0x7FFFFFFFFFFFFFFFULL;
508 if (attr_time == 0) {
512 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
513 if (maxPwdAge == 0) {
516 attr_time -= maxPwdAge;
523 pull a samr_Password structutre from a result set.
525 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
527 struct samr_Password *hash = NULL;
528 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
529 if (val && (val->length >= sizeof(hash->hash))) {
530 hash = talloc(mem_ctx, struct samr_Password);
531 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
537 pull an array of samr_Password structutres from a result set.
539 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
540 const char *attr, struct samr_Password **hashes)
543 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
550 count = val->length / 16;
555 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
560 for (i=0;i<count;i++) {
561 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
567 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
568 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
570 struct samr_Password *lmPwdHash, *ntPwdHash;
573 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
576 } else if (num_nt > 1) {
577 return NT_STATUS_INTERNAL_DB_CORRUPTION;
579 *nt_pwd = &ntPwdHash[0];
584 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
587 } else if (num_lm > 1) {
588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590 *lm_pwd = &lmPwdHash[0];
597 pull a samr_LogonHours structutre from a result set.
599 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
601 struct samr_LogonHours hours;
602 const int units_per_week = 168;
603 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
605 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
609 hours.units_per_week = units_per_week;
610 memset(hours.bits, 0xFF, units_per_week);
612 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
618 pull a set of account_flags from a result set.
620 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
622 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
623 return samdb_uf2acb(userAccountControl);
627 /* Find an attribute, with a particular value */
629 /* The current callers of this function expect a very specific
630 * behaviour: In particular, objectClass subclass equivilance is not
631 * wanted. This means that we should not lookup the schema for the
632 * comparison function */
633 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
634 const struct ldb_message *msg,
635 const char *name, const char *value)
638 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
641 v.data = discard_const_p(uint8_t, value);
642 v.length = strlen(value);
648 for (i=0;i<el->num_values;i++) {
649 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
657 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
659 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
660 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
665 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
667 struct ldb_message_element *el;
669 el = ldb_msg_find_element(msg, name);
674 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
679 copy from a template record to a message
681 int samdb_copy_template(struct ldb_context *ldb,
682 struct ldb_message *msg, const char *name,
683 const char **errstring)
685 struct ldb_result *res;
686 struct ldb_message *t;
688 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
692 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
693 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
695 return LDB_ERR_OPERATIONS_ERROR;
698 /* pull the template record */
699 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
701 if (ret != LDB_SUCCESS) {
702 *errstring = talloc_steal(msg, ldb_errstring(ldb));
705 if (res->count != 1) {
706 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
710 return LDB_ERR_OPERATIONS_ERROR;
714 for (i = 0; i < t->num_elements; i++) {
715 struct ldb_message_element *el = &t->elements[i];
716 /* some elements should not be copied from the template */
717 if (ldb_attr_cmp(el->name, "cn") == 0 ||
718 ldb_attr_cmp(el->name, "name") == 0 ||
719 ldb_attr_cmp(el->name, "objectClass") == 0 ||
720 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
721 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
722 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
723 ldb_attr_cmp(el->name, "objectGUID") == 0) {
726 for (j = 0; j < el->num_values; j++) {
727 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
728 (char *)el->values[j].data);
730 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
744 add a string element to a message
746 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
747 const char *attr_name, const char *str)
749 char *s = talloc_strdup(mem_ctx, str);
750 char *a = talloc_strdup(mem_ctx, attr_name);
751 if (s == NULL || a == NULL) {
752 return LDB_ERR_OPERATIONS_ERROR;
754 return ldb_msg_add_string(msg, a, s);
758 add a dom_sid element to a message
760 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
761 const char *attr_name, struct dom_sid *sid)
765 status = ndr_push_struct_blob(&v, mem_ctx, sid,
766 (ndr_push_flags_fn_t)ndr_push_dom_sid);
767 if (!NT_STATUS_IS_OK(status)) {
770 return ldb_msg_add_value(msg, attr_name, &v, NULL);
775 add a delete element operation to a message
777 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
778 const char *attr_name)
780 /* we use an empty replace rather than a delete, as it allows for
781 samdb_replace() to be used everywhere */
782 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
786 add a add attribute value to a message
788 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
789 const char *attr_name, const char *value)
791 struct ldb_message_element *el;
794 a = talloc_strdup(mem_ctx, attr_name);
797 v = talloc_strdup(mem_ctx, value);
800 ret = ldb_msg_add_string(msg, a, v);
803 el = ldb_msg_find_element(msg, a);
806 el->flags = LDB_FLAG_MOD_ADD;
811 add a delete attribute value to a message
813 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
814 const char *attr_name, const char *value)
816 struct ldb_message_element *el;
819 a = talloc_strdup(mem_ctx, attr_name);
822 v = talloc_strdup(mem_ctx, value);
825 ret = ldb_msg_add_string(msg, a, v);
828 el = ldb_msg_find_element(msg, a);
831 el->flags = LDB_FLAG_MOD_DELETE;
836 add a int element to a message
838 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
839 const char *attr_name, int v)
841 const char *s = talloc_asprintf(mem_ctx, "%d", v);
842 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
846 add a uint_t element to a message
848 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849 const char *attr_name, uint_t v)
851 const char *s = talloc_asprintf(mem_ctx, "%u", v);
852 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
856 add a (signed) int64_t element to a message
858 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
859 const char *attr_name, int64_t v)
861 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
862 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
866 add a uint64_t element to a message
868 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
869 const char *attr_name, uint64_t v)
871 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
872 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
876 add a samr_Password element to a message
878 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
879 const char *attr_name, struct samr_Password *hash)
882 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
887 return ldb_msg_add_value(msg, attr_name, &val, NULL);
891 add a samr_Password array to a message
893 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
894 const char *attr_name, struct samr_Password *hashes, uint_t count)
898 val.data = talloc_array_size(mem_ctx, 16, count);
899 val.length = count*16;
903 for (i=0;i<count;i++) {
904 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
906 return ldb_msg_add_value(msg, attr_name, &val, NULL);
910 add a acct_flags element to a message
912 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
913 const char *attr_name, uint32_t v)
915 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
919 add a logon_hours element to a message
921 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
922 const char *attr_name, struct samr_LogonHours *hours)
925 val.length = hours->units_per_week / 8;
926 val.data = hours->bits;
927 return ldb_msg_add_value(msg, attr_name, &val, NULL);
931 add a general value element to a message
933 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
934 const char *attr_name, const struct ldb_val *val)
936 return ldb_msg_add_value(msg, attr_name, val, NULL);
940 sets a general value element to a message
942 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
943 const char *attr_name, const struct ldb_val *val)
945 struct ldb_message_element *el;
947 el = ldb_msg_find_element(msg, attr_name);
951 return ldb_msg_add_value(msg, attr_name, val, NULL);
955 set a string element in a message
957 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
958 const char *attr_name, const char *str)
960 struct ldb_message_element *el;
962 el = ldb_msg_find_element(msg, attr_name);
966 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
972 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
974 return ldb_add(sam_ldb, msg);
980 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
982 return ldb_delete(sam_ldb, dn);
988 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
990 return ldb_modify(sam_ldb, msg);
994 replace elements in a record
996 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1000 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1001 for (i=0;i<msg->num_elements;i++) {
1002 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1005 /* modify the samdb record */
1006 return samdb_modify(sam_ldb, mem_ctx, msg);
1010 return a default security descriptor
1012 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1014 struct security_descriptor *sd;
1016 sd = security_descriptor_initialise(mem_ctx);
1021 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1023 return ldb_get_default_basedn(sam_ctx);
1026 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1028 return ldb_get_config_basedn(sam_ctx);
1031 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1033 return ldb_get_schema_basedn(sam_ctx);
1036 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1038 return ldb_get_root_basedn(sam_ctx);
1041 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1043 struct ldb_dn *new_dn;
1045 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1046 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1047 talloc_free(new_dn);
1053 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1055 struct ldb_dn *new_dn;
1057 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1058 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1059 talloc_free(new_dn);
1066 work out the domain sid for the current open ldb
1068 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1070 TALLOC_CTX *tmp_ctx;
1071 struct dom_sid *domain_sid;
1073 /* see if we have a cached copy */
1074 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1079 tmp_ctx = talloc_new(ldb);
1080 if (tmp_ctx == NULL) {
1084 /* find the domain_sid */
1085 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1086 "objectSid", "objectClass=domainDNS");
1087 if (domain_sid == NULL) {
1091 /* cache the domain_sid in the ldb */
1092 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1096 talloc_steal(ldb, domain_sid);
1097 talloc_free(tmp_ctx);
1102 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1103 talloc_free(tmp_ctx);
1107 /* Obtain the short name of the flexible single master operator
1108 * (FSMO), such as the PDC Emulator */
1109 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1112 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1113 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1114 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1115 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1117 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1118 /* Ensure this matches the format. This gives us a
1119 * bit more confidence that a 'cn' value will be a
1124 return (char *)val->data;
1130 work out the ntds settings dn for the current open ldb
1132 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1134 TALLOC_CTX *tmp_ctx;
1135 const char *root_attrs[] = { "dsServiceName", NULL };
1137 struct ldb_result *root_res;
1138 struct ldb_dn *settings_dn;
1140 /* see if we have a cached copy */
1141 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1146 tmp_ctx = talloc_new(ldb);
1147 if (tmp_ctx == NULL) {
1152 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1154 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1155 ldb_errstring(ldb)));
1158 talloc_steal(tmp_ctx, root_res);
1160 if (root_res->count != 1) {
1164 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1166 /* cache the domain_sid in the ldb */
1167 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1171 talloc_steal(ldb, settings_dn);
1172 talloc_free(tmp_ctx);
1177 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1178 talloc_free(tmp_ctx);
1183 work out the ntds settings invocationId for the current open ldb
1185 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1187 TALLOC_CTX *tmp_ctx;
1188 const char *attrs[] = { "invocationId", NULL };
1190 struct ldb_result *res;
1191 struct GUID *invocation_id;
1193 /* see if we have a cached copy */
1194 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1195 if (invocation_id) {
1196 return invocation_id;
1199 tmp_ctx = talloc_new(ldb);
1200 if (tmp_ctx == NULL) {
1204 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1208 talloc_steal(tmp_ctx, res);
1210 if (res->count != 1) {
1214 invocation_id = talloc(tmp_ctx, struct GUID);
1215 if (!invocation_id) {
1219 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1221 /* cache the domain_sid in the ldb */
1222 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1226 talloc_steal(ldb, invocation_id);
1227 talloc_free(tmp_ctx);
1229 return invocation_id;
1232 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1233 talloc_free(tmp_ctx);
1237 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1239 TALLOC_CTX *tmp_ctx;
1240 struct GUID *invocation_id_new;
1241 struct GUID *invocation_id_old;
1243 /* see if we have a cached copy */
1244 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1245 "cache.invocation_id");
1247 tmp_ctx = talloc_new(ldb);
1248 if (tmp_ctx == NULL) {
1252 invocation_id_new = talloc(tmp_ctx, struct GUID);
1253 if (!invocation_id_new) {
1257 *invocation_id_new = *invocation_id_in;
1259 /* cache the domain_sid in the ldb */
1260 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1264 talloc_steal(ldb, invocation_id_new);
1265 talloc_free(tmp_ctx);
1266 talloc_free(invocation_id_old);
1271 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1272 talloc_free(tmp_ctx);
1277 work out the ntds settings objectGUID for the current open ldb
1279 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1281 TALLOC_CTX *tmp_ctx;
1282 const char *attrs[] = { "objectGUID", NULL };
1284 struct ldb_result *res;
1285 struct GUID *ntds_guid;
1287 /* see if we have a cached copy */
1288 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1293 tmp_ctx = talloc_new(ldb);
1294 if (tmp_ctx == NULL) {
1298 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1302 talloc_steal(tmp_ctx, res);
1304 if (res->count != 1) {
1308 ntds_guid = talloc(tmp_ctx, struct GUID);
1313 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1315 /* cache the domain_sid in the ldb */
1316 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1320 talloc_steal(ldb, ntds_guid);
1321 talloc_free(tmp_ctx);
1326 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1327 talloc_free(tmp_ctx);
1331 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1333 TALLOC_CTX *tmp_ctx;
1334 struct GUID *ntds_guid_new;
1335 struct GUID *ntds_guid_old;
1337 /* see if we have a cached copy */
1338 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1340 tmp_ctx = talloc_new(ldb);
1341 if (tmp_ctx == NULL) {
1345 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1346 if (!ntds_guid_new) {
1350 *ntds_guid_new = *ntds_guid_in;
1352 /* cache the domain_sid in the ldb */
1353 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1357 talloc_steal(ldb, ntds_guid_new);
1358 talloc_free(tmp_ctx);
1359 talloc_free(ntds_guid_old);
1364 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1365 talloc_free(tmp_ctx);
1370 work out the server dn for the current open ldb
1372 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1374 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1378 work out the server dn for the current open ldb
1380 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1382 struct ldb_dn *server_dn;
1383 struct ldb_dn *server_site_dn;
1385 server_dn = samdb_server_dn(ldb, mem_ctx);
1386 if (!server_dn) return NULL;
1388 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1390 talloc_free(server_dn);
1391 return server_site_dn;
1395 work out if we are the PDC for the domain of the current open ldb
1397 BOOL samdb_is_pdc(struct ldb_context *ldb)
1399 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1401 struct ldb_result *dom_res;
1402 TALLOC_CTX *tmp_ctx;
1406 tmp_ctx = talloc_new(ldb);
1407 if (tmp_ctx == NULL) {
1408 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1412 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1414 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1415 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1416 ldb_errstring(ldb)));
1419 talloc_steal(tmp_ctx, dom_res);
1420 if (dom_res->count != 1) {
1424 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1426 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1432 talloc_free(tmp_ctx);
1437 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1438 talloc_free(tmp_ctx);
1443 /* Find a domain object in the parents of a particular DN. */
1444 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1446 TALLOC_CTX *local_ctx;
1447 struct ldb_dn *sdn = dn;
1448 struct ldb_result *res = NULL;
1450 const char *attrs[] = { NULL };
1452 local_ctx = talloc_new(mem_ctx);
1453 if (local_ctx == NULL) return NULL;
1455 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1456 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1457 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1458 if (ret == LDB_SUCCESS) {
1459 talloc_steal(local_ctx, res);
1460 if (res->count == 1) {
1466 if (ret != LDB_SUCCESS || res->count != 1) {
1467 talloc_free(local_ctx);
1471 talloc_steal(mem_ctx, sdn);
1472 talloc_free(local_ctx);
1478 check that a password is sufficiently complex
1480 static BOOL samdb_password_complexity_ok(const char *pass)
1482 return check_password_quality(pass);
1488 set the user password using plaintext, obeying any user or domain
1489 password restrictions
1491 note that this function doesn't actually store the result in the
1492 database, it just fills in the "mod" structure with ldb modify
1493 elements to setup the correct change when samdb_replace() is
1494 called. This allows the caller to combine the change with other
1495 changes (as is needed by some of the set user info levels)
1497 The caller should probably have a transaction wrapping this
1499 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1500 struct ldb_dn *user_dn,
1501 struct ldb_dn *domain_dn,
1502 struct ldb_message *mod,
1503 const char *new_pass,
1504 struct samr_Password *lmNewHash,
1505 struct samr_Password *ntNewHash,
1507 enum samr_RejectReason *reject_reason,
1508 struct samr_DomInfo1 **_dominfo)
1510 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1512 "dBCSPwd", "unicodePwd",
1514 "pwdLastSet", NULL };
1515 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1516 "maxPwdAge", "minPwdAge",
1517 "minPwdLength", NULL };
1520 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1521 uint_t userAccountControl;
1522 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1523 struct samr_Password local_lmNewHash, local_ntNewHash;
1524 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1525 struct dom_sid *domain_sid;
1526 struct ldb_message **res;
1529 time_t now = time(NULL);
1533 /* we need to know the time to compute password age */
1534 unix_to_nt_time(&now_nt, now);
1536 /* pull all the user parameters */
1537 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1539 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1541 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1542 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1543 "lmPwdHistory", &sambaLMPwdHistory);
1544 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1545 "ntPwdHistory", &sambaNTPwdHistory);
1546 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1547 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1548 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1550 /* Only non-trust accounts have restrictions (possibly this
1551 * test is the wrong way around, but I like to be restrictive
1553 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1554 |UF_WORKSTATION_TRUST_ACCOUNT
1555 |UF_SERVER_TRUST_ACCOUNT));
1558 /* pull the domain parameters */
1559 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1561 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1562 ldb_dn_get_linearized(domain_dn),
1563 ldb_dn_get_linearized(user_dn)));
1564 return NT_STATUS_NO_SUCH_DOMAIN;
1567 /* work out the domain sid, and pull the domain from there */
1568 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1569 if (domain_sid == NULL) {
1570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1573 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1575 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1577 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1578 dom_sid_string(mem_ctx, domain_sid),
1579 ldb_dn_get_linearized(user_dn)));
1580 return NT_STATUS_NO_SUCH_DOMAIN;
1584 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1585 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1586 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1587 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1590 struct samr_DomInfo1 *dominfo;
1591 /* on failure we need to fill in the reject reasons */
1592 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1593 if (dominfo == NULL) {
1594 return NT_STATUS_NO_MEMORY;
1596 dominfo->min_password_length = minPwdLength;
1597 dominfo->password_properties = pwdProperties;
1598 dominfo->password_history_length = pwdHistoryLength;
1599 dominfo->max_password_age = minPwdAge;
1600 dominfo->min_password_age = minPwdAge;
1601 *_dominfo = dominfo;
1604 if (restrictions && new_pass) {
1606 /* check the various password restrictions */
1607 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1608 if (reject_reason) {
1609 *reject_reason = SAMR_REJECT_TOO_SHORT;
1611 return NT_STATUS_PASSWORD_RESTRICTION;
1614 /* possibly check password complexity */
1615 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1616 !samdb_password_complexity_ok(new_pass)) {
1617 if (reject_reason) {
1618 *reject_reason = SAMR_REJECT_COMPLEXITY;
1620 return NT_STATUS_PASSWORD_RESTRICTION;
1623 /* compute the new nt and lm hashes */
1624 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1625 lmNewHash = &local_lmNewHash;
1627 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1628 /* If we can't convert this password to UCS2, then we should not accept it */
1629 if (reject_reason) {
1630 *reject_reason = SAMR_REJECT_OTHER;
1632 return NT_STATUS_PASSWORD_RESTRICTION;
1634 ntNewHash = &local_ntNewHash;
1638 /* are all password changes disallowed? */
1639 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1640 if (reject_reason) {
1641 *reject_reason = SAMR_REJECT_OTHER;
1643 return NT_STATUS_PASSWORD_RESTRICTION;
1646 /* can this user change password? */
1647 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1648 if (reject_reason) {
1649 *reject_reason = SAMR_REJECT_OTHER;
1651 return NT_STATUS_PASSWORD_RESTRICTION;
1654 /* yes, this is a minus. The ages are in negative 100nsec units! */
1655 if (pwdLastSet - minPwdAge > now_nt) {
1656 if (reject_reason) {
1657 *reject_reason = SAMR_REJECT_OTHER;
1659 return NT_STATUS_PASSWORD_RESTRICTION;
1662 /* check the immediately past password */
1663 if (pwdHistoryLength > 0) {
1664 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1665 if (reject_reason) {
1666 *reject_reason = SAMR_REJECT_IN_HISTORY;
1668 return NT_STATUS_PASSWORD_RESTRICTION;
1670 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1671 if (reject_reason) {
1672 *reject_reason = SAMR_REJECT_IN_HISTORY;
1674 return NT_STATUS_PASSWORD_RESTRICTION;
1678 /* check the password history */
1679 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1680 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1682 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1683 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1684 if (reject_reason) {
1685 *reject_reason = SAMR_REJECT_IN_HISTORY;
1687 return NT_STATUS_PASSWORD_RESTRICTION;
1690 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1691 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1692 if (reject_reason) {
1693 *reject_reason = SAMR_REJECT_IN_HISTORY;
1695 return NT_STATUS_PASSWORD_RESTRICTION;
1700 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1702 /* the password is acceptable. Start forming the new fields */
1704 /* if we know the cleartext, then only set it.
1705 * Modules in ldb will set all the appropriate
1707 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1708 "sambaPassword", new_pass));
1710 /* We don't have the cleartext, so delete the old one
1711 * and set what we have of the hashes */
1712 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1715 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1717 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1721 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1723 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1727 return NT_STATUS_OK;
1732 set the user password using plaintext, obeying any user or domain
1733 password restrictions
1735 This wrapper function takes a SID as input, rather than a user DN,
1736 and actually performs the password change
1739 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1740 const struct dom_sid *user_sid,
1741 const char *new_pass,
1742 struct samr_Password *lmNewHash,
1743 struct samr_Password *ntNewHash,
1745 enum samr_RejectReason *reject_reason,
1746 struct samr_DomInfo1 **_dominfo)
1749 struct ldb_dn *user_dn;
1750 struct ldb_message *msg;
1753 ret = ldb_transaction_start(ctx);
1755 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1756 return NT_STATUS_TRANSACTION_ABORTED;
1759 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1760 "(&(objectSid=%s)(objectClass=user))",
1761 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1763 ldb_transaction_cancel(ctx);
1764 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1765 dom_sid_string(mem_ctx, user_sid)));
1766 return NT_STATUS_NO_SUCH_USER;
1769 msg = ldb_msg_new(mem_ctx);
1771 ldb_transaction_cancel(ctx);
1772 return NT_STATUS_NO_MEMORY;
1775 msg->dn = ldb_dn_copy(msg, user_dn);
1777 ldb_transaction_cancel(ctx);
1778 return NT_STATUS_NO_MEMORY;
1781 nt_status = samdb_set_password(ctx, mem_ctx,
1784 lmNewHash, ntNewHash,
1785 user_change, /* This is a password set, not change */
1786 reject_reason, _dominfo);
1787 if (!NT_STATUS_IS_OK(nt_status)) {
1788 ldb_transaction_cancel(ctx);
1792 /* modify the samdb record */
1793 ret = samdb_replace(ctx, mem_ctx, msg);
1795 ldb_transaction_cancel(ctx);
1796 return NT_STATUS_ACCESS_DENIED;
1799 ret = ldb_transaction_commit(ctx);
1801 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1802 ldb_dn_get_linearized(msg->dn),
1803 ldb_errstring(ctx)));
1804 return NT_STATUS_TRANSACTION_ABORTED;
1806 return NT_STATUS_OK;
1809 /****************************************************************************
1810 Create the SID list for this user.
1811 ****************************************************************************/
1812 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1813 struct dom_sid *user_sid,
1814 struct dom_sid *group_sid,
1816 struct dom_sid **groupSIDs,
1817 BOOL is_authenticated,
1818 struct security_token **token)
1820 struct security_token *ptoken;
1824 ptoken = security_token_initialise(mem_ctx);
1825 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1827 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1828 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1830 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1831 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1832 ptoken->privilege_mask = 0;
1834 ptoken->sids[0] = ptoken->user_sid;
1835 ptoken->sids[1] = ptoken->group_sid;
1838 * Finally add the "standard" SIDs.
1839 * The only difference between guest and "anonymous"
1840 * is the addition of Authenticated_Users.
1842 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1843 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1844 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1845 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1846 ptoken->num_sids = 4;
1848 if (is_authenticated) {
1849 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1850 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1854 for (i = 0; i < n_groupSIDs; i++) {
1855 size_t check_sid_idx;
1856 for (check_sid_idx = 1;
1857 check_sid_idx < ptoken->num_sids;
1859 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1864 if (check_sid_idx == ptoken->num_sids) {
1865 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1869 /* setup the privilege mask for this token */
1870 status = samdb_privilege_setup(ptoken);
1871 if (!NT_STATUS_IS_OK(status)) {
1872 talloc_free(ptoken);
1876 security_token_debug(10, ptoken);
1880 return NT_STATUS_OK;
1884 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1885 struct dom_sid *sid, struct ldb_dn **ret_dn)
1887 struct ldb_message *msg;
1888 struct ldb_dn *basedn;
1892 sidstr = dom_sid_string(mem_ctx, sid);
1893 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1895 /* We might have to create a ForeignSecurityPrincipal, even if this user
1896 * is in our own domain */
1898 msg = ldb_msg_new(mem_ctx);
1900 return NT_STATUS_NO_MEMORY;
1903 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1904 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1905 * not work, this is wrong for the Builtin domain, there's no
1906 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1909 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1910 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1912 if (basedn == NULL) {
1913 DEBUG(0, ("Failed to find DN for "
1914 "ForeignSecurityPrincipal container\n"));
1915 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1918 /* add core elements to the ldb_message for the alias */
1919 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1920 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1921 return NT_STATUS_NO_MEMORY;
1923 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1925 "foreignSecurityPrincipal");
1927 /* create the alias */
1928 ret = samdb_add(sam_ctx, mem_ctx, msg);
1930 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1932 ldb_dn_get_linearized(msg->dn),
1933 ldb_errstring(sam_ctx)));
1934 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1937 return NT_STATUS_OK;
1942 Find the DN of a domain, assuming it to be a dotted.dns name
1945 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1948 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1949 const char *binary_encoded;
1950 const char **split_realm;
1957 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1959 talloc_free(tmp_ctx);
1962 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1963 for (i=0; split_realm[i]; i++) {
1964 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1965 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1966 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1967 binary_encoded, ldb_dn_get_linearized(dn)));
1968 talloc_free(tmp_ctx);
1972 if (!ldb_dn_validate(dn)) {
1973 DEBUG(2, ("Failed to validated DN %s\n",
1974 ldb_dn_get_linearized(dn)));
1980 Find the DN of a domain, be it the netbios or DNS name
1983 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1984 const char *domain_name)
1986 const char * const domain_ref_attrs[] = {
1989 const char * const domain_ref2_attrs[] = {
1992 struct ldb_result *res_domain_ref;
1993 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1994 /* find the domain's DN */
1995 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1997 samdb_partitions_dn(ldb, mem_ctx),
2000 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2002 if (ret_domain != 0) {
2006 if (res_domain_ref->count == 0) {
2007 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2009 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2012 "(objectclass=domain)");
2013 if (ret_domain != 0) {
2017 if (res_domain_ref->count == 1) {
2018 return res_domain_ref->msgs[0]->dn;
2023 if (res_domain_ref->count > 1) {
2024 DEBUG(0,("Found %d records matching domain [%s]\n",
2025 ret_domain, domain_name));
2029 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);