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, global_loadparm,
49 lp_sam_url(global_loadparm), session_info,
54 dsdb_make_schema_global(ldb);
59 search the sam for the specified attributes in a specific domain, filter on
60 objectSid being in domain_sid.
62 int samdb_search_domain(struct ldb_context *sam_ldb,
64 struct ldb_dn *basedn,
65 struct ldb_message ***res,
66 const char * const *attrs,
67 const struct dom_sid *domain_sid,
68 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
74 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
75 res, attrs, format, ap);
81 struct dom_sid *entry_sid;
83 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
85 if ((entry_sid == NULL) ||
86 (!dom_sid_in_domain(domain_sid, entry_sid))) {
87 /* Delete that entry from the result set */
88 (*res)[i] = (*res)[count-1];
90 talloc_free(entry_sid);
93 talloc_free(entry_sid);
101 search the sam for a single string attribute in exactly 1 record
103 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
105 struct ldb_dn *basedn,
106 const char *attr_name,
107 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
110 const char *attrs[2] = { NULL, NULL };
111 struct ldb_message **res = NULL;
113 attrs[0] = attr_name;
115 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
117 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
118 attr_name, format, count));
125 return samdb_result_string(res[0], attr_name, NULL);
130 search the sam for a single string attribute in exactly 1 record
132 const char *samdb_search_string(struct ldb_context *sam_ldb,
134 struct ldb_dn *basedn,
135 const char *attr_name,
136 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
141 va_start(ap, format);
142 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
148 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
150 struct ldb_dn *basedn,
151 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
155 struct ldb_message **res = NULL;
158 va_start(ap, format);
159 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
162 if (count != 1) return NULL;
164 ret = talloc_steal(mem_ctx, res[0]->dn);
171 search the sam for a dom_sid attribute in exactly 1 record
173 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
175 struct ldb_dn *basedn,
176 const char *attr_name,
177 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
181 struct ldb_message **res;
182 const char *attrs[2] = { NULL, NULL };
185 attrs[0] = attr_name;
187 va_start(ap, format);
188 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
191 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
192 attr_name, format, count));
198 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
204 return the count of the number of records in the sam matching the query
206 int samdb_search_count(struct ldb_context *sam_ldb,
208 struct ldb_dn *basedn,
209 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
212 struct ldb_message **res;
213 const char * const attrs[] = { NULL };
216 va_start(ap, format);
217 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
225 search the sam for a single integer attribute in exactly 1 record
227 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
229 uint_t default_value,
230 struct ldb_dn *basedn,
231 const char *attr_name,
232 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
236 struct ldb_message **res;
237 const char *attrs[2] = { NULL, NULL };
239 attrs[0] = attr_name;
241 va_start(ap, format);
242 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
246 return default_value;
249 return samdb_result_uint(res[0], attr_name, default_value);
253 search the sam for a single signed 64 bit integer attribute in exactly 1 record
255 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
257 int64_t default_value,
258 struct ldb_dn *basedn,
259 const char *attr_name,
260 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
264 struct ldb_message **res;
265 const char *attrs[2] = { NULL, NULL };
267 attrs[0] = attr_name;
269 va_start(ap, format);
270 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
274 return default_value;
277 return samdb_result_int64(res[0], attr_name, default_value);
281 search the sam for multipe records each giving a single string attribute
282 return the number of matches, or -1 on error
284 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
286 struct ldb_dn *basedn,
288 const char *attr_name,
289 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
293 const char *attrs[2] = { NULL, NULL };
294 struct ldb_message **res = NULL;
296 attrs[0] = attr_name;
298 va_start(ap, format);
299 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
306 /* make sure its single valued */
307 for (i=0;i<count;i++) {
308 if (res[i]->num_elements != 1) {
309 DEBUG(1,("samdb: search for %s %s not single valued\n",
316 *strs = talloc_array(mem_ctx, const char *, count+1);
322 for (i=0;i<count;i++) {
323 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
325 (*strs)[count] = NULL;
331 pull a uint from a result set.
333 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
335 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
339 pull a (signed) int64 from a result set.
341 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
343 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
347 pull a string from a result set.
349 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
350 const char *default_value)
352 return ldb_msg_find_attr_as_string(msg, attr, default_value);
355 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
356 const char *attr, struct ldb_dn *default_value)
358 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
360 return default_value;
366 pull a rid from a objectSid in a result set.
368 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
369 const char *attr, uint32_t default_value)
374 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
376 return default_value;
378 rid = sid->sub_auths[sid->num_auths-1];
384 pull a dom_sid structure from a objectSid in a result set.
386 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
389 const struct ldb_val *v;
391 enum ndr_err_code ndr_err;
392 v = ldb_msg_find_ldb_val(msg, attr);
396 sid = talloc(mem_ctx, struct dom_sid);
400 ndr_err = ndr_pull_struct_blob(v, sid, sid,
401 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
402 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
410 pull a guid structure from a objectGUID in a result set.
412 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
414 const struct ldb_val *v;
415 enum ndr_err_code ndr_err;
421 v = ldb_msg_find_ldb_val(msg, attr);
424 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
425 if (!mem_ctx) return guid;
426 ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid,
427 (ndr_pull_flags_fn_t)ndr_pull_GUID);
428 talloc_free(mem_ctx);
429 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
437 pull a sid prefix from a objectSid in a result set.
438 this is used to find the domain sid for a user
440 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
443 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
444 if (!sid || sid->num_auths < 1) return NULL;
450 pull a NTTIME in a result set.
452 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
454 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
458 pull a uint64_t from a result set.
460 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
462 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
467 construct the allow_password_change field from the PwdLastSet attribute and the
468 domain password settings
470 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
472 struct ldb_dn *domain_dn,
473 struct ldb_message *msg,
476 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
479 if (attr_time == 0) {
483 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
485 /* yes, this is a -= not a += as minPwdAge is stored as the negative
486 of the number of 100-nano-seconds */
487 attr_time -= minPwdAge;
493 construct the force_password_change field from the PwdLastSet attribute and the
494 domain password settings
496 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
498 struct ldb_dn *domain_dn,
499 struct ldb_message *msg)
501 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
502 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
505 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
506 return 0x7FFFFFFFFFFFFFFFULL;
509 if (attr_time == 0) {
513 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
514 if (maxPwdAge == 0) {
517 attr_time -= maxPwdAge;
524 pull a samr_Password structutre from a result set.
526 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
528 struct samr_Password *hash = NULL;
529 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
530 if (val && (val->length >= sizeof(hash->hash))) {
531 hash = talloc(mem_ctx, struct samr_Password);
532 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
538 pull an array of samr_Password structutres from a result set.
540 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
541 const char *attr, struct samr_Password **hashes)
544 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
551 count = val->length / 16;
556 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
561 for (i=0;i<count;i++) {
562 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
568 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
569 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
571 struct samr_Password *lmPwdHash, *ntPwdHash;
574 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
577 } else if (num_nt > 1) {
578 return NT_STATUS_INTERNAL_DB_CORRUPTION;
580 *nt_pwd = &ntPwdHash[0];
585 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
588 } else if (num_lm > 1) {
589 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591 *lm_pwd = &lmPwdHash[0];
598 pull a samr_LogonHours structutre from a result set.
600 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
602 struct samr_LogonHours hours;
603 const int units_per_week = 168;
604 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
606 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
610 hours.units_per_week = units_per_week;
611 memset(hours.bits, 0xFF, units_per_week);
613 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
619 pull a set of account_flags from a result set.
621 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
623 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
624 return samdb_uf2acb(userAccountControl);
628 /* Find an attribute, with a particular value */
630 /* The current callers of this function expect a very specific
631 * behaviour: In particular, objectClass subclass equivilance is not
632 * wanted. This means that we should not lookup the schema for the
633 * comparison function */
634 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
635 const struct ldb_message *msg,
636 const char *name, const char *value)
639 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
645 for (i=0;i<el->num_values;i++) {
646 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
654 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
656 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
657 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
662 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
664 struct ldb_message_element *el;
666 el = ldb_msg_find_element(msg, name);
671 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
676 copy from a template record to a message
678 int samdb_copy_template(struct ldb_context *ldb,
679 struct ldb_message *msg, const char *name,
680 const char **errstring)
682 struct ldb_result *res;
683 struct ldb_message *t;
685 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
689 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
690 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
692 return LDB_ERR_OPERATIONS_ERROR;
695 /* pull the template record */
696 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
698 if (ret != LDB_SUCCESS) {
699 *errstring = talloc_steal(msg, ldb_errstring(ldb));
702 if (res->count != 1) {
703 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
707 return LDB_ERR_OPERATIONS_ERROR;
711 for (i = 0; i < t->num_elements; i++) {
712 struct ldb_message_element *el = &t->elements[i];
713 /* some elements should not be copied from the template */
714 if (ldb_attr_cmp(el->name, "cn") == 0 ||
715 ldb_attr_cmp(el->name, "name") == 0 ||
716 ldb_attr_cmp(el->name, "objectClass") == 0 ||
717 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
718 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
719 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
720 ldb_attr_cmp(el->name, "objectGUID") == 0) {
723 for (j = 0; j < el->num_values; j++) {
724 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
725 (char *)el->values[j].data);
727 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
741 add a string element to a message
743 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
744 const char *attr_name, const char *str)
746 char *s = talloc_strdup(mem_ctx, str);
747 char *a = talloc_strdup(mem_ctx, attr_name);
748 if (s == NULL || a == NULL) {
749 return LDB_ERR_OPERATIONS_ERROR;
751 return ldb_msg_add_string(msg, a, s);
755 add a dom_sid element to a message
757 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758 const char *attr_name, struct dom_sid *sid)
761 enum ndr_err_code ndr_err;
763 ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid,
764 (ndr_push_flags_fn_t)ndr_push_dom_sid);
765 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
768 return ldb_msg_add_value(msg, attr_name, &v, NULL);
773 add a delete element operation to a message
775 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
776 const char *attr_name)
778 /* we use an empty replace rather than a delete, as it allows for
779 samdb_replace() to be used everywhere */
780 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
784 add a add attribute value to a message
786 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
787 const char *attr_name, const char *value)
789 struct ldb_message_element *el;
792 a = talloc_strdup(mem_ctx, attr_name);
795 v = talloc_strdup(mem_ctx, value);
798 ret = ldb_msg_add_string(msg, a, v);
801 el = ldb_msg_find_element(msg, a);
804 el->flags = LDB_FLAG_MOD_ADD;
809 add a delete attribute value to a message
811 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
812 const char *attr_name, const char *value)
814 struct ldb_message_element *el;
817 a = talloc_strdup(mem_ctx, attr_name);
820 v = talloc_strdup(mem_ctx, value);
823 ret = ldb_msg_add_string(msg, a, v);
826 el = ldb_msg_find_element(msg, a);
829 el->flags = LDB_FLAG_MOD_DELETE;
834 add a int element to a message
836 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
837 const char *attr_name, int v)
839 const char *s = talloc_asprintf(mem_ctx, "%d", v);
840 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
844 add a uint_t element to a message
846 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
847 const char *attr_name, uint_t v)
849 const char *s = talloc_asprintf(mem_ctx, "%u", v);
850 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
854 add a (signed) int64_t element to a message
856 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
857 const char *attr_name, int64_t v)
859 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
860 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
864 add a uint64_t element to a message
866 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
867 const char *attr_name, uint64_t v)
869 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
870 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
874 add a samr_Password element to a message
876 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
877 const char *attr_name, struct samr_Password *hash)
880 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
885 return ldb_msg_add_value(msg, attr_name, &val, NULL);
889 add a samr_Password array to a message
891 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
892 const char *attr_name, struct samr_Password *hashes, uint_t count)
896 val.data = talloc_array_size(mem_ctx, 16, count);
897 val.length = count*16;
901 for (i=0;i<count;i++) {
902 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
904 return ldb_msg_add_value(msg, attr_name, &val, NULL);
908 add a acct_flags element to a message
910 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
911 const char *attr_name, uint32_t v)
913 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
917 add a logon_hours element to a message
919 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
920 const char *attr_name, struct samr_LogonHours *hours)
923 val.length = hours->units_per_week / 8;
924 val.data = hours->bits;
925 return ldb_msg_add_value(msg, attr_name, &val, NULL);
929 add a general value element to a message
931 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
932 const char *attr_name, const struct ldb_val *val)
934 return ldb_msg_add_value(msg, attr_name, val, NULL);
938 sets a general value element to a message
940 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
941 const char *attr_name, const struct ldb_val *val)
943 struct ldb_message_element *el;
945 el = ldb_msg_find_element(msg, attr_name);
949 return ldb_msg_add_value(msg, attr_name, val, NULL);
953 set a string element in a message
955 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
956 const char *attr_name, const char *str)
958 struct ldb_message_element *el;
960 el = ldb_msg_find_element(msg, attr_name);
964 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
970 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
972 return ldb_add(sam_ldb, msg);
978 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
980 return ldb_delete(sam_ldb, dn);
986 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
988 return ldb_modify(sam_ldb, msg);
992 replace elements in a record
994 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
998 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
999 for (i=0;i<msg->num_elements;i++) {
1000 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1003 /* modify the samdb record */
1004 return samdb_modify(sam_ldb, mem_ctx, msg);
1008 return a default security descriptor
1010 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1012 struct security_descriptor *sd;
1014 sd = security_descriptor_initialise(mem_ctx);
1019 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1021 return ldb_get_default_basedn(sam_ctx);
1024 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1026 return ldb_get_config_basedn(sam_ctx);
1029 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1031 return ldb_get_schema_basedn(sam_ctx);
1034 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1036 return ldb_get_root_basedn(sam_ctx);
1039 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1041 struct ldb_dn *new_dn;
1043 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1044 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1045 talloc_free(new_dn);
1051 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1053 struct ldb_dn *new_dn;
1055 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1056 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1057 talloc_free(new_dn);
1064 work out the domain sid for the current open ldb
1066 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1068 TALLOC_CTX *tmp_ctx;
1069 struct dom_sid *domain_sid;
1071 /* see if we have a cached copy */
1072 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1077 tmp_ctx = talloc_new(ldb);
1078 if (tmp_ctx == NULL) {
1082 /* find the domain_sid */
1083 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1084 "objectSid", "objectClass=domainDNS");
1085 if (domain_sid == NULL) {
1089 /* cache the domain_sid in the ldb */
1090 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1094 talloc_steal(ldb, domain_sid);
1095 talloc_free(tmp_ctx);
1100 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1101 talloc_free(tmp_ctx);
1105 /* Obtain the short name of the flexible single master operator
1106 * (FSMO), such as the PDC Emulator */
1107 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1110 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1111 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1112 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1113 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1115 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1116 /* Ensure this matches the format. This gives us a
1117 * bit more confidence that a 'cn' value will be a
1122 return (char *)val->data;
1128 work out the ntds settings dn for the current open ldb
1130 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1132 TALLOC_CTX *tmp_ctx;
1133 const char *root_attrs[] = { "dsServiceName", NULL };
1135 struct ldb_result *root_res;
1136 struct ldb_dn *settings_dn;
1138 /* see if we have a cached copy */
1139 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1144 tmp_ctx = talloc_new(ldb);
1145 if (tmp_ctx == NULL) {
1150 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1152 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1153 ldb_errstring(ldb)));
1156 talloc_steal(tmp_ctx, root_res);
1158 if (root_res->count != 1) {
1162 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1164 /* cache the domain_sid in the ldb */
1165 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1169 talloc_steal(ldb, settings_dn);
1170 talloc_free(tmp_ctx);
1175 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1176 talloc_free(tmp_ctx);
1181 work out the ntds settings invocationId for the current open ldb
1183 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1185 TALLOC_CTX *tmp_ctx;
1186 const char *attrs[] = { "invocationId", NULL };
1188 struct ldb_result *res;
1189 struct GUID *invocation_id;
1191 /* see if we have a cached copy */
1192 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1193 if (invocation_id) {
1194 return invocation_id;
1197 tmp_ctx = talloc_new(ldb);
1198 if (tmp_ctx == NULL) {
1202 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1206 talloc_steal(tmp_ctx, res);
1208 if (res->count != 1) {
1212 invocation_id = talloc(tmp_ctx, struct GUID);
1213 if (!invocation_id) {
1217 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1219 /* cache the domain_sid in the ldb */
1220 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1224 talloc_steal(ldb, invocation_id);
1225 talloc_free(tmp_ctx);
1227 return invocation_id;
1230 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1231 talloc_free(tmp_ctx);
1235 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1237 TALLOC_CTX *tmp_ctx;
1238 struct GUID *invocation_id_new;
1239 struct GUID *invocation_id_old;
1241 /* see if we have a cached copy */
1242 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1243 "cache.invocation_id");
1245 tmp_ctx = talloc_new(ldb);
1246 if (tmp_ctx == NULL) {
1250 invocation_id_new = talloc(tmp_ctx, struct GUID);
1251 if (!invocation_id_new) {
1255 *invocation_id_new = *invocation_id_in;
1257 /* cache the domain_sid in the ldb */
1258 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1262 talloc_steal(ldb, invocation_id_new);
1263 talloc_free(tmp_ctx);
1264 talloc_free(invocation_id_old);
1269 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1270 talloc_free(tmp_ctx);
1275 work out the ntds settings objectGUID for the current open ldb
1277 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1279 TALLOC_CTX *tmp_ctx;
1280 const char *attrs[] = { "objectGUID", NULL };
1282 struct ldb_result *res;
1283 struct GUID *ntds_guid;
1285 /* see if we have a cached copy */
1286 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1291 tmp_ctx = talloc_new(ldb);
1292 if (tmp_ctx == NULL) {
1296 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1300 talloc_steal(tmp_ctx, res);
1302 if (res->count != 1) {
1306 ntds_guid = talloc(tmp_ctx, struct GUID);
1311 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1313 /* cache the domain_sid in the ldb */
1314 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1318 talloc_steal(ldb, ntds_guid);
1319 talloc_free(tmp_ctx);
1324 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1325 talloc_free(tmp_ctx);
1329 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1331 TALLOC_CTX *tmp_ctx;
1332 struct GUID *ntds_guid_new;
1333 struct GUID *ntds_guid_old;
1335 /* see if we have a cached copy */
1336 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1338 tmp_ctx = talloc_new(ldb);
1339 if (tmp_ctx == NULL) {
1343 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1344 if (!ntds_guid_new) {
1348 *ntds_guid_new = *ntds_guid_in;
1350 /* cache the domain_sid in the ldb */
1351 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1355 talloc_steal(ldb, ntds_guid_new);
1356 talloc_free(tmp_ctx);
1357 talloc_free(ntds_guid_old);
1362 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1363 talloc_free(tmp_ctx);
1368 work out the server dn for the current open ldb
1370 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1372 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1376 work out the server dn for the current open ldb
1378 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1380 struct ldb_dn *server_dn;
1381 struct ldb_dn *server_site_dn;
1383 server_dn = samdb_server_dn(ldb, mem_ctx);
1384 if (!server_dn) return NULL;
1386 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1388 talloc_free(server_dn);
1389 return server_site_dn;
1393 work out if we are the PDC for the domain of the current open ldb
1395 bool samdb_is_pdc(struct ldb_context *ldb)
1397 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1399 struct ldb_result *dom_res;
1400 TALLOC_CTX *tmp_ctx;
1404 tmp_ctx = talloc_new(ldb);
1405 if (tmp_ctx == NULL) {
1406 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1410 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1412 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1413 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1414 ldb_errstring(ldb)));
1417 talloc_steal(tmp_ctx, dom_res);
1418 if (dom_res->count != 1) {
1422 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1424 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1430 talloc_free(tmp_ctx);
1435 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1436 talloc_free(tmp_ctx);
1441 /* Find a domain object in the parents of a particular DN. */
1442 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1444 TALLOC_CTX *local_ctx;
1445 struct ldb_dn *sdn = dn;
1446 struct ldb_result *res = NULL;
1448 const char *attrs[] = { NULL };
1450 local_ctx = talloc_new(mem_ctx);
1451 if (local_ctx == NULL) return NULL;
1453 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1454 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1455 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1456 if (ret == LDB_SUCCESS) {
1457 talloc_steal(local_ctx, res);
1458 if (res->count == 1) {
1464 if (ret != LDB_SUCCESS || res->count != 1) {
1465 talloc_free(local_ctx);
1469 talloc_steal(mem_ctx, sdn);
1470 talloc_free(local_ctx);
1476 check that a password is sufficiently complex
1478 static bool samdb_password_complexity_ok(const char *pass)
1480 return check_password_quality(pass);
1486 set the user password using plaintext, obeying any user or domain
1487 password restrictions
1489 note that this function doesn't actually store the result in the
1490 database, it just fills in the "mod" structure with ldb modify
1491 elements to setup the correct change when samdb_replace() is
1492 called. This allows the caller to combine the change with other
1493 changes (as is needed by some of the set user info levels)
1495 The caller should probably have a transaction wrapping this
1497 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1498 struct ldb_dn *user_dn,
1499 struct ldb_dn *domain_dn,
1500 struct ldb_message *mod,
1501 const char *new_pass,
1502 struct samr_Password *lmNewHash,
1503 struct samr_Password *ntNewHash,
1505 enum samr_RejectReason *reject_reason,
1506 struct samr_DomInfo1 **_dominfo)
1508 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1510 "dBCSPwd", "unicodePwd",
1512 "pwdLastSet", NULL };
1513 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1514 "maxPwdAge", "minPwdAge",
1515 "minPwdLength", NULL };
1518 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1519 uint_t userAccountControl;
1520 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1521 struct samr_Password local_lmNewHash, local_ntNewHash;
1522 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1523 struct dom_sid *domain_sid;
1524 struct ldb_message **res;
1527 time_t now = time(NULL);
1531 /* we need to know the time to compute password age */
1532 unix_to_nt_time(&now_nt, now);
1534 /* pull all the user parameters */
1535 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1537 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1539 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1540 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1541 "lmPwdHistory", &sambaLMPwdHistory);
1542 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1543 "ntPwdHistory", &sambaNTPwdHistory);
1544 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1545 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1546 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1548 /* Only non-trust accounts have restrictions (possibly this
1549 * test is the wrong way around, but I like to be restrictive
1551 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1552 |UF_WORKSTATION_TRUST_ACCOUNT
1553 |UF_SERVER_TRUST_ACCOUNT));
1556 /* pull the domain parameters */
1557 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1559 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1560 ldb_dn_get_linearized(domain_dn),
1561 ldb_dn_get_linearized(user_dn)));
1562 return NT_STATUS_NO_SUCH_DOMAIN;
1565 /* work out the domain sid, and pull the domain from there */
1566 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1567 if (domain_sid == NULL) {
1568 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1571 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1573 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1575 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1576 dom_sid_string(mem_ctx, domain_sid),
1577 ldb_dn_get_linearized(user_dn)));
1578 return NT_STATUS_NO_SUCH_DOMAIN;
1582 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1583 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1584 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1585 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1588 struct samr_DomInfo1 *dominfo;
1589 /* on failure we need to fill in the reject reasons */
1590 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1591 if (dominfo == NULL) {
1592 return NT_STATUS_NO_MEMORY;
1594 dominfo->min_password_length = minPwdLength;
1595 dominfo->password_properties = pwdProperties;
1596 dominfo->password_history_length = pwdHistoryLength;
1597 dominfo->max_password_age = minPwdAge;
1598 dominfo->min_password_age = minPwdAge;
1599 *_dominfo = dominfo;
1602 if (restrictions && new_pass) {
1604 /* check the various password restrictions */
1605 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1606 if (reject_reason) {
1607 *reject_reason = SAMR_REJECT_TOO_SHORT;
1609 return NT_STATUS_PASSWORD_RESTRICTION;
1612 /* possibly check password complexity */
1613 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1614 !samdb_password_complexity_ok(new_pass)) {
1615 if (reject_reason) {
1616 *reject_reason = SAMR_REJECT_COMPLEXITY;
1618 return NT_STATUS_PASSWORD_RESTRICTION;
1621 /* compute the new nt and lm hashes */
1622 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1623 lmNewHash = &local_lmNewHash;
1625 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1626 /* If we can't convert this password to UCS2, then we should not accept it */
1627 if (reject_reason) {
1628 *reject_reason = SAMR_REJECT_OTHER;
1630 return NT_STATUS_PASSWORD_RESTRICTION;
1632 ntNewHash = &local_ntNewHash;
1636 /* are all password changes disallowed? */
1637 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1638 if (reject_reason) {
1639 *reject_reason = SAMR_REJECT_OTHER;
1641 return NT_STATUS_PASSWORD_RESTRICTION;
1644 /* can this user change password? */
1645 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1646 if (reject_reason) {
1647 *reject_reason = SAMR_REJECT_OTHER;
1649 return NT_STATUS_PASSWORD_RESTRICTION;
1652 /* yes, this is a minus. The ages are in negative 100nsec units! */
1653 if (pwdLastSet - minPwdAge > now_nt) {
1654 if (reject_reason) {
1655 *reject_reason = SAMR_REJECT_OTHER;
1657 return NT_STATUS_PASSWORD_RESTRICTION;
1660 /* check the immediately past password */
1661 if (pwdHistoryLength > 0) {
1662 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1663 if (reject_reason) {
1664 *reject_reason = SAMR_REJECT_IN_HISTORY;
1666 return NT_STATUS_PASSWORD_RESTRICTION;
1668 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1669 if (reject_reason) {
1670 *reject_reason = SAMR_REJECT_IN_HISTORY;
1672 return NT_STATUS_PASSWORD_RESTRICTION;
1676 /* check the password history */
1677 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1678 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1680 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1681 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1682 if (reject_reason) {
1683 *reject_reason = SAMR_REJECT_IN_HISTORY;
1685 return NT_STATUS_PASSWORD_RESTRICTION;
1688 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1689 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1690 if (reject_reason) {
1691 *reject_reason = SAMR_REJECT_IN_HISTORY;
1693 return NT_STATUS_PASSWORD_RESTRICTION;
1698 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1700 /* the password is acceptable. Start forming the new fields */
1702 /* if we know the cleartext, then only set it.
1703 * Modules in ldb will set all the appropriate
1705 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1706 "sambaPassword", new_pass));
1708 /* We don't have the cleartext, so delete the old one
1709 * and set what we have of the hashes */
1710 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1713 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1715 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1719 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1721 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1725 return NT_STATUS_OK;
1730 set the user password using plaintext, obeying any user or domain
1731 password restrictions
1733 This wrapper function takes a SID as input, rather than a user DN,
1734 and actually performs the password change
1737 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1738 const struct dom_sid *user_sid,
1739 const char *new_pass,
1740 struct samr_Password *lmNewHash,
1741 struct samr_Password *ntNewHash,
1743 enum samr_RejectReason *reject_reason,
1744 struct samr_DomInfo1 **_dominfo)
1747 struct ldb_dn *user_dn;
1748 struct ldb_message *msg;
1751 ret = ldb_transaction_start(ctx);
1753 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1754 return NT_STATUS_TRANSACTION_ABORTED;
1757 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1758 "(&(objectSid=%s)(objectClass=user))",
1759 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1761 ldb_transaction_cancel(ctx);
1762 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1763 dom_sid_string(mem_ctx, user_sid)));
1764 return NT_STATUS_NO_SUCH_USER;
1767 msg = ldb_msg_new(mem_ctx);
1769 ldb_transaction_cancel(ctx);
1770 return NT_STATUS_NO_MEMORY;
1773 msg->dn = ldb_dn_copy(msg, user_dn);
1775 ldb_transaction_cancel(ctx);
1776 return NT_STATUS_NO_MEMORY;
1779 nt_status = samdb_set_password(ctx, mem_ctx,
1782 lmNewHash, ntNewHash,
1783 user_change, /* This is a password set, not change */
1784 reject_reason, _dominfo);
1785 if (!NT_STATUS_IS_OK(nt_status)) {
1786 ldb_transaction_cancel(ctx);
1790 /* modify the samdb record */
1791 ret = samdb_replace(ctx, mem_ctx, msg);
1793 ldb_transaction_cancel(ctx);
1794 return NT_STATUS_ACCESS_DENIED;
1797 ret = ldb_transaction_commit(ctx);
1799 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1800 ldb_dn_get_linearized(msg->dn),
1801 ldb_errstring(ctx)));
1802 return NT_STATUS_TRANSACTION_ABORTED;
1804 return NT_STATUS_OK;
1807 /****************************************************************************
1808 Create the SID list for this user.
1809 ****************************************************************************/
1810 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1811 struct dom_sid *user_sid,
1812 struct dom_sid *group_sid,
1814 struct dom_sid **groupSIDs,
1815 bool is_authenticated,
1816 struct security_token **token)
1818 struct security_token *ptoken;
1822 ptoken = security_token_initialise(mem_ctx);
1823 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1825 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1826 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1828 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1829 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1830 ptoken->privilege_mask = 0;
1832 ptoken->sids[0] = ptoken->user_sid;
1833 ptoken->sids[1] = ptoken->group_sid;
1836 * Finally add the "standard" SIDs.
1837 * The only difference between guest and "anonymous"
1838 * is the addition of Authenticated_Users.
1840 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1841 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1842 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1843 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1844 ptoken->num_sids = 4;
1846 if (is_authenticated) {
1847 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1848 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1852 for (i = 0; i < n_groupSIDs; i++) {
1853 size_t check_sid_idx;
1854 for (check_sid_idx = 1;
1855 check_sid_idx < ptoken->num_sids;
1857 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1862 if (check_sid_idx == ptoken->num_sids) {
1863 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1867 /* setup the privilege mask for this token */
1868 status = samdb_privilege_setup(ptoken);
1869 if (!NT_STATUS_IS_OK(status)) {
1870 talloc_free(ptoken);
1874 security_token_debug(10, ptoken);
1878 return NT_STATUS_OK;
1882 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1883 struct dom_sid *sid, struct ldb_dn **ret_dn)
1885 struct ldb_message *msg;
1886 struct ldb_dn *basedn;
1890 sidstr = dom_sid_string(mem_ctx, sid);
1891 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1893 /* We might have to create a ForeignSecurityPrincipal, even if this user
1894 * is in our own domain */
1896 msg = ldb_msg_new(mem_ctx);
1898 return NT_STATUS_NO_MEMORY;
1901 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1902 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1903 * not work, this is wrong for the Builtin domain, there's no
1904 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1907 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1908 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1910 if (basedn == NULL) {
1911 DEBUG(0, ("Failed to find DN for "
1912 "ForeignSecurityPrincipal container\n"));
1913 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1916 /* add core elements to the ldb_message for the alias */
1917 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1918 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1919 return NT_STATUS_NO_MEMORY;
1921 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1923 "foreignSecurityPrincipal");
1925 /* create the alias */
1926 ret = samdb_add(sam_ctx, mem_ctx, msg);
1928 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1930 ldb_dn_get_linearized(msg->dn),
1931 ldb_errstring(sam_ctx)));
1932 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1935 return NT_STATUS_OK;
1940 Find the DN of a domain, assuming it to be a dotted.dns name
1943 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1946 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1947 const char *binary_encoded;
1948 const char **split_realm;
1955 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1957 talloc_free(tmp_ctx);
1960 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1961 for (i=0; split_realm[i]; i++) {
1962 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1963 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1964 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1965 binary_encoded, ldb_dn_get_linearized(dn)));
1966 talloc_free(tmp_ctx);
1970 if (!ldb_dn_validate(dn)) {
1971 DEBUG(2, ("Failed to validated DN %s\n",
1972 ldb_dn_get_linearized(dn)));
1978 Find the DN of a domain, be it the netbios or DNS name
1981 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1982 const char *domain_name)
1984 const char * const domain_ref_attrs[] = {
1987 const char * const domain_ref2_attrs[] = {
1990 struct ldb_result *res_domain_ref;
1991 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1992 /* find the domain's DN */
1993 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1995 samdb_partitions_dn(ldb, mem_ctx),
1998 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2000 if (ret_domain != 0) {
2004 if (res_domain_ref->count == 0) {
2005 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2007 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2010 "(objectclass=domain)");
2011 if (ret_domain != 0) {
2015 if (res_domain_ref->count == 1) {
2016 return res_domain_ref->msgs[0]->dn;
2021 if (res_domain_ref->count > 1) {
2022 DEBUG(0,("Found %d records matching domain [%s]\n",
2023 ret_domain, domain_name));
2027 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);