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;
392 v = ldb_msg_find_ldb_val(msg, attr);
396 sid = talloc(mem_ctx, struct dom_sid);
400 status = ndr_pull_struct_blob(v, sid, sid,
401 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
402 if (!NT_STATUS_IS_OK(status)) {
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;
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 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
427 (ndr_pull_flags_fn_t)ndr_pull_GUID);
428 talloc_free(mem_ctx);
429 if (!NT_STATUS_IS_OK(status)) {
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)
762 status = ndr_push_struct_blob(&v, mem_ctx, sid,
763 (ndr_push_flags_fn_t)ndr_push_dom_sid);
764 if (!NT_STATUS_IS_OK(status)) {
767 return ldb_msg_add_value(msg, attr_name, &v, NULL);
772 add a delete element operation to a message
774 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
775 const char *attr_name)
777 /* we use an empty replace rather than a delete, as it allows for
778 samdb_replace() to be used everywhere */
779 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
783 add a add attribute value to a message
785 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
786 const char *attr_name, const char *value)
788 struct ldb_message_element *el;
791 a = talloc_strdup(mem_ctx, attr_name);
794 v = talloc_strdup(mem_ctx, value);
797 ret = ldb_msg_add_string(msg, a, v);
800 el = ldb_msg_find_element(msg, a);
803 el->flags = LDB_FLAG_MOD_ADD;
808 add a delete attribute value to a message
810 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
811 const char *attr_name, const char *value)
813 struct ldb_message_element *el;
816 a = talloc_strdup(mem_ctx, attr_name);
819 v = talloc_strdup(mem_ctx, value);
822 ret = ldb_msg_add_string(msg, a, v);
825 el = ldb_msg_find_element(msg, a);
828 el->flags = LDB_FLAG_MOD_DELETE;
833 add a int element to a message
835 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
836 const char *attr_name, int v)
838 const char *s = talloc_asprintf(mem_ctx, "%d", v);
839 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
843 add a uint_t element to a message
845 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846 const char *attr_name, uint_t v)
848 const char *s = talloc_asprintf(mem_ctx, "%u", v);
849 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
853 add a (signed) int64_t element to a message
855 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
856 const char *attr_name, int64_t v)
858 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
859 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
863 add a uint64_t element to a message
865 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866 const char *attr_name, uint64_t v)
868 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
869 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
873 add a samr_Password element to a message
875 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876 const char *attr_name, struct samr_Password *hash)
879 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
884 return ldb_msg_add_value(msg, attr_name, &val, NULL);
888 add a samr_Password array to a message
890 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891 const char *attr_name, struct samr_Password *hashes, uint_t count)
895 val.data = talloc_array_size(mem_ctx, 16, count);
896 val.length = count*16;
900 for (i=0;i<count;i++) {
901 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
903 return ldb_msg_add_value(msg, attr_name, &val, NULL);
907 add a acct_flags element to a message
909 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
910 const char *attr_name, uint32_t v)
912 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
916 add a logon_hours element to a message
918 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
919 const char *attr_name, struct samr_LogonHours *hours)
922 val.length = hours->units_per_week / 8;
923 val.data = hours->bits;
924 return ldb_msg_add_value(msg, attr_name, &val, NULL);
928 add a general value element to a message
930 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
931 const char *attr_name, const struct ldb_val *val)
933 return ldb_msg_add_value(msg, attr_name, val, NULL);
937 sets a general value element to a message
939 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
940 const char *attr_name, const struct ldb_val *val)
942 struct ldb_message_element *el;
944 el = ldb_msg_find_element(msg, attr_name);
948 return ldb_msg_add_value(msg, attr_name, val, NULL);
952 set a string element in a message
954 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955 const char *attr_name, const char *str)
957 struct ldb_message_element *el;
959 el = ldb_msg_find_element(msg, attr_name);
963 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
969 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
971 return ldb_add(sam_ldb, msg);
977 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
979 return ldb_delete(sam_ldb, dn);
985 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
987 return ldb_modify(sam_ldb, msg);
991 replace elements in a record
993 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
997 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
998 for (i=0;i<msg->num_elements;i++) {
999 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1002 /* modify the samdb record */
1003 return samdb_modify(sam_ldb, mem_ctx, msg);
1007 return a default security descriptor
1009 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1011 struct security_descriptor *sd;
1013 sd = security_descriptor_initialise(mem_ctx);
1018 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1020 return ldb_get_default_basedn(sam_ctx);
1023 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1025 return ldb_get_config_basedn(sam_ctx);
1028 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1030 return ldb_get_schema_basedn(sam_ctx);
1033 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1035 return ldb_get_root_basedn(sam_ctx);
1038 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1040 struct ldb_dn *new_dn;
1042 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1043 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1044 talloc_free(new_dn);
1050 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1052 struct ldb_dn *new_dn;
1054 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1055 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1056 talloc_free(new_dn);
1063 work out the domain sid for the current open ldb
1065 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1067 TALLOC_CTX *tmp_ctx;
1068 struct dom_sid *domain_sid;
1070 /* see if we have a cached copy */
1071 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1076 tmp_ctx = talloc_new(ldb);
1077 if (tmp_ctx == NULL) {
1081 /* find the domain_sid */
1082 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1083 "objectSid", "objectClass=domainDNS");
1084 if (domain_sid == NULL) {
1088 /* cache the domain_sid in the ldb */
1089 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1093 talloc_steal(ldb, domain_sid);
1094 talloc_free(tmp_ctx);
1099 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1100 talloc_free(tmp_ctx);
1104 /* Obtain the short name of the flexible single master operator
1105 * (FSMO), such as the PDC Emulator */
1106 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1109 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1110 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1111 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1112 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1114 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1115 /* Ensure this matches the format. This gives us a
1116 * bit more confidence that a 'cn' value will be a
1121 return (char *)val->data;
1127 work out the ntds settings dn for the current open ldb
1129 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1131 TALLOC_CTX *tmp_ctx;
1132 const char *root_attrs[] = { "dsServiceName", NULL };
1134 struct ldb_result *root_res;
1135 struct ldb_dn *settings_dn;
1137 /* see if we have a cached copy */
1138 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1143 tmp_ctx = talloc_new(ldb);
1144 if (tmp_ctx == NULL) {
1149 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1151 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1152 ldb_errstring(ldb)));
1155 talloc_steal(tmp_ctx, root_res);
1157 if (root_res->count != 1) {
1161 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1163 /* cache the domain_sid in the ldb */
1164 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1168 talloc_steal(ldb, settings_dn);
1169 talloc_free(tmp_ctx);
1174 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1175 talloc_free(tmp_ctx);
1180 work out the ntds settings invocationId for the current open ldb
1182 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1184 TALLOC_CTX *tmp_ctx;
1185 const char *attrs[] = { "invocationId", NULL };
1187 struct ldb_result *res;
1188 struct GUID *invocation_id;
1190 /* see if we have a cached copy */
1191 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1192 if (invocation_id) {
1193 return invocation_id;
1196 tmp_ctx = talloc_new(ldb);
1197 if (tmp_ctx == NULL) {
1201 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1205 talloc_steal(tmp_ctx, res);
1207 if (res->count != 1) {
1211 invocation_id = talloc(tmp_ctx, struct GUID);
1212 if (!invocation_id) {
1216 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1218 /* cache the domain_sid in the ldb */
1219 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1223 talloc_steal(ldb, invocation_id);
1224 talloc_free(tmp_ctx);
1226 return invocation_id;
1229 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1230 talloc_free(tmp_ctx);
1234 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1236 TALLOC_CTX *tmp_ctx;
1237 struct GUID *invocation_id_new;
1238 struct GUID *invocation_id_old;
1240 /* see if we have a cached copy */
1241 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1242 "cache.invocation_id");
1244 tmp_ctx = talloc_new(ldb);
1245 if (tmp_ctx == NULL) {
1249 invocation_id_new = talloc(tmp_ctx, struct GUID);
1250 if (!invocation_id_new) {
1254 *invocation_id_new = *invocation_id_in;
1256 /* cache the domain_sid in the ldb */
1257 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1261 talloc_steal(ldb, invocation_id_new);
1262 talloc_free(tmp_ctx);
1263 talloc_free(invocation_id_old);
1268 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1269 talloc_free(tmp_ctx);
1274 work out the ntds settings objectGUID for the current open ldb
1276 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1278 TALLOC_CTX *tmp_ctx;
1279 const char *attrs[] = { "objectGUID", NULL };
1281 struct ldb_result *res;
1282 struct GUID *ntds_guid;
1284 /* see if we have a cached copy */
1285 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1290 tmp_ctx = talloc_new(ldb);
1291 if (tmp_ctx == NULL) {
1295 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1299 talloc_steal(tmp_ctx, res);
1301 if (res->count != 1) {
1305 ntds_guid = talloc(tmp_ctx, struct GUID);
1310 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1312 /* cache the domain_sid in the ldb */
1313 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1317 talloc_steal(ldb, ntds_guid);
1318 talloc_free(tmp_ctx);
1323 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1324 talloc_free(tmp_ctx);
1328 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1330 TALLOC_CTX *tmp_ctx;
1331 struct GUID *ntds_guid_new;
1332 struct GUID *ntds_guid_old;
1334 /* see if we have a cached copy */
1335 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1337 tmp_ctx = talloc_new(ldb);
1338 if (tmp_ctx == NULL) {
1342 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1343 if (!ntds_guid_new) {
1347 *ntds_guid_new = *ntds_guid_in;
1349 /* cache the domain_sid in the ldb */
1350 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1354 talloc_steal(ldb, ntds_guid_new);
1355 talloc_free(tmp_ctx);
1356 talloc_free(ntds_guid_old);
1361 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1362 talloc_free(tmp_ctx);
1367 work out the server dn for the current open ldb
1369 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1371 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1375 work out the server dn for the current open ldb
1377 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1379 struct ldb_dn *server_dn;
1380 struct ldb_dn *server_site_dn;
1382 server_dn = samdb_server_dn(ldb, mem_ctx);
1383 if (!server_dn) return NULL;
1385 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1387 talloc_free(server_dn);
1388 return server_site_dn;
1392 work out if we are the PDC for the domain of the current open ldb
1394 BOOL samdb_is_pdc(struct ldb_context *ldb)
1396 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1398 struct ldb_result *dom_res;
1399 TALLOC_CTX *tmp_ctx;
1403 tmp_ctx = talloc_new(ldb);
1404 if (tmp_ctx == NULL) {
1405 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1409 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1411 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1412 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1413 ldb_errstring(ldb)));
1416 talloc_steal(tmp_ctx, dom_res);
1417 if (dom_res->count != 1) {
1421 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1423 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1429 talloc_free(tmp_ctx);
1434 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1435 talloc_free(tmp_ctx);
1440 /* Find a domain object in the parents of a particular DN. */
1441 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1443 TALLOC_CTX *local_ctx;
1444 struct ldb_dn *sdn = dn;
1445 struct ldb_result *res = NULL;
1447 const char *attrs[] = { NULL };
1449 local_ctx = talloc_new(mem_ctx);
1450 if (local_ctx == NULL) return NULL;
1452 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1453 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1454 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1455 if (ret == LDB_SUCCESS) {
1456 talloc_steal(local_ctx, res);
1457 if (res->count == 1) {
1463 if (ret != LDB_SUCCESS || res->count != 1) {
1464 talloc_free(local_ctx);
1468 talloc_steal(mem_ctx, sdn);
1469 talloc_free(local_ctx);
1475 check that a password is sufficiently complex
1477 static BOOL samdb_password_complexity_ok(const char *pass)
1479 return check_password_quality(pass);
1485 set the user password using plaintext, obeying any user or domain
1486 password restrictions
1488 note that this function doesn't actually store the result in the
1489 database, it just fills in the "mod" structure with ldb modify
1490 elements to setup the correct change when samdb_replace() is
1491 called. This allows the caller to combine the change with other
1492 changes (as is needed by some of the set user info levels)
1494 The caller should probably have a transaction wrapping this
1496 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1497 struct ldb_dn *user_dn,
1498 struct ldb_dn *domain_dn,
1499 struct ldb_message *mod,
1500 const char *new_pass,
1501 struct samr_Password *lmNewHash,
1502 struct samr_Password *ntNewHash,
1504 enum samr_RejectReason *reject_reason,
1505 struct samr_DomInfo1 **_dominfo)
1507 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1509 "dBCSPwd", "unicodePwd",
1511 "pwdLastSet", NULL };
1512 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1513 "maxPwdAge", "minPwdAge",
1514 "minPwdLength", NULL };
1517 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1518 uint_t userAccountControl;
1519 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1520 struct samr_Password local_lmNewHash, local_ntNewHash;
1521 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1522 struct dom_sid *domain_sid;
1523 struct ldb_message **res;
1526 time_t now = time(NULL);
1530 /* we need to know the time to compute password age */
1531 unix_to_nt_time(&now_nt, now);
1533 /* pull all the user parameters */
1534 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1536 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1538 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1539 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1540 "lmPwdHistory", &sambaLMPwdHistory);
1541 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1542 "ntPwdHistory", &sambaNTPwdHistory);
1543 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1544 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1545 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1547 /* Only non-trust accounts have restrictions (possibly this
1548 * test is the wrong way around, but I like to be restrictive
1550 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1551 |UF_WORKSTATION_TRUST_ACCOUNT
1552 |UF_SERVER_TRUST_ACCOUNT));
1555 /* pull the domain parameters */
1556 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1558 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1559 ldb_dn_get_linearized(domain_dn),
1560 ldb_dn_get_linearized(user_dn)));
1561 return NT_STATUS_NO_SUCH_DOMAIN;
1564 /* work out the domain sid, and pull the domain from there */
1565 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1566 if (domain_sid == NULL) {
1567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1570 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1572 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1574 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1575 dom_sid_string(mem_ctx, domain_sid),
1576 ldb_dn_get_linearized(user_dn)));
1577 return NT_STATUS_NO_SUCH_DOMAIN;
1581 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1582 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1583 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1584 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1587 struct samr_DomInfo1 *dominfo;
1588 /* on failure we need to fill in the reject reasons */
1589 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1590 if (dominfo == NULL) {
1591 return NT_STATUS_NO_MEMORY;
1593 dominfo->min_password_length = minPwdLength;
1594 dominfo->password_properties = pwdProperties;
1595 dominfo->password_history_length = pwdHistoryLength;
1596 dominfo->max_password_age = minPwdAge;
1597 dominfo->min_password_age = minPwdAge;
1598 *_dominfo = dominfo;
1601 if (restrictions && new_pass) {
1603 /* check the various password restrictions */
1604 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1605 if (reject_reason) {
1606 *reject_reason = SAMR_REJECT_TOO_SHORT;
1608 return NT_STATUS_PASSWORD_RESTRICTION;
1611 /* possibly check password complexity */
1612 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1613 !samdb_password_complexity_ok(new_pass)) {
1614 if (reject_reason) {
1615 *reject_reason = SAMR_REJECT_COMPLEXITY;
1617 return NT_STATUS_PASSWORD_RESTRICTION;
1620 /* compute the new nt and lm hashes */
1621 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1622 lmNewHash = &local_lmNewHash;
1624 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1625 /* If we can't convert this password to UCS2, then we should not accept it */
1626 if (reject_reason) {
1627 *reject_reason = SAMR_REJECT_OTHER;
1629 return NT_STATUS_PASSWORD_RESTRICTION;
1631 ntNewHash = &local_ntNewHash;
1635 /* are all password changes disallowed? */
1636 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1637 if (reject_reason) {
1638 *reject_reason = SAMR_REJECT_OTHER;
1640 return NT_STATUS_PASSWORD_RESTRICTION;
1643 /* can this user change password? */
1644 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1645 if (reject_reason) {
1646 *reject_reason = SAMR_REJECT_OTHER;
1648 return NT_STATUS_PASSWORD_RESTRICTION;
1651 /* yes, this is a minus. The ages are in negative 100nsec units! */
1652 if (pwdLastSet - minPwdAge > now_nt) {
1653 if (reject_reason) {
1654 *reject_reason = SAMR_REJECT_OTHER;
1656 return NT_STATUS_PASSWORD_RESTRICTION;
1659 /* check the immediately past password */
1660 if (pwdHistoryLength > 0) {
1661 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1662 if (reject_reason) {
1663 *reject_reason = SAMR_REJECT_IN_HISTORY;
1665 return NT_STATUS_PASSWORD_RESTRICTION;
1667 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1668 if (reject_reason) {
1669 *reject_reason = SAMR_REJECT_IN_HISTORY;
1671 return NT_STATUS_PASSWORD_RESTRICTION;
1675 /* check the password history */
1676 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1677 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1679 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1680 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1681 if (reject_reason) {
1682 *reject_reason = SAMR_REJECT_IN_HISTORY;
1684 return NT_STATUS_PASSWORD_RESTRICTION;
1687 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1688 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1689 if (reject_reason) {
1690 *reject_reason = SAMR_REJECT_IN_HISTORY;
1692 return NT_STATUS_PASSWORD_RESTRICTION;
1697 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1699 /* the password is acceptable. Start forming the new fields */
1701 /* if we know the cleartext, then only set it.
1702 * Modules in ldb will set all the appropriate
1704 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1705 "sambaPassword", new_pass));
1707 /* We don't have the cleartext, so delete the old one
1708 * and set what we have of the hashes */
1709 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1712 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1714 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1718 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1720 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1724 return NT_STATUS_OK;
1729 set the user password using plaintext, obeying any user or domain
1730 password restrictions
1732 This wrapper function takes a SID as input, rather than a user DN,
1733 and actually performs the password change
1736 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1737 const struct dom_sid *user_sid,
1738 const char *new_pass,
1739 struct samr_Password *lmNewHash,
1740 struct samr_Password *ntNewHash,
1742 enum samr_RejectReason *reject_reason,
1743 struct samr_DomInfo1 **_dominfo)
1746 struct ldb_dn *user_dn;
1747 struct ldb_message *msg;
1750 ret = ldb_transaction_start(ctx);
1752 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1753 return NT_STATUS_TRANSACTION_ABORTED;
1756 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1757 "(&(objectSid=%s)(objectClass=user))",
1758 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1760 ldb_transaction_cancel(ctx);
1761 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1762 dom_sid_string(mem_ctx, user_sid)));
1763 return NT_STATUS_NO_SUCH_USER;
1766 msg = ldb_msg_new(mem_ctx);
1768 ldb_transaction_cancel(ctx);
1769 return NT_STATUS_NO_MEMORY;
1772 msg->dn = ldb_dn_copy(msg, user_dn);
1774 ldb_transaction_cancel(ctx);
1775 return NT_STATUS_NO_MEMORY;
1778 nt_status = samdb_set_password(ctx, mem_ctx,
1781 lmNewHash, ntNewHash,
1782 user_change, /* This is a password set, not change */
1783 reject_reason, _dominfo);
1784 if (!NT_STATUS_IS_OK(nt_status)) {
1785 ldb_transaction_cancel(ctx);
1789 /* modify the samdb record */
1790 ret = samdb_replace(ctx, mem_ctx, msg);
1792 ldb_transaction_cancel(ctx);
1793 return NT_STATUS_ACCESS_DENIED;
1796 ret = ldb_transaction_commit(ctx);
1798 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1799 ldb_dn_get_linearized(msg->dn),
1800 ldb_errstring(ctx)));
1801 return NT_STATUS_TRANSACTION_ABORTED;
1803 return NT_STATUS_OK;
1806 /****************************************************************************
1807 Create the SID list for this user.
1808 ****************************************************************************/
1809 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1810 struct dom_sid *user_sid,
1811 struct dom_sid *group_sid,
1813 struct dom_sid **groupSIDs,
1814 BOOL is_authenticated,
1815 struct security_token **token)
1817 struct security_token *ptoken;
1821 ptoken = security_token_initialise(mem_ctx);
1822 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1824 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1825 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1827 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1828 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1829 ptoken->privilege_mask = 0;
1831 ptoken->sids[0] = ptoken->user_sid;
1832 ptoken->sids[1] = ptoken->group_sid;
1835 * Finally add the "standard" SIDs.
1836 * The only difference between guest and "anonymous"
1837 * is the addition of Authenticated_Users.
1839 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1840 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1841 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1842 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1843 ptoken->num_sids = 4;
1845 if (is_authenticated) {
1846 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1847 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1851 for (i = 0; i < n_groupSIDs; i++) {
1852 size_t check_sid_idx;
1853 for (check_sid_idx = 1;
1854 check_sid_idx < ptoken->num_sids;
1856 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1861 if (check_sid_idx == ptoken->num_sids) {
1862 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1866 /* setup the privilege mask for this token */
1867 status = samdb_privilege_setup(ptoken);
1868 if (!NT_STATUS_IS_OK(status)) {
1869 talloc_free(ptoken);
1873 security_token_debug(10, ptoken);
1877 return NT_STATUS_OK;
1881 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1882 struct dom_sid *sid, struct ldb_dn **ret_dn)
1884 struct ldb_message *msg;
1885 struct ldb_dn *basedn;
1889 sidstr = dom_sid_string(mem_ctx, sid);
1890 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1892 /* We might have to create a ForeignSecurityPrincipal, even if this user
1893 * is in our own domain */
1895 msg = ldb_msg_new(mem_ctx);
1897 return NT_STATUS_NO_MEMORY;
1900 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1901 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1902 * not work, this is wrong for the Builtin domain, there's no
1903 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1906 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1907 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1909 if (basedn == NULL) {
1910 DEBUG(0, ("Failed to find DN for "
1911 "ForeignSecurityPrincipal container\n"));
1912 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1915 /* add core elements to the ldb_message for the alias */
1916 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1917 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1918 return NT_STATUS_NO_MEMORY;
1920 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1922 "foreignSecurityPrincipal");
1924 /* create the alias */
1925 ret = samdb_add(sam_ctx, mem_ctx, msg);
1927 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1929 ldb_dn_get_linearized(msg->dn),
1930 ldb_errstring(sam_ctx)));
1931 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1934 return NT_STATUS_OK;
1939 Find the DN of a domain, assuming it to be a dotted.dns name
1942 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1945 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1946 const char *binary_encoded;
1947 const char **split_realm;
1954 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1956 talloc_free(tmp_ctx);
1959 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1960 for (i=0; split_realm[i]; i++) {
1961 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1962 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1963 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1964 binary_encoded, ldb_dn_get_linearized(dn)));
1965 talloc_free(tmp_ctx);
1969 if (!ldb_dn_validate(dn)) {
1970 DEBUG(2, ("Failed to validated DN %s\n",
1971 ldb_dn_get_linearized(dn)));
1977 Find the DN of a domain, be it the netbios or DNS name
1980 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1981 const char *domain_name)
1983 const char * const domain_ref_attrs[] = {
1986 const char * const domain_ref2_attrs[] = {
1989 struct ldb_result *res_domain_ref;
1990 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1991 /* find the domain's DN */
1992 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1994 samdb_partitions_dn(ldb, mem_ctx),
1997 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1999 if (ret_domain != 0) {
2003 if (res_domain_ref->count == 0) {
2004 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2006 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2009 "(objectclass=domain)");
2010 if (ret_domain != 0) {
2014 if (res_domain_ref->count == 1) {
2015 return res_domain_ref->msgs[0]->dn;
2020 if (res_domain_ref->count > 1) {
2021 DEBUG(0,("Found %d records matching domain [%s]\n",
2022 ret_domain, domain_name));
2026 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);