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(global_loadparm), 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);
644 for (i=0;i<el->num_values;i++) {
645 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
653 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
655 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
656 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
661 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
663 struct ldb_message_element *el;
665 el = ldb_msg_find_element(msg, name);
670 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
675 copy from a template record to a message
677 int samdb_copy_template(struct ldb_context *ldb,
678 struct ldb_message *msg, const char *name,
679 const char **errstring)
681 struct ldb_result *res;
682 struct ldb_message *t;
684 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
688 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
689 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
691 return LDB_ERR_OPERATIONS_ERROR;
694 /* pull the template record */
695 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
697 if (ret != LDB_SUCCESS) {
698 *errstring = talloc_steal(msg, ldb_errstring(ldb));
701 if (res->count != 1) {
702 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
706 return LDB_ERR_OPERATIONS_ERROR;
710 for (i = 0; i < t->num_elements; i++) {
711 struct ldb_message_element *el = &t->elements[i];
712 /* some elements should not be copied from the template */
713 if (ldb_attr_cmp(el->name, "cn") == 0 ||
714 ldb_attr_cmp(el->name, "name") == 0 ||
715 ldb_attr_cmp(el->name, "objectClass") == 0 ||
716 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
717 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
718 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
719 ldb_attr_cmp(el->name, "objectGUID") == 0) {
722 for (j = 0; j < el->num_values; j++) {
723 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
724 (char *)el->values[j].data);
726 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
740 add a string element to a message
742 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
743 const char *attr_name, const char *str)
745 char *s = talloc_strdup(mem_ctx, str);
746 char *a = talloc_strdup(mem_ctx, attr_name);
747 if (s == NULL || a == NULL) {
748 return LDB_ERR_OPERATIONS_ERROR;
750 return ldb_msg_add_string(msg, a, s);
754 add a dom_sid element to a message
756 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
757 const char *attr_name, struct dom_sid *sid)
761 status = ndr_push_struct_blob(&v, mem_ctx, sid,
762 (ndr_push_flags_fn_t)ndr_push_dom_sid);
763 if (!NT_STATUS_IS_OK(status)) {
766 return ldb_msg_add_value(msg, attr_name, &v, NULL);
771 add a delete element operation to a message
773 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
774 const char *attr_name)
776 /* we use an empty replace rather than a delete, as it allows for
777 samdb_replace() to be used everywhere */
778 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
782 add a add attribute value to a message
784 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name, const char *value)
787 struct ldb_message_element *el;
790 a = talloc_strdup(mem_ctx, attr_name);
793 v = talloc_strdup(mem_ctx, value);
796 ret = ldb_msg_add_string(msg, a, v);
799 el = ldb_msg_find_element(msg, a);
802 el->flags = LDB_FLAG_MOD_ADD;
807 add a delete attribute value to a message
809 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
810 const char *attr_name, const char *value)
812 struct ldb_message_element *el;
815 a = talloc_strdup(mem_ctx, attr_name);
818 v = talloc_strdup(mem_ctx, value);
821 ret = ldb_msg_add_string(msg, a, v);
824 el = ldb_msg_find_element(msg, a);
827 el->flags = LDB_FLAG_MOD_DELETE;
832 add a int element to a message
834 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
835 const char *attr_name, int v)
837 const char *s = talloc_asprintf(mem_ctx, "%d", v);
838 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
842 add a uint_t element to a message
844 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
845 const char *attr_name, uint_t v)
847 const char *s = talloc_asprintf(mem_ctx, "%u", v);
848 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
852 add a (signed) int64_t element to a message
854 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
855 const char *attr_name, int64_t v)
857 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
858 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
862 add a uint64_t element to a message
864 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
865 const char *attr_name, uint64_t v)
867 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
868 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
872 add a samr_Password element to a message
874 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
875 const char *attr_name, struct samr_Password *hash)
878 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
883 return ldb_msg_add_value(msg, attr_name, &val, NULL);
887 add a samr_Password array to a message
889 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
890 const char *attr_name, struct samr_Password *hashes, uint_t count)
894 val.data = talloc_array_size(mem_ctx, 16, count);
895 val.length = count*16;
899 for (i=0;i<count;i++) {
900 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
902 return ldb_msg_add_value(msg, attr_name, &val, NULL);
906 add a acct_flags element to a message
908 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
909 const char *attr_name, uint32_t v)
911 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
915 add a logon_hours element to a message
917 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
918 const char *attr_name, struct samr_LogonHours *hours)
921 val.length = hours->units_per_week / 8;
922 val.data = hours->bits;
923 return ldb_msg_add_value(msg, attr_name, &val, NULL);
927 add a general value element to a message
929 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
930 const char *attr_name, const struct ldb_val *val)
932 return ldb_msg_add_value(msg, attr_name, val, NULL);
936 sets a general value element to a message
938 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939 const char *attr_name, const struct ldb_val *val)
941 struct ldb_message_element *el;
943 el = ldb_msg_find_element(msg, attr_name);
947 return ldb_msg_add_value(msg, attr_name, val, NULL);
951 set a string element in a message
953 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
954 const char *attr_name, const char *str)
956 struct ldb_message_element *el;
958 el = ldb_msg_find_element(msg, attr_name);
962 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
968 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
970 return ldb_add(sam_ldb, msg);
976 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
978 return ldb_delete(sam_ldb, dn);
984 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
986 return ldb_modify(sam_ldb, msg);
990 replace elements in a record
992 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
996 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
997 for (i=0;i<msg->num_elements;i++) {
998 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1001 /* modify the samdb record */
1002 return samdb_modify(sam_ldb, mem_ctx, msg);
1006 return a default security descriptor
1008 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1010 struct security_descriptor *sd;
1012 sd = security_descriptor_initialise(mem_ctx);
1017 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1019 return ldb_get_default_basedn(sam_ctx);
1022 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1024 return ldb_get_config_basedn(sam_ctx);
1027 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1029 return ldb_get_schema_basedn(sam_ctx);
1032 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1034 return ldb_get_root_basedn(sam_ctx);
1037 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1039 struct ldb_dn *new_dn;
1041 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1042 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1043 talloc_free(new_dn);
1049 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1051 struct ldb_dn *new_dn;
1053 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1054 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1055 talloc_free(new_dn);
1062 work out the domain sid for the current open ldb
1064 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1066 TALLOC_CTX *tmp_ctx;
1067 struct dom_sid *domain_sid;
1069 /* see if we have a cached copy */
1070 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1075 tmp_ctx = talloc_new(ldb);
1076 if (tmp_ctx == NULL) {
1080 /* find the domain_sid */
1081 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1082 "objectSid", "objectClass=domainDNS");
1083 if (domain_sid == NULL) {
1087 /* cache the domain_sid in the ldb */
1088 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1092 talloc_steal(ldb, domain_sid);
1093 talloc_free(tmp_ctx);
1098 DEBUG(1,("Failed to find domain_sid for open 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, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1150 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1151 ldb_errstring(ldb)));
1154 talloc_steal(tmp_ctx, root_res);
1156 if (root_res->count != 1) {
1160 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1162 /* cache the domain_sid in the ldb */
1163 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1167 talloc_steal(ldb, settings_dn);
1168 talloc_free(tmp_ctx);
1173 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1174 talloc_free(tmp_ctx);
1179 work out the ntds settings invocationId for the current open ldb
1181 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1183 TALLOC_CTX *tmp_ctx;
1184 const char *attrs[] = { "invocationId", NULL };
1186 struct ldb_result *res;
1187 struct GUID *invocation_id;
1189 /* see if we have a cached copy */
1190 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1191 if (invocation_id) {
1192 return invocation_id;
1195 tmp_ctx = talloc_new(ldb);
1196 if (tmp_ctx == NULL) {
1200 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1204 talloc_steal(tmp_ctx, res);
1206 if (res->count != 1) {
1210 invocation_id = talloc(tmp_ctx, struct GUID);
1211 if (!invocation_id) {
1215 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1217 /* cache the domain_sid in the ldb */
1218 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1222 talloc_steal(ldb, invocation_id);
1223 talloc_free(tmp_ctx);
1225 return invocation_id;
1228 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1229 talloc_free(tmp_ctx);
1233 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1235 TALLOC_CTX *tmp_ctx;
1236 struct GUID *invocation_id_new;
1237 struct GUID *invocation_id_old;
1239 /* see if we have a cached copy */
1240 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1241 "cache.invocation_id");
1243 tmp_ctx = talloc_new(ldb);
1244 if (tmp_ctx == NULL) {
1248 invocation_id_new = talloc(tmp_ctx, struct GUID);
1249 if (!invocation_id_new) {
1253 *invocation_id_new = *invocation_id_in;
1255 /* cache the domain_sid in the ldb */
1256 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1260 talloc_steal(ldb, invocation_id_new);
1261 talloc_free(tmp_ctx);
1262 talloc_free(invocation_id_old);
1267 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1268 talloc_free(tmp_ctx);
1273 work out the ntds settings objectGUID for the current open ldb
1275 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1277 TALLOC_CTX *tmp_ctx;
1278 const char *attrs[] = { "objectGUID", NULL };
1280 struct ldb_result *res;
1281 struct GUID *ntds_guid;
1283 /* see if we have a cached copy */
1284 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1289 tmp_ctx = talloc_new(ldb);
1290 if (tmp_ctx == NULL) {
1294 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1298 talloc_steal(tmp_ctx, res);
1300 if (res->count != 1) {
1304 ntds_guid = talloc(tmp_ctx, struct GUID);
1309 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1311 /* cache the domain_sid in the ldb */
1312 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1316 talloc_steal(ldb, ntds_guid);
1317 talloc_free(tmp_ctx);
1322 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1323 talloc_free(tmp_ctx);
1327 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1329 TALLOC_CTX *tmp_ctx;
1330 struct GUID *ntds_guid_new;
1331 struct GUID *ntds_guid_old;
1333 /* see if we have a cached copy */
1334 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1336 tmp_ctx = talloc_new(ldb);
1337 if (tmp_ctx == NULL) {
1341 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1342 if (!ntds_guid_new) {
1346 *ntds_guid_new = *ntds_guid_in;
1348 /* cache the domain_sid in the ldb */
1349 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1353 talloc_steal(ldb, ntds_guid_new);
1354 talloc_free(tmp_ctx);
1355 talloc_free(ntds_guid_old);
1360 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1361 talloc_free(tmp_ctx);
1366 work out the server dn for the current open ldb
1368 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1370 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1374 work out the server dn for the current open ldb
1376 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1378 struct ldb_dn *server_dn;
1379 struct ldb_dn *server_site_dn;
1381 server_dn = samdb_server_dn(ldb, mem_ctx);
1382 if (!server_dn) return NULL;
1384 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1386 talloc_free(server_dn);
1387 return server_site_dn;
1391 work out if we are the PDC for the domain of the current open ldb
1393 BOOL samdb_is_pdc(struct ldb_context *ldb)
1395 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1397 struct ldb_result *dom_res;
1398 TALLOC_CTX *tmp_ctx;
1402 tmp_ctx = talloc_new(ldb);
1403 if (tmp_ctx == NULL) {
1404 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1408 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1410 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1411 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1412 ldb_errstring(ldb)));
1415 talloc_steal(tmp_ctx, dom_res);
1416 if (dom_res->count != 1) {
1420 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1422 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1428 talloc_free(tmp_ctx);
1433 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1434 talloc_free(tmp_ctx);
1439 /* Find a domain object in the parents of a particular DN. */
1440 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1442 TALLOC_CTX *local_ctx;
1443 struct ldb_dn *sdn = dn;
1444 struct ldb_result *res = NULL;
1446 const char *attrs[] = { NULL };
1448 local_ctx = talloc_new(mem_ctx);
1449 if (local_ctx == NULL) return NULL;
1451 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1452 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1453 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1454 if (ret == LDB_SUCCESS) {
1455 talloc_steal(local_ctx, res);
1456 if (res->count == 1) {
1462 if (ret != LDB_SUCCESS || res->count != 1) {
1463 talloc_free(local_ctx);
1467 talloc_steal(mem_ctx, sdn);
1468 talloc_free(local_ctx);
1474 check that a password is sufficiently complex
1476 static BOOL samdb_password_complexity_ok(const char *pass)
1478 return check_password_quality(pass);
1484 set the user password using plaintext, obeying any user or domain
1485 password restrictions
1487 note that this function doesn't actually store the result in the
1488 database, it just fills in the "mod" structure with ldb modify
1489 elements to setup the correct change when samdb_replace() is
1490 called. This allows the caller to combine the change with other
1491 changes (as is needed by some of the set user info levels)
1493 The caller should probably have a transaction wrapping this
1495 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1496 struct ldb_dn *user_dn,
1497 struct ldb_dn *domain_dn,
1498 struct ldb_message *mod,
1499 const char *new_pass,
1500 struct samr_Password *lmNewHash,
1501 struct samr_Password *ntNewHash,
1503 enum samr_RejectReason *reject_reason,
1504 struct samr_DomInfo1 **_dominfo)
1506 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1508 "dBCSPwd", "unicodePwd",
1510 "pwdLastSet", NULL };
1511 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1512 "maxPwdAge", "minPwdAge",
1513 "minPwdLength", NULL };
1516 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1517 uint_t userAccountControl;
1518 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1519 struct samr_Password local_lmNewHash, local_ntNewHash;
1520 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1521 struct dom_sid *domain_sid;
1522 struct ldb_message **res;
1525 time_t now = time(NULL);
1529 /* we need to know the time to compute password age */
1530 unix_to_nt_time(&now_nt, now);
1532 /* pull all the user parameters */
1533 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1535 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1537 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1538 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1539 "lmPwdHistory", &sambaLMPwdHistory);
1540 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1541 "ntPwdHistory", &sambaNTPwdHistory);
1542 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1543 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1544 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1546 /* Only non-trust accounts have restrictions (possibly this
1547 * test is the wrong way around, but I like to be restrictive
1549 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1550 |UF_WORKSTATION_TRUST_ACCOUNT
1551 |UF_SERVER_TRUST_ACCOUNT));
1554 /* pull the domain parameters */
1555 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1557 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1558 ldb_dn_get_linearized(domain_dn),
1559 ldb_dn_get_linearized(user_dn)));
1560 return NT_STATUS_NO_SUCH_DOMAIN;
1563 /* work out the domain sid, and pull the domain from there */
1564 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1565 if (domain_sid == NULL) {
1566 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1569 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1571 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1573 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1574 dom_sid_string(mem_ctx, domain_sid),
1575 ldb_dn_get_linearized(user_dn)));
1576 return NT_STATUS_NO_SUCH_DOMAIN;
1580 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1581 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1582 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1583 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1586 struct samr_DomInfo1 *dominfo;
1587 /* on failure we need to fill in the reject reasons */
1588 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1589 if (dominfo == NULL) {
1590 return NT_STATUS_NO_MEMORY;
1592 dominfo->min_password_length = minPwdLength;
1593 dominfo->password_properties = pwdProperties;
1594 dominfo->password_history_length = pwdHistoryLength;
1595 dominfo->max_password_age = minPwdAge;
1596 dominfo->min_password_age = minPwdAge;
1597 *_dominfo = dominfo;
1600 if (restrictions && new_pass) {
1602 /* check the various password restrictions */
1603 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1604 if (reject_reason) {
1605 *reject_reason = SAMR_REJECT_TOO_SHORT;
1607 return NT_STATUS_PASSWORD_RESTRICTION;
1610 /* possibly check password complexity */
1611 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1612 !samdb_password_complexity_ok(new_pass)) {
1613 if (reject_reason) {
1614 *reject_reason = SAMR_REJECT_COMPLEXITY;
1616 return NT_STATUS_PASSWORD_RESTRICTION;
1619 /* compute the new nt and lm hashes */
1620 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1621 lmNewHash = &local_lmNewHash;
1623 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1624 /* If we can't convert this password to UCS2, then we should not accept it */
1625 if (reject_reason) {
1626 *reject_reason = SAMR_REJECT_OTHER;
1628 return NT_STATUS_PASSWORD_RESTRICTION;
1630 ntNewHash = &local_ntNewHash;
1634 /* are all password changes disallowed? */
1635 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1636 if (reject_reason) {
1637 *reject_reason = SAMR_REJECT_OTHER;
1639 return NT_STATUS_PASSWORD_RESTRICTION;
1642 /* can this user change password? */
1643 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1644 if (reject_reason) {
1645 *reject_reason = SAMR_REJECT_OTHER;
1647 return NT_STATUS_PASSWORD_RESTRICTION;
1650 /* yes, this is a minus. The ages are in negative 100nsec units! */
1651 if (pwdLastSet - minPwdAge > now_nt) {
1652 if (reject_reason) {
1653 *reject_reason = SAMR_REJECT_OTHER;
1655 return NT_STATUS_PASSWORD_RESTRICTION;
1658 /* check the immediately past password */
1659 if (pwdHistoryLength > 0) {
1660 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1661 if (reject_reason) {
1662 *reject_reason = SAMR_REJECT_IN_HISTORY;
1664 return NT_STATUS_PASSWORD_RESTRICTION;
1666 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1667 if (reject_reason) {
1668 *reject_reason = SAMR_REJECT_IN_HISTORY;
1670 return NT_STATUS_PASSWORD_RESTRICTION;
1674 /* check the password history */
1675 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1676 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1678 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1679 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1680 if (reject_reason) {
1681 *reject_reason = SAMR_REJECT_IN_HISTORY;
1683 return NT_STATUS_PASSWORD_RESTRICTION;
1686 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1687 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1688 if (reject_reason) {
1689 *reject_reason = SAMR_REJECT_IN_HISTORY;
1691 return NT_STATUS_PASSWORD_RESTRICTION;
1696 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1698 /* the password is acceptable. Start forming the new fields */
1700 /* if we know the cleartext, then only set it.
1701 * Modules in ldb will set all the appropriate
1703 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1704 "sambaPassword", new_pass));
1706 /* We don't have the cleartext, so delete the old one
1707 * and set what we have of the hashes */
1708 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1711 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1713 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1717 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1719 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1723 return NT_STATUS_OK;
1728 set the user password using plaintext, obeying any user or domain
1729 password restrictions
1731 This wrapper function takes a SID as input, rather than a user DN,
1732 and actually performs the password change
1735 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1736 const struct dom_sid *user_sid,
1737 const char *new_pass,
1738 struct samr_Password *lmNewHash,
1739 struct samr_Password *ntNewHash,
1741 enum samr_RejectReason *reject_reason,
1742 struct samr_DomInfo1 **_dominfo)
1745 struct ldb_dn *user_dn;
1746 struct ldb_message *msg;
1749 ret = ldb_transaction_start(ctx);
1751 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1752 return NT_STATUS_TRANSACTION_ABORTED;
1755 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1756 "(&(objectSid=%s)(objectClass=user))",
1757 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1759 ldb_transaction_cancel(ctx);
1760 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1761 dom_sid_string(mem_ctx, user_sid)));
1762 return NT_STATUS_NO_SUCH_USER;
1765 msg = ldb_msg_new(mem_ctx);
1767 ldb_transaction_cancel(ctx);
1768 return NT_STATUS_NO_MEMORY;
1771 msg->dn = ldb_dn_copy(msg, user_dn);
1773 ldb_transaction_cancel(ctx);
1774 return NT_STATUS_NO_MEMORY;
1777 nt_status = samdb_set_password(ctx, mem_ctx,
1780 lmNewHash, ntNewHash,
1781 user_change, /* This is a password set, not change */
1782 reject_reason, _dominfo);
1783 if (!NT_STATUS_IS_OK(nt_status)) {
1784 ldb_transaction_cancel(ctx);
1788 /* modify the samdb record */
1789 ret = samdb_replace(ctx, mem_ctx, msg);
1791 ldb_transaction_cancel(ctx);
1792 return NT_STATUS_ACCESS_DENIED;
1795 ret = ldb_transaction_commit(ctx);
1797 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1798 ldb_dn_get_linearized(msg->dn),
1799 ldb_errstring(ctx)));
1800 return NT_STATUS_TRANSACTION_ABORTED;
1802 return NT_STATUS_OK;
1805 /****************************************************************************
1806 Create the SID list for this user.
1807 ****************************************************************************/
1808 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1809 struct dom_sid *user_sid,
1810 struct dom_sid *group_sid,
1812 struct dom_sid **groupSIDs,
1813 BOOL is_authenticated,
1814 struct security_token **token)
1816 struct security_token *ptoken;
1820 ptoken = security_token_initialise(mem_ctx);
1821 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1823 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1824 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1826 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1827 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1828 ptoken->privilege_mask = 0;
1830 ptoken->sids[0] = ptoken->user_sid;
1831 ptoken->sids[1] = ptoken->group_sid;
1834 * Finally add the "standard" SIDs.
1835 * The only difference between guest and "anonymous"
1836 * is the addition of Authenticated_Users.
1838 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1839 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1840 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1841 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1842 ptoken->num_sids = 4;
1844 if (is_authenticated) {
1845 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1846 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1850 for (i = 0; i < n_groupSIDs; i++) {
1851 size_t check_sid_idx;
1852 for (check_sid_idx = 1;
1853 check_sid_idx < ptoken->num_sids;
1855 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1860 if (check_sid_idx == ptoken->num_sids) {
1861 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1865 /* setup the privilege mask for this token */
1866 status = samdb_privilege_setup(ptoken);
1867 if (!NT_STATUS_IS_OK(status)) {
1868 talloc_free(ptoken);
1872 security_token_debug(10, ptoken);
1876 return NT_STATUS_OK;
1880 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1881 struct dom_sid *sid, struct ldb_dn **ret_dn)
1883 struct ldb_message *msg;
1884 struct ldb_dn *basedn;
1888 sidstr = dom_sid_string(mem_ctx, sid);
1889 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1891 /* We might have to create a ForeignSecurityPrincipal, even if this user
1892 * is in our own domain */
1894 msg = ldb_msg_new(mem_ctx);
1896 return NT_STATUS_NO_MEMORY;
1899 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1900 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1901 * not work, this is wrong for the Builtin domain, there's no
1902 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1905 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1906 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1908 if (basedn == NULL) {
1909 DEBUG(0, ("Failed to find DN for "
1910 "ForeignSecurityPrincipal container\n"));
1911 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1914 /* add core elements to the ldb_message for the alias */
1915 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1916 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1917 return NT_STATUS_NO_MEMORY;
1919 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1921 "foreignSecurityPrincipal");
1923 /* create the alias */
1924 ret = samdb_add(sam_ctx, mem_ctx, msg);
1926 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1928 ldb_dn_get_linearized(msg->dn),
1929 ldb_errstring(sam_ctx)));
1930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1933 return NT_STATUS_OK;
1938 Find the DN of a domain, assuming it to be a dotted.dns name
1941 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1944 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1945 const char *binary_encoded;
1946 const char **split_realm;
1953 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1955 talloc_free(tmp_ctx);
1958 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1959 for (i=0; split_realm[i]; i++) {
1960 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1961 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1962 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1963 binary_encoded, ldb_dn_get_linearized(dn)));
1964 talloc_free(tmp_ctx);
1968 if (!ldb_dn_validate(dn)) {
1969 DEBUG(2, ("Failed to validated DN %s\n",
1970 ldb_dn_get_linearized(dn)));
1976 Find the DN of a domain, be it the netbios or DNS name
1979 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1980 const char *domain_name)
1982 const char * const domain_ref_attrs[] = {
1985 const char * const domain_ref2_attrs[] = {
1988 struct ldb_result *res_domain_ref;
1989 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1990 /* find the domain's DN */
1991 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1993 samdb_partitions_dn(ldb, mem_ctx),
1996 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1998 if (ret_domain != 0) {
2002 if (res_domain_ref->count == 0) {
2003 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2005 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2008 "(objectclass=domain)");
2009 if (ret_domain != 0) {
2013 if (res_domain_ref->count == 1) {
2014 return res_domain_ref->msgs[0]->dn;
2019 if (res_domain_ref->count > 1) {
2020 DEBUG(0,("Found %d records matching domain [%s]\n",
2021 ret_domain, domain_name));
2025 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);