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"
40 connect to the SAM database
41 return an opaque context pointer on success, or NULL on failure
43 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
44 struct auth_session_info *session_info)
46 struct ldb_context *ldb;
47 ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
52 dsdb_make_schema_global(ldb);
57 search the sam for the specified attributes in a specific domain, filter on
58 objectSid being in domain_sid.
60 int samdb_search_domain(struct ldb_context *sam_ldb,
62 struct ldb_dn *basedn,
63 struct ldb_message ***res,
64 const char * const *attrs,
65 const struct dom_sid *domain_sid,
66 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
72 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73 res, attrs, format, ap);
79 struct dom_sid *entry_sid;
81 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
83 if ((entry_sid == NULL) ||
84 (!dom_sid_in_domain(domain_sid, entry_sid))) {
85 /* Delete that entry from the result set */
86 (*res)[i] = (*res)[count-1];
88 talloc_free(entry_sid);
91 talloc_free(entry_sid);
99 search the sam for a single string attribute in exactly 1 record
101 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
103 struct ldb_dn *basedn,
104 const char *attr_name,
105 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
108 const char *attrs[2] = { NULL, NULL };
109 struct ldb_message **res = NULL;
111 attrs[0] = attr_name;
113 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
115 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
116 attr_name, format, count));
123 return samdb_result_string(res[0], attr_name, NULL);
128 search the sam for a single string attribute in exactly 1 record
130 const char *samdb_search_string(struct ldb_context *sam_ldb,
132 struct ldb_dn *basedn,
133 const char *attr_name,
134 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
139 va_start(ap, format);
140 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
148 struct ldb_dn *basedn,
149 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
153 struct ldb_message **res = NULL;
156 va_start(ap, format);
157 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
160 if (count != 1) return NULL;
162 ret = talloc_steal(mem_ctx, res[0]->dn);
169 search the sam for a dom_sid attribute in exactly 1 record
171 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
173 struct ldb_dn *basedn,
174 const char *attr_name,
175 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
179 struct ldb_message **res;
180 const char *attrs[2] = { NULL, NULL };
183 attrs[0] = attr_name;
185 va_start(ap, format);
186 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
189 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
190 attr_name, format, count));
196 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
202 return the count of the number of records in the sam matching the query
204 int samdb_search_count(struct ldb_context *sam_ldb,
206 struct ldb_dn *basedn,
207 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
210 struct ldb_message **res;
211 const char * const attrs[] = { NULL };
214 va_start(ap, format);
215 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
223 search the sam for a single integer attribute in exactly 1 record
225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
227 uint_t default_value,
228 struct ldb_dn *basedn,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
234 struct ldb_message **res;
235 const char *attrs[2] = { NULL, NULL };
237 attrs[0] = attr_name;
239 va_start(ap, format);
240 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
244 return default_value;
247 return samdb_result_uint(res[0], attr_name, default_value);
251 search the sam for a single signed 64 bit integer attribute in exactly 1 record
253 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
255 int64_t default_value,
256 struct ldb_dn *basedn,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
262 struct ldb_message **res;
263 const char *attrs[2] = { NULL, NULL };
265 attrs[0] = attr_name;
267 va_start(ap, format);
268 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
272 return default_value;
275 return samdb_result_int64(res[0], attr_name, default_value);
279 search the sam for multipe records each giving a single string attribute
280 return the number of matches, or -1 on error
282 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
284 struct ldb_dn *basedn,
286 const char *attr_name,
287 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
291 const char *attrs[2] = { NULL, NULL };
292 struct ldb_message **res = NULL;
294 attrs[0] = attr_name;
296 va_start(ap, format);
297 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
304 /* make sure its single valued */
305 for (i=0;i<count;i++) {
306 if (res[i]->num_elements != 1) {
307 DEBUG(1,("samdb: search for %s %s not single valued\n",
314 *strs = talloc_array(mem_ctx, const char *, count+1);
320 for (i=0;i<count;i++) {
321 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
323 (*strs)[count] = NULL;
329 pull a uint from a result set.
331 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
333 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
337 pull a (signed) int64 from a result set.
339 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
341 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
345 pull a string from a result set.
347 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
348 const char *default_value)
350 return ldb_msg_find_attr_as_string(msg, attr, default_value);
353 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354 const char *attr, struct ldb_dn *default_value)
356 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
358 return default_value;
364 pull a rid from a objectSid in a result set.
366 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
367 const char *attr, uint32_t default_value)
372 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
374 return default_value;
376 rid = sid->sub_auths[sid->num_auths-1];
382 pull a dom_sid structure from a objectSid in a result set.
384 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
387 const struct ldb_val *v;
390 v = ldb_msg_find_ldb_val(msg, attr);
394 sid = talloc(mem_ctx, struct dom_sid);
398 status = ndr_pull_struct_blob(v, sid, sid,
399 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
400 if (!NT_STATUS_IS_OK(status)) {
408 pull a guid structure from a objectGUID in a result set.
410 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
412 const struct ldb_val *v;
419 v = ldb_msg_find_ldb_val(msg, attr);
422 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
423 if (!mem_ctx) return guid;
424 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
425 (ndr_pull_flags_fn_t)ndr_pull_GUID);
426 talloc_free(mem_ctx);
427 if (!NT_STATUS_IS_OK(status)) {
435 pull a sid prefix from a objectSid in a result set.
436 this is used to find the domain sid for a user
438 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
441 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
442 if (!sid || sid->num_auths < 1) return NULL;
448 pull a NTTIME in a result set.
450 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
452 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
456 pull a uint64_t from a result set.
458 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
460 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
465 construct the allow_password_change field from the PwdLastSet attribute and the
466 domain password settings
468 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
470 struct ldb_dn *domain_dn,
471 struct ldb_message *msg,
474 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
477 if (attr_time == 0) {
481 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
483 /* yes, this is a -= not a += as minPwdAge is stored as the negative
484 of the number of 100-nano-seconds */
485 attr_time -= minPwdAge;
491 construct the force_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
496 struct ldb_dn *domain_dn,
497 struct ldb_message *msg)
499 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
500 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
503 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
504 return 0x7FFFFFFFFFFFFFFFULL;
507 if (attr_time == 0) {
511 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
512 if (maxPwdAge == 0) {
515 attr_time -= maxPwdAge;
522 pull a samr_Password structutre from a result set.
524 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
526 struct samr_Password *hash = NULL;
527 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
528 if (val && (val->length >= sizeof(hash->hash))) {
529 hash = talloc(mem_ctx, struct samr_Password);
530 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
536 pull an array of samr_Password structutres from a result set.
538 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
539 const char *attr, struct samr_Password **hashes)
542 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
549 count = val->length / 16;
554 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
559 for (i=0;i<count;i++) {
560 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
566 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
567 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
569 struct samr_Password *lmPwdHash, *ntPwdHash;
572 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
575 } else if (num_nt > 1) {
576 return NT_STATUS_INTERNAL_DB_CORRUPTION;
578 *nt_pwd = &ntPwdHash[0];
583 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
586 } else if (num_lm > 1) {
587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
589 *lm_pwd = &lmPwdHash[0];
596 pull a samr_LogonHours structutre from a result set.
598 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
600 struct samr_LogonHours hours;
601 const int units_per_week = 168;
602 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
604 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
608 hours.units_per_week = units_per_week;
609 memset(hours.bits, 0xFF, units_per_week);
611 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
617 pull a set of account_flags from a result set.
619 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
621 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
622 return samdb_uf2acb(userAccountControl);
626 /* Find an attribute, with a particular value */
628 /* The current callers of this function expect a very specific
629 * behaviour: In particular, objectClass subclass equivilance is not
630 * wanted. This means that we should not lookup the schema for the
631 * comparison function */
632 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
633 const struct ldb_message *msg,
634 const char *name, const char *value)
637 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
640 v.data = discard_const_p(uint8_t, value);
641 v.length = strlen(value);
647 for (i=0;i<el->num_values;i++) {
648 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
656 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
658 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
659 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
664 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
666 struct ldb_message_element *el;
668 el = ldb_msg_find_element(msg, name);
673 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
678 copy from a template record to a message
680 int samdb_copy_template(struct ldb_context *ldb,
681 struct ldb_message *msg, const char *name,
682 const char **errstring)
684 struct ldb_result *res;
685 struct ldb_message *t;
687 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
691 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
692 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
694 return LDB_ERR_OPERATIONS_ERROR;
697 /* pull the template record */
698 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, "cn=*", NULL, &res);
700 if (ret != LDB_SUCCESS) {
701 *errstring = talloc_steal(msg, ldb_errstring(ldb));
704 if (res->count != 1) {
705 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
709 return LDB_ERR_OPERATIONS_ERROR;
713 for (i = 0; i < t->num_elements; i++) {
714 struct ldb_message_element *el = &t->elements[i];
715 /* some elements should not be copied from the template */
716 if (ldb_attr_cmp(el->name, "cn") == 0 ||
717 ldb_attr_cmp(el->name, "name") == 0 ||
718 ldb_attr_cmp(el->name, "objectClass") == 0 ||
719 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
720 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
721 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
722 ldb_attr_cmp(el->name, "objectGUID") == 0) {
725 for (j = 0; j < el->num_values; j++) {
726 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
727 (char *)el->values[j].data);
729 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
743 add a string element to a message
745 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
746 const char *attr_name, const char *str)
748 char *s = talloc_strdup(mem_ctx, str);
749 char *a = talloc_strdup(mem_ctx, attr_name);
750 if (s == NULL || a == NULL) {
751 return LDB_ERR_OPERATIONS_ERROR;
753 return ldb_msg_add_string(msg, a, s);
757 add a dom_sid element to a message
759 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
760 const char *attr_name, struct dom_sid *sid)
764 status = ndr_push_struct_blob(&v, mem_ctx, sid,
765 (ndr_push_flags_fn_t)ndr_push_dom_sid);
766 if (!NT_STATUS_IS_OK(status)) {
769 return ldb_msg_add_value(msg, attr_name, &v, NULL);
774 add a delete element operation to a message
776 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
777 const char *attr_name)
779 /* we use an empty replace rather than a delete, as it allows for
780 samdb_replace() to be used everywhere */
781 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
785 add a add attribute value to a message
787 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
788 const char *attr_name, const char *value)
790 struct ldb_message_element *el;
793 a = talloc_strdup(mem_ctx, attr_name);
796 v = talloc_strdup(mem_ctx, value);
799 ret = ldb_msg_add_string(msg, a, v);
802 el = ldb_msg_find_element(msg, a);
805 el->flags = LDB_FLAG_MOD_ADD;
810 add a delete attribute value to a message
812 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
813 const char *attr_name, const char *value)
815 struct ldb_message_element *el;
818 a = talloc_strdup(mem_ctx, attr_name);
821 v = talloc_strdup(mem_ctx, value);
824 ret = ldb_msg_add_string(msg, a, v);
827 el = ldb_msg_find_element(msg, a);
830 el->flags = LDB_FLAG_MOD_DELETE;
835 add a int element to a message
837 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
838 const char *attr_name, int v)
840 const char *s = talloc_asprintf(mem_ctx, "%d", v);
841 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
845 add a uint_t element to a message
847 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
848 const char *attr_name, uint_t v)
850 const char *s = talloc_asprintf(mem_ctx, "%u", v);
851 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
855 add a (signed) int64_t element to a message
857 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
858 const char *attr_name, int64_t v)
860 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
861 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
865 add a uint64_t element to a message
867 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
868 const char *attr_name, uint64_t v)
870 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
871 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
875 add a samr_Password element to a message
877 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
878 const char *attr_name, struct samr_Password *hash)
881 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
886 return ldb_msg_add_value(msg, attr_name, &val, NULL);
890 add a samr_Password array to a message
892 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
893 const char *attr_name, struct samr_Password *hashes, uint_t count)
897 val.data = talloc_array_size(mem_ctx, 16, count);
898 val.length = count*16;
902 for (i=0;i<count;i++) {
903 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
905 return ldb_msg_add_value(msg, attr_name, &val, NULL);
909 add a acct_flags element to a message
911 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912 const char *attr_name, uint32_t v)
914 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
918 add a logon_hours element to a message
920 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
921 const char *attr_name, struct samr_LogonHours *hours)
924 val.length = hours->units_per_week / 8;
925 val.data = hours->bits;
926 return ldb_msg_add_value(msg, attr_name, &val, NULL);
930 add a general value element to a message
932 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
933 const char *attr_name, const struct ldb_val *val)
935 return ldb_msg_add_value(msg, attr_name, val, NULL);
939 sets a general value element to a message
941 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
942 const char *attr_name, const struct ldb_val *val)
944 struct ldb_message_element *el;
946 el = ldb_msg_find_element(msg, attr_name);
950 return ldb_msg_add_value(msg, attr_name, val, NULL);
954 set a string element in a message
956 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
957 const char *attr_name, const char *str)
959 struct ldb_message_element *el;
961 el = ldb_msg_find_element(msg, attr_name);
965 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
971 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
973 return ldb_add(sam_ldb, msg);
979 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
981 return ldb_delete(sam_ldb, dn);
987 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
989 return ldb_modify(sam_ldb, msg);
993 replace elements in a record
995 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
999 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1000 for (i=0;i<msg->num_elements;i++) {
1001 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1004 /* modify the samdb record */
1005 return samdb_modify(sam_ldb, mem_ctx, msg);
1009 return a default security descriptor
1011 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1013 struct security_descriptor *sd;
1015 sd = security_descriptor_initialise(mem_ctx);
1020 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1022 return ldb_get_default_basedn(sam_ctx);
1025 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1027 return ldb_get_config_basedn(sam_ctx);
1030 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1032 return ldb_get_schema_basedn(sam_ctx);
1035 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1037 return ldb_get_root_basedn(sam_ctx);
1040 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1042 struct ldb_dn *new_dn;
1044 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1045 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1046 talloc_free(new_dn);
1052 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1054 struct ldb_dn *new_dn;
1056 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1057 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1058 talloc_free(new_dn);
1065 work out the domain sid for the current open ldb
1067 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1069 TALLOC_CTX *tmp_ctx;
1070 struct dom_sid *domain_sid;
1072 /* see if we have a cached copy */
1073 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1078 tmp_ctx = talloc_new(ldb);
1079 if (tmp_ctx == NULL) {
1083 /* find the domain_sid */
1084 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1085 "objectSid", "objectClass=domainDNS");
1086 if (domain_sid == NULL) {
1090 /* cache the domain_sid in the ldb */
1091 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1095 talloc_steal(ldb, domain_sid);
1096 talloc_free(tmp_ctx);
1101 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1102 talloc_free(tmp_ctx);
1106 /* Obtain the short name of the flexible single master operator
1107 * (FSMO), such as the PDC Emulator */
1108 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1111 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1112 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1113 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1114 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1116 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1117 /* Ensure this matches the format. This gives us a
1118 * bit more confidence that a 'cn' value will be a
1123 return (char *)val->data;
1129 work out the ntds settings dn for the current open ldb
1131 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1133 TALLOC_CTX *tmp_ctx;
1134 const char *root_attrs[] = { "dsServiceName", NULL };
1136 struct ldb_result *root_res;
1137 struct ldb_dn *settings_dn;
1139 /* see if we have a cached copy */
1140 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1145 tmp_ctx = talloc_new(ldb);
1146 if (tmp_ctx == NULL) {
1151 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1153 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1154 ldb_errstring(ldb)));
1157 talloc_steal(tmp_ctx, root_res);
1159 if (root_res->count != 1) {
1163 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1165 /* cache the domain_sid in the ldb */
1166 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1170 talloc_steal(ldb, settings_dn);
1171 talloc_free(tmp_ctx);
1176 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1177 talloc_free(tmp_ctx);
1182 work out the ntds settings invocationId for the current open ldb
1184 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1186 TALLOC_CTX *tmp_ctx;
1187 const char *attrs[] = { "invocationId", NULL };
1189 struct ldb_result *res;
1190 struct GUID *invocation_id;
1192 /* see if we have a cached copy */
1193 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1194 if (invocation_id) {
1195 return invocation_id;
1198 tmp_ctx = talloc_new(ldb);
1199 if (tmp_ctx == NULL) {
1203 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1207 talloc_steal(tmp_ctx, res);
1209 if (res->count != 1) {
1213 invocation_id = talloc(tmp_ctx, struct GUID);
1214 if (!invocation_id) {
1218 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1220 /* cache the domain_sid in the ldb */
1221 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1225 talloc_steal(ldb, invocation_id);
1226 talloc_free(tmp_ctx);
1228 return invocation_id;
1231 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1232 talloc_free(tmp_ctx);
1236 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1238 TALLOC_CTX *tmp_ctx;
1239 struct GUID *invocation_id_new;
1240 struct GUID *invocation_id_old;
1242 /* see if we have a cached copy */
1243 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1244 "cache.invocation_id");
1246 tmp_ctx = talloc_new(ldb);
1247 if (tmp_ctx == NULL) {
1251 invocation_id_new = talloc(tmp_ctx, struct GUID);
1252 if (!invocation_id_new) {
1256 *invocation_id_new = *invocation_id_in;
1258 /* cache the domain_sid in the ldb */
1259 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1263 talloc_steal(ldb, invocation_id_new);
1264 talloc_free(tmp_ctx);
1265 talloc_free(invocation_id_old);
1270 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1271 talloc_free(tmp_ctx);
1276 work out the ntds settings objectGUID for the current open ldb
1278 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1280 TALLOC_CTX *tmp_ctx;
1281 const char *attrs[] = { "objectGUID", NULL };
1283 struct ldb_result *res;
1284 struct GUID *ntds_guid;
1286 /* see if we have a cached copy */
1287 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1292 tmp_ctx = talloc_new(ldb);
1293 if (tmp_ctx == NULL) {
1297 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1301 talloc_steal(tmp_ctx, res);
1303 if (res->count != 1) {
1307 ntds_guid = talloc(tmp_ctx, struct GUID);
1312 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1314 /* cache the domain_sid in the ldb */
1315 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1319 talloc_steal(ldb, ntds_guid);
1320 talloc_free(tmp_ctx);
1325 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1326 talloc_free(tmp_ctx);
1330 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1332 TALLOC_CTX *tmp_ctx;
1333 struct GUID *ntds_guid_new;
1334 struct GUID *ntds_guid_old;
1336 /* see if we have a cached copy */
1337 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1339 tmp_ctx = talloc_new(ldb);
1340 if (tmp_ctx == NULL) {
1344 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1345 if (!ntds_guid_new) {
1349 *ntds_guid_new = *ntds_guid_in;
1351 /* cache the domain_sid in the ldb */
1352 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1356 talloc_steal(ldb, ntds_guid_new);
1357 talloc_free(tmp_ctx);
1358 talloc_free(ntds_guid_old);
1363 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1364 talloc_free(tmp_ctx);
1369 work out the server dn for the current open ldb
1371 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1373 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1377 work out the server dn for the current open ldb
1379 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1381 struct ldb_dn *server_dn;
1382 struct ldb_dn *server_site_dn;
1384 server_dn = samdb_server_dn(ldb, mem_ctx);
1385 if (!server_dn) return NULL;
1387 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1389 talloc_free(server_dn);
1390 return server_site_dn;
1394 work out if we are the PDC for the domain of the current open ldb
1396 BOOL samdb_is_pdc(struct ldb_context *ldb)
1398 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1400 struct ldb_result *dom_res;
1401 TALLOC_CTX *tmp_ctx;
1405 tmp_ctx = talloc_new(ldb);
1406 if (tmp_ctx == NULL) {
1407 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1411 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1413 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1414 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1415 ldb_errstring(ldb)));
1418 talloc_steal(tmp_ctx, dom_res);
1419 if (dom_res->count != 1) {
1423 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1425 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1431 talloc_free(tmp_ctx);
1436 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1437 talloc_free(tmp_ctx);
1442 /* Find a domain object in the parents of a particular DN. */
1443 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1445 TALLOC_CTX *local_ctx;
1446 struct ldb_dn *sdn = dn;
1447 struct ldb_result *res = NULL;
1449 const char *attrs[] = { NULL };
1451 local_ctx = talloc_new(mem_ctx);
1452 if (local_ctx == NULL) return NULL;
1454 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1455 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1456 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1457 if (ret == LDB_SUCCESS) {
1458 talloc_steal(local_ctx, res);
1459 if (res->count == 1) {
1465 if (ret != LDB_SUCCESS || res->count != 1) {
1466 talloc_free(local_ctx);
1470 talloc_steal(mem_ctx, sdn);
1471 talloc_free(local_ctx);
1477 check that a password is sufficiently complex
1479 static BOOL samdb_password_complexity_ok(const char *pass)
1481 return check_password_quality(pass);
1487 set the user password using plaintext, obeying any user or domain
1488 password restrictions
1490 note that this function doesn't actually store the result in the
1491 database, it just fills in the "mod" structure with ldb modify
1492 elements to setup the correct change when samdb_replace() is
1493 called. This allows the caller to combine the change with other
1494 changes (as is needed by some of the set user info levels)
1496 The caller should probably have a transaction wrapping this
1498 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1499 struct ldb_dn *user_dn,
1500 struct ldb_dn *domain_dn,
1501 struct ldb_message *mod,
1502 const char *new_pass,
1503 struct samr_Password *lmNewHash,
1504 struct samr_Password *ntNewHash,
1506 enum samr_RejectReason *reject_reason,
1507 struct samr_DomInfo1 **_dominfo)
1509 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1511 "dBCSPwd", "unicodePwd",
1513 "pwdLastSet", NULL };
1514 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1515 "maxPwdAge", "minPwdAge",
1516 "minPwdLength", NULL };
1519 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1520 uint_t userAccountControl;
1521 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1522 struct samr_Password local_lmNewHash, local_ntNewHash;
1523 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1524 struct dom_sid *domain_sid;
1525 struct ldb_message **res;
1528 time_t now = time(NULL);
1532 /* we need to know the time to compute password age */
1533 unix_to_nt_time(&now_nt, now);
1535 /* pull all the user parameters */
1536 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1538 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1540 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1541 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1542 "lmPwdHistory", &sambaLMPwdHistory);
1543 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1544 "ntPwdHistory", &sambaNTPwdHistory);
1545 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1546 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1547 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1549 /* Only non-trust accounts have restrictions (possibly this
1550 * test is the wrong way around, but I like to be restrictive
1552 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1553 |UF_WORKSTATION_TRUST_ACCOUNT
1554 |UF_SERVER_TRUST_ACCOUNT));
1557 /* pull the domain parameters */
1558 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1560 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1561 ldb_dn_get_linearized(domain_dn),
1562 ldb_dn_get_linearized(user_dn)));
1563 return NT_STATUS_NO_SUCH_DOMAIN;
1566 /* work out the domain sid, and pull the domain from there */
1567 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1568 if (domain_sid == NULL) {
1569 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1572 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1574 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1576 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1577 dom_sid_string(mem_ctx, domain_sid),
1578 ldb_dn_get_linearized(user_dn)));
1579 return NT_STATUS_NO_SUCH_DOMAIN;
1583 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1584 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1585 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1586 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1589 struct samr_DomInfo1 *dominfo;
1590 /* on failure we need to fill in the reject reasons */
1591 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1592 if (dominfo == NULL) {
1593 return NT_STATUS_NO_MEMORY;
1595 dominfo->min_password_length = minPwdLength;
1596 dominfo->password_properties = pwdProperties;
1597 dominfo->password_history_length = pwdHistoryLength;
1598 dominfo->max_password_age = minPwdAge;
1599 dominfo->min_password_age = minPwdAge;
1600 *_dominfo = dominfo;
1603 if (restrictions && new_pass) {
1605 /* check the various password restrictions */
1606 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1607 if (reject_reason) {
1608 *reject_reason = SAMR_REJECT_TOO_SHORT;
1610 return NT_STATUS_PASSWORD_RESTRICTION;
1613 /* possibly check password complexity */
1614 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1615 !samdb_password_complexity_ok(new_pass)) {
1616 if (reject_reason) {
1617 *reject_reason = SAMR_REJECT_COMPLEXITY;
1619 return NT_STATUS_PASSWORD_RESTRICTION;
1622 /* compute the new nt and lm hashes */
1623 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1624 lmNewHash = &local_lmNewHash;
1626 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1627 /* If we can't convert this password to UCS2, then we should not accept it */
1628 if (reject_reason) {
1629 *reject_reason = SAMR_REJECT_OTHER;
1631 return NT_STATUS_PASSWORD_RESTRICTION;
1633 ntNewHash = &local_ntNewHash;
1637 /* are all password changes disallowed? */
1638 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1639 if (reject_reason) {
1640 *reject_reason = SAMR_REJECT_OTHER;
1642 return NT_STATUS_PASSWORD_RESTRICTION;
1645 /* can this user change password? */
1646 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1647 if (reject_reason) {
1648 *reject_reason = SAMR_REJECT_OTHER;
1650 return NT_STATUS_PASSWORD_RESTRICTION;
1653 /* yes, this is a minus. The ages are in negative 100nsec units! */
1654 if (pwdLastSet - minPwdAge > now_nt) {
1655 if (reject_reason) {
1656 *reject_reason = SAMR_REJECT_OTHER;
1658 return NT_STATUS_PASSWORD_RESTRICTION;
1661 /* check the immediately past password */
1662 if (pwdHistoryLength > 0) {
1663 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1664 if (reject_reason) {
1665 *reject_reason = SAMR_REJECT_IN_HISTORY;
1667 return NT_STATUS_PASSWORD_RESTRICTION;
1669 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1670 if (reject_reason) {
1671 *reject_reason = SAMR_REJECT_IN_HISTORY;
1673 return NT_STATUS_PASSWORD_RESTRICTION;
1677 /* check the password history */
1678 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1679 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1681 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1682 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1683 if (reject_reason) {
1684 *reject_reason = SAMR_REJECT_IN_HISTORY;
1686 return NT_STATUS_PASSWORD_RESTRICTION;
1689 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1690 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1691 if (reject_reason) {
1692 *reject_reason = SAMR_REJECT_IN_HISTORY;
1694 return NT_STATUS_PASSWORD_RESTRICTION;
1699 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1701 /* the password is acceptable. Start forming the new fields */
1703 /* if we know the cleartext, then only set it.
1704 * Modules in ldb will set all the appropriate
1706 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1707 "sambaPassword", new_pass));
1709 /* We don't have the cleartext, so delete the old one
1710 * and set what we have of the hashes */
1711 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1714 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1716 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1720 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1722 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1726 return NT_STATUS_OK;
1731 set the user password using plaintext, obeying any user or domain
1732 password restrictions
1734 This wrapper function takes a SID as input, rather than a user DN,
1735 and actually performs the password change
1738 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1739 const struct dom_sid *user_sid,
1740 const char *new_pass,
1741 struct samr_Password *lmNewHash,
1742 struct samr_Password *ntNewHash,
1744 enum samr_RejectReason *reject_reason,
1745 struct samr_DomInfo1 **_dominfo)
1748 struct ldb_dn *user_dn;
1749 struct ldb_message *msg;
1752 ret = ldb_transaction_start(ctx);
1754 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1755 return NT_STATUS_TRANSACTION_ABORTED;
1758 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1759 "(&(objectSid=%s)(objectClass=user))",
1760 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1762 ldb_transaction_cancel(ctx);
1763 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1764 dom_sid_string(mem_ctx, user_sid)));
1765 return NT_STATUS_NO_SUCH_USER;
1768 msg = ldb_msg_new(mem_ctx);
1770 ldb_transaction_cancel(ctx);
1771 return NT_STATUS_NO_MEMORY;
1774 msg->dn = ldb_dn_copy(msg, user_dn);
1776 ldb_transaction_cancel(ctx);
1777 return NT_STATUS_NO_MEMORY;
1780 nt_status = samdb_set_password(ctx, mem_ctx,
1783 lmNewHash, ntNewHash,
1784 user_change, /* This is a password set, not change */
1785 reject_reason, _dominfo);
1786 if (!NT_STATUS_IS_OK(nt_status)) {
1787 ldb_transaction_cancel(ctx);
1791 /* modify the samdb record */
1792 ret = samdb_replace(ctx, mem_ctx, msg);
1794 ldb_transaction_cancel(ctx);
1795 return NT_STATUS_ACCESS_DENIED;
1798 ret = ldb_transaction_commit(ctx);
1800 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1801 ldb_dn_get_linearized(msg->dn),
1802 ldb_errstring(ctx)));
1803 return NT_STATUS_TRANSACTION_ABORTED;
1805 return NT_STATUS_OK;
1808 /****************************************************************************
1809 Create the SID list for this user.
1810 ****************************************************************************/
1811 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1812 struct dom_sid *user_sid,
1813 struct dom_sid *group_sid,
1815 struct dom_sid **groupSIDs,
1816 BOOL is_authenticated,
1817 struct security_token **token)
1819 struct security_token *ptoken;
1823 ptoken = security_token_initialise(mem_ctx);
1824 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1826 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1827 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1829 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1830 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1831 ptoken->privilege_mask = 0;
1833 ptoken->sids[0] = ptoken->user_sid;
1834 ptoken->sids[1] = ptoken->group_sid;
1837 * Finally add the "standard" SIDs.
1838 * The only difference between guest and "anonymous"
1839 * is the addition of Authenticated_Users.
1841 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1842 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1843 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1844 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1845 ptoken->num_sids = 4;
1847 if (is_authenticated) {
1848 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1849 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1853 for (i = 0; i < n_groupSIDs; i++) {
1854 size_t check_sid_idx;
1855 for (check_sid_idx = 1;
1856 check_sid_idx < ptoken->num_sids;
1858 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1863 if (check_sid_idx == ptoken->num_sids) {
1864 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1868 /* setup the privilege mask for this token */
1869 status = samdb_privilege_setup(ptoken);
1870 if (!NT_STATUS_IS_OK(status)) {
1871 talloc_free(ptoken);
1875 security_token_debug(10, ptoken);
1879 return NT_STATUS_OK;
1883 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1884 struct dom_sid *sid, struct ldb_dn **ret_dn)
1886 struct ldb_message *msg;
1887 struct ldb_dn *basedn;
1891 sidstr = dom_sid_string(mem_ctx, sid);
1892 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1894 /* We might have to create a ForeignSecurityPrincipal, even if this user
1895 * is in our own domain */
1897 msg = ldb_msg_new(mem_ctx);
1899 return NT_STATUS_NO_MEMORY;
1902 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1903 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1904 * not work, this is wrong for the Builtin domain, there's no
1905 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1908 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1909 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1911 if (basedn == NULL) {
1912 DEBUG(0, ("Failed to find DN for "
1913 "ForeignSecurityPrincipal container\n"));
1914 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1917 /* add core elements to the ldb_message for the alias */
1918 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1919 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1920 return NT_STATUS_NO_MEMORY;
1922 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1924 "foreignSecurityPrincipal");
1926 /* create the alias */
1927 ret = samdb_add(sam_ctx, mem_ctx, msg);
1929 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1931 ldb_dn_get_linearized(msg->dn),
1932 ldb_errstring(sam_ctx)));
1933 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1936 return NT_STATUS_OK;
1941 Find the DN of a domain, assuming it to be a dotted.dns name
1944 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1947 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1948 const char *binary_encoded;
1949 const char **split_realm;
1956 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1958 talloc_free(tmp_ctx);
1961 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1962 for (i=0; split_realm[i]; i++) {
1963 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1964 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1965 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1966 binary_encoded, ldb_dn_get_linearized(dn)));
1967 talloc_free(tmp_ctx);
1971 if (!ldb_dn_validate(dn)) {
1972 DEBUG(2, ("Failed to validated DN %s\n",
1973 ldb_dn_get_linearized(dn)));
1979 Find the DN of a domain, be it the netbios or DNS name
1982 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1983 const char *domain_name)
1985 const char * const domain_ref_attrs[] = {
1988 const char * const domain_ref2_attrs[] = {
1991 struct ldb_result *res_domain_ref;
1992 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1993 /* find the domain's DN */
1994 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1996 samdb_partitions_dn(ldb, mem_ctx),
1999 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2001 if (ret_domain != 0) {
2005 if (res_domain_ref->count == 0) {
2006 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2008 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2011 "(objectclass=domain)");
2012 if (ret_domain != 0) {
2016 if (res_domain_ref->count == 1) {
2017 return res_domain_ref->msgs[0]->dn;
2022 if (res_domain_ref->count > 1) {
2023 DEBUG(0,("Found %d records matching domain [%s]\n",
2024 ret_domain, domain_name));
2028 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);