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 "util/util_ldb.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "dsdb/common/flags.h"
39 #include "param/param.h"
41 char *samdb_relative_path(struct ldb_context *ldb,
45 const char *base_url =
46 (const char *)ldb_get_opaque(ldb, "ldb_url");
47 char *path, *p, *full_name;
51 if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) {
52 return talloc_strdup(mem_ctx, name);
54 path = talloc_strdup(mem_ctx, base_url);
58 if ( (p = strrchr(path, '/')) != NULL) {
60 full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name);
62 full_name = talloc_asprintf(mem_ctx, "./%s", name);
70 connect to the SAM database
71 return an opaque context pointer on success, or NULL on failure
73 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
74 struct loadparm_context *lp_ctx,
75 struct auth_session_info *session_info)
77 struct ldb_context *ldb;
78 ldb = ldb_wrap_connect(mem_ctx, lp_ctx,
79 lp_sam_url(lp_ctx), session_info,
84 dsdb_make_schema_global(ldb);
89 search the sam for the specified attributes in a specific domain, filter on
90 objectSid being in domain_sid.
92 int samdb_search_domain(struct ldb_context *sam_ldb,
94 struct ldb_dn *basedn,
95 struct ldb_message ***res,
96 const char * const *attrs,
97 const struct dom_sid *domain_sid,
98 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
103 va_start(ap, format);
104 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
105 res, attrs, format, ap);
111 struct dom_sid *entry_sid;
113 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
115 if ((entry_sid == NULL) ||
116 (!dom_sid_in_domain(domain_sid, entry_sid))) {
117 /* Delete that entry from the result set */
118 (*res)[i] = (*res)[count-1];
120 talloc_free(entry_sid);
123 talloc_free(entry_sid);
131 search the sam for a single string attribute in exactly 1 record
133 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
135 struct ldb_dn *basedn,
136 const char *attr_name,
137 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
140 const char *attrs[2] = { NULL, NULL };
141 struct ldb_message **res = NULL;
143 attrs[0] = attr_name;
145 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
147 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
148 attr_name, format, count));
155 return samdb_result_string(res[0], attr_name, NULL);
160 search the sam for a single string attribute in exactly 1 record
162 const char *samdb_search_string(struct ldb_context *sam_ldb,
164 struct ldb_dn *basedn,
165 const char *attr_name,
166 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
171 va_start(ap, format);
172 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
178 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
180 struct ldb_dn *basedn,
181 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
185 struct ldb_message **res = NULL;
188 va_start(ap, format);
189 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
192 if (count != 1) return NULL;
194 ret = talloc_steal(mem_ctx, res[0]->dn);
201 search the sam for a dom_sid attribute in exactly 1 record
203 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
205 struct ldb_dn *basedn,
206 const char *attr_name,
207 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
211 struct ldb_message **res;
212 const char *attrs[2] = { NULL, NULL };
215 attrs[0] = attr_name;
217 va_start(ap, format);
218 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
221 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
222 attr_name, format, count));
228 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
234 return the count of the number of records in the sam matching the query
236 int samdb_search_count(struct ldb_context *sam_ldb,
238 struct ldb_dn *basedn,
239 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
242 struct ldb_message **res;
243 const char * const attrs[] = { NULL };
246 va_start(ap, format);
247 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
255 search the sam for a single integer attribute in exactly 1 record
257 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
259 uint_t default_value,
260 struct ldb_dn *basedn,
261 const char *attr_name,
262 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
266 struct ldb_message **res;
267 const char *attrs[2] = { NULL, NULL };
269 attrs[0] = attr_name;
271 va_start(ap, format);
272 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
276 return default_value;
279 return samdb_result_uint(res[0], attr_name, default_value);
283 search the sam for a single signed 64 bit integer attribute in exactly 1 record
285 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
287 int64_t default_value,
288 struct ldb_dn *basedn,
289 const char *attr_name,
290 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
294 struct ldb_message **res;
295 const char *attrs[2] = { NULL, NULL };
297 attrs[0] = attr_name;
299 va_start(ap, format);
300 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
304 return default_value;
307 return samdb_result_int64(res[0], attr_name, default_value);
311 search the sam for multipe records each giving a single string attribute
312 return the number of matches, or -1 on error
314 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
316 struct ldb_dn *basedn,
318 const char *attr_name,
319 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
323 const char *attrs[2] = { NULL, NULL };
324 struct ldb_message **res = NULL;
326 attrs[0] = attr_name;
328 va_start(ap, format);
329 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
336 /* make sure its single valued */
337 for (i=0;i<count;i++) {
338 if (res[i]->num_elements != 1) {
339 DEBUG(1,("samdb: search for %s %s not single valued\n",
346 *strs = talloc_array(mem_ctx, const char *, count+1);
352 for (i=0;i<count;i++) {
353 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
355 (*strs)[count] = NULL;
361 pull a uint from a result set.
363 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
365 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
369 pull a (signed) int64 from a result set.
371 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
373 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
377 pull a string from a result set.
379 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
380 const char *default_value)
382 return ldb_msg_find_attr_as_string(msg, attr, default_value);
385 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
386 const char *attr, struct ldb_dn *default_value)
388 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
390 return default_value;
396 pull a rid from a objectSid in a result set.
398 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
399 const char *attr, uint32_t default_value)
404 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
406 return default_value;
408 rid = sid->sub_auths[sid->num_auths-1];
414 pull a dom_sid structure from a objectSid in a result set.
416 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
419 const struct ldb_val *v;
421 enum ndr_err_code ndr_err;
422 v = ldb_msg_find_ldb_val(msg, attr);
426 sid = talloc(mem_ctx, struct dom_sid);
430 ndr_err = ndr_pull_struct_blob(v, sid, sid,
431 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
432 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
440 pull a guid structure from a objectGUID in a result set.
442 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
444 const struct ldb_val *v;
445 enum ndr_err_code ndr_err;
451 v = ldb_msg_find_ldb_val(msg, attr);
454 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
455 if (!mem_ctx) return guid;
456 ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid,
457 (ndr_pull_flags_fn_t)ndr_pull_GUID);
458 talloc_free(mem_ctx);
459 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
467 pull a sid prefix from a objectSid in a result set.
468 this is used to find the domain sid for a user
470 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
473 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
474 if (!sid || sid->num_auths < 1) return NULL;
480 pull a NTTIME in a result set.
482 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
484 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
488 pull a uint64_t from a result set.
490 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
492 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
497 construct the allow_password_change field from the PwdLastSet attribute and the
498 domain password settings
500 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
502 struct ldb_dn *domain_dn,
503 struct ldb_message *msg,
506 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
509 if (attr_time == 0) {
513 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
515 /* yes, this is a -= not a += as minPwdAge is stored as the negative
516 of the number of 100-nano-seconds */
517 attr_time -= minPwdAge;
523 construct the force_password_change field from the PwdLastSet attribute and the
524 domain password settings
526 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
528 struct ldb_dn *domain_dn,
529 struct ldb_message *msg)
531 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
532 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
535 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
536 return 0x7FFFFFFFFFFFFFFFULL;
539 if (attr_time == 0) {
543 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
544 if (maxPwdAge == 0) {
547 attr_time -= maxPwdAge;
554 pull a samr_Password structutre from a result set.
556 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
558 struct samr_Password *hash = NULL;
559 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
560 if (val && (val->length >= sizeof(hash->hash))) {
561 hash = talloc(mem_ctx, struct samr_Password);
562 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
568 pull an array of samr_Password structutres from a result set.
570 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
571 const char *attr, struct samr_Password **hashes)
574 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
581 count = val->length / 16;
586 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
591 for (i=0;i<count;i++) {
592 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
598 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
599 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
601 struct samr_Password *lmPwdHash, *ntPwdHash;
604 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
607 } else if (num_nt > 1) {
608 return NT_STATUS_INTERNAL_DB_CORRUPTION;
610 *nt_pwd = &ntPwdHash[0];
615 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
618 } else if (num_lm > 1) {
619 return NT_STATUS_INTERNAL_DB_CORRUPTION;
621 *lm_pwd = &lmPwdHash[0];
628 pull a samr_LogonHours structutre from a result set.
630 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
632 struct samr_LogonHours hours;
633 const int units_per_week = 168;
634 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
636 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
640 hours.units_per_week = units_per_week;
641 memset(hours.bits, 0xFF, units_per_week);
643 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
649 pull a set of account_flags from a result set.
651 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
653 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
654 return samdb_uf2acb(userAccountControl);
658 /* Find an attribute, with a particular value */
660 /* The current callers of this function expect a very specific
661 * behaviour: In particular, objectClass subclass equivilance is not
662 * wanted. This means that we should not lookup the schema for the
663 * comparison function */
664 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
665 const struct ldb_message *msg,
666 const char *name, const char *value)
669 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
675 for (i=0;i<el->num_values;i++) {
676 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
684 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
686 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
687 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
692 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
694 struct ldb_message_element *el;
696 el = ldb_msg_find_element(msg, name);
701 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
706 copy from a template record to a message
708 int samdb_copy_template(struct ldb_context *ldb,
709 struct ldb_message *msg, const char *name,
710 const char **errstring)
712 struct ldb_result *res;
713 struct ldb_message *t;
715 struct ldb_context *templates_ldb;
716 char *templates_ldb_path;
717 struct ldb_dn *basedn;
719 templates_ldb = talloc_get_type(ldb_get_opaque(ldb, "templates_ldb"), struct ldb_context);
721 if (!templates_ldb) {
722 templates_ldb_path = samdb_relative_path(ldb,
725 if (!templates_ldb_path) {
726 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct path for template db");
727 return LDB_ERR_OPERATIONS_ERROR;
730 templates_ldb = ldb_wrap_connect(ldb, global_loadparm,
731 templates_ldb_path, NULL,
733 talloc_free(templates_ldb_path);
734 if (!templates_ldb) {
735 return LDB_ERR_OPERATIONS_ERROR;
738 ret = ldb_set_opaque(ldb, "templates_ldb", templates_ldb);
739 if (ret != LDB_SUCCESS) {
745 basedn = ldb_dn_new(templates_ldb, ldb, "cn=Templates");
746 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
748 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
750 return LDB_ERR_OPERATIONS_ERROR;
753 /* pull the template record */
754 ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "(dn=*)", NULL, &res);
756 if (ret != LDB_SUCCESS) {
757 *errstring = talloc_steal(msg, ldb_errstring(templates_ldb));
760 if (res->count != 1) {
761 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
765 return LDB_ERR_OPERATIONS_ERROR;
769 for (i = 0; i < t->num_elements; i++) {
770 struct ldb_message_element *el = &t->elements[i];
771 /* some elements should not be copied from the template */
772 if (ldb_attr_cmp(el->name, "cn") == 0 ||
773 ldb_attr_cmp(el->name, "name") == 0 ||
774 ldb_attr_cmp(el->name, "objectClass") == 0 ||
775 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
776 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
777 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
778 ldb_attr_cmp(el->name, "objectGUID") == 0) {
781 for (j = 0; j < el->num_values; j++) {
782 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
783 (char *)el->values[j].data);
785 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
799 add a string element to a message
801 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
802 const char *attr_name, const char *str)
804 char *s = talloc_strdup(mem_ctx, str);
805 char *a = talloc_strdup(mem_ctx, attr_name);
806 if (s == NULL || a == NULL) {
807 return LDB_ERR_OPERATIONS_ERROR;
809 return ldb_msg_add_string(msg, a, s);
813 add a dom_sid element to a message
815 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
816 const char *attr_name, struct dom_sid *sid)
819 enum ndr_err_code ndr_err;
821 ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid,
822 (ndr_push_flags_fn_t)ndr_push_dom_sid);
823 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
826 return ldb_msg_add_value(msg, attr_name, &v, NULL);
831 add a delete element operation to a message
833 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
834 const char *attr_name)
836 /* we use an empty replace rather than a delete, as it allows for
837 samdb_replace() to be used everywhere */
838 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
842 add a add attribute value to a message
844 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
845 const char *attr_name, const char *value)
847 struct ldb_message_element *el;
850 a = talloc_strdup(mem_ctx, attr_name);
853 v = talloc_strdup(mem_ctx, value);
856 ret = ldb_msg_add_string(msg, a, v);
859 el = ldb_msg_find_element(msg, a);
862 el->flags = LDB_FLAG_MOD_ADD;
867 add a delete attribute value to a message
869 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
870 const char *attr_name, const char *value)
872 struct ldb_message_element *el;
875 a = talloc_strdup(mem_ctx, attr_name);
878 v = talloc_strdup(mem_ctx, value);
881 ret = ldb_msg_add_string(msg, a, v);
884 el = ldb_msg_find_element(msg, a);
887 el->flags = LDB_FLAG_MOD_DELETE;
892 add a int element to a message
894 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
895 const char *attr_name, int v)
897 const char *s = talloc_asprintf(mem_ctx, "%d", v);
898 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
902 add a uint_t element to a message
904 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
905 const char *attr_name, uint_t v)
907 const char *s = talloc_asprintf(mem_ctx, "%u", v);
908 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
912 add a (signed) int64_t element to a message
914 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
915 const char *attr_name, int64_t v)
917 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
918 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
922 add a uint64_t element to a message
924 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
925 const char *attr_name, uint64_t v)
927 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
928 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
932 add a samr_Password element to a message
934 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
935 const char *attr_name, struct samr_Password *hash)
938 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
943 return ldb_msg_add_value(msg, attr_name, &val, NULL);
947 add a samr_Password array to a message
949 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
950 const char *attr_name, struct samr_Password *hashes, uint_t count)
954 val.data = talloc_array_size(mem_ctx, 16, count);
955 val.length = count*16;
959 for (i=0;i<count;i++) {
960 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
962 return ldb_msg_add_value(msg, attr_name, &val, NULL);
966 add a acct_flags element to a message
968 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
969 const char *attr_name, uint32_t v)
971 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
975 add a logon_hours element to a message
977 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
978 const char *attr_name, struct samr_LogonHours *hours)
981 val.length = hours->units_per_week / 8;
982 val.data = hours->bits;
983 return ldb_msg_add_value(msg, attr_name, &val, NULL);
987 add a general value element to a message
989 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
990 const char *attr_name, const struct ldb_val *val)
992 return ldb_msg_add_value(msg, attr_name, val, NULL);
996 sets a general value element to a message
998 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
999 const char *attr_name, const struct ldb_val *val)
1001 struct ldb_message_element *el;
1003 el = ldb_msg_find_element(msg, attr_name);
1007 return ldb_msg_add_value(msg, attr_name, val, NULL);
1011 set a string element in a message
1013 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1014 const char *attr_name, const char *str)
1016 struct ldb_message_element *el;
1018 el = ldb_msg_find_element(msg, attr_name);
1022 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1026 replace elements in a record
1028 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1032 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1033 for (i=0;i<msg->num_elements;i++) {
1034 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1037 /* modify the samdb record */
1038 return ldb_modify(sam_ldb, msg);
1042 return a default security descriptor
1044 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1046 struct security_descriptor *sd;
1048 sd = security_descriptor_initialise(mem_ctx);
1053 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1055 return ldb_get_default_basedn(sam_ctx);
1058 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1060 return ldb_get_config_basedn(sam_ctx);
1063 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1065 return ldb_get_schema_basedn(sam_ctx);
1068 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1070 return ldb_get_root_basedn(sam_ctx);
1073 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1075 struct ldb_dn *new_dn;
1077 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1078 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1079 talloc_free(new_dn);
1085 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1087 struct ldb_dn *new_dn;
1089 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1090 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1091 talloc_free(new_dn);
1098 work out the domain sid for the current open ldb
1100 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1102 TALLOC_CTX *tmp_ctx;
1103 struct dom_sid *domain_sid;
1105 /* see if we have a cached copy */
1106 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1111 tmp_ctx = talloc_new(ldb);
1112 if (tmp_ctx == NULL) {
1116 /* find the domain_sid */
1117 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1118 "objectSid", "objectClass=domainDNS");
1119 if (domain_sid == NULL) {
1123 /* cache the domain_sid in the ldb */
1124 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1128 talloc_steal(ldb, domain_sid);
1129 talloc_free(tmp_ctx);
1134 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1135 talloc_free(tmp_ctx);
1139 /* Obtain the short name of the flexible single master operator
1140 * (FSMO), such as the PDC Emulator */
1141 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1144 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1145 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1146 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1147 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1149 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1150 /* Ensure this matches the format. This gives us a
1151 * bit more confidence that a 'cn' value will be a
1156 return (char *)val->data;
1162 work out the ntds settings dn for the current open ldb
1164 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1166 TALLOC_CTX *tmp_ctx;
1167 const char *root_attrs[] = { "dsServiceName", NULL };
1169 struct ldb_result *root_res;
1170 struct ldb_dn *settings_dn;
1172 /* see if we have a cached copy */
1173 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1178 tmp_ctx = talloc_new(ldb);
1179 if (tmp_ctx == NULL) {
1184 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1186 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1187 ldb_errstring(ldb)));
1190 talloc_steal(tmp_ctx, root_res);
1192 if (root_res->count != 1) {
1196 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1198 /* cache the domain_sid in the ldb */
1199 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1203 talloc_steal(ldb, settings_dn);
1204 talloc_free(tmp_ctx);
1209 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1210 talloc_free(tmp_ctx);
1215 work out the ntds settings invocationId for the current open ldb
1217 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1219 TALLOC_CTX *tmp_ctx;
1220 const char *attrs[] = { "invocationId", NULL };
1222 struct ldb_result *res;
1223 struct GUID *invocation_id;
1225 /* see if we have a cached copy */
1226 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1227 if (invocation_id) {
1228 return invocation_id;
1231 tmp_ctx = talloc_new(ldb);
1232 if (tmp_ctx == NULL) {
1236 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1240 talloc_steal(tmp_ctx, res);
1242 if (res->count != 1) {
1246 invocation_id = talloc(tmp_ctx, struct GUID);
1247 if (!invocation_id) {
1251 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1253 /* cache the domain_sid in the ldb */
1254 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1258 talloc_steal(ldb, invocation_id);
1259 talloc_free(tmp_ctx);
1261 return invocation_id;
1264 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1265 talloc_free(tmp_ctx);
1269 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1271 TALLOC_CTX *tmp_ctx;
1272 struct GUID *invocation_id_new;
1273 struct GUID *invocation_id_old;
1275 /* see if we have a cached copy */
1276 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1277 "cache.invocation_id");
1279 tmp_ctx = talloc_new(ldb);
1280 if (tmp_ctx == NULL) {
1284 invocation_id_new = talloc(tmp_ctx, struct GUID);
1285 if (!invocation_id_new) {
1289 *invocation_id_new = *invocation_id_in;
1291 /* cache the domain_sid in the ldb */
1292 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1296 talloc_steal(ldb, invocation_id_new);
1297 talloc_free(tmp_ctx);
1298 talloc_free(invocation_id_old);
1303 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1304 talloc_free(tmp_ctx);
1309 work out the ntds settings objectGUID for the current open ldb
1311 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1313 TALLOC_CTX *tmp_ctx;
1314 const char *attrs[] = { "objectGUID", NULL };
1316 struct ldb_result *res;
1317 struct GUID *ntds_guid;
1319 /* see if we have a cached copy */
1320 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1325 tmp_ctx = talloc_new(ldb);
1326 if (tmp_ctx == NULL) {
1330 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1334 talloc_steal(tmp_ctx, res);
1336 if (res->count != 1) {
1340 ntds_guid = talloc(tmp_ctx, struct GUID);
1345 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1347 /* cache the domain_sid in the ldb */
1348 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1352 talloc_steal(ldb, ntds_guid);
1353 talloc_free(tmp_ctx);
1358 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1359 talloc_free(tmp_ctx);
1363 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1365 TALLOC_CTX *tmp_ctx;
1366 struct GUID *ntds_guid_new;
1367 struct GUID *ntds_guid_old;
1369 /* see if we have a cached copy */
1370 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1372 tmp_ctx = talloc_new(ldb);
1373 if (tmp_ctx == NULL) {
1377 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1378 if (!ntds_guid_new) {
1382 *ntds_guid_new = *ntds_guid_in;
1384 /* cache the domain_sid in the ldb */
1385 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1389 talloc_steal(ldb, ntds_guid_new);
1390 talloc_free(tmp_ctx);
1391 talloc_free(ntds_guid_old);
1396 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1397 talloc_free(tmp_ctx);
1402 work out the server dn for the current open ldb
1404 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1406 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1410 work out the server dn for the current open ldb
1412 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1414 struct ldb_dn *server_dn;
1415 struct ldb_dn *server_site_dn;
1417 server_dn = samdb_server_dn(ldb, mem_ctx);
1418 if (!server_dn) return NULL;
1420 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1422 talloc_free(server_dn);
1423 return server_site_dn;
1427 work out if we are the PDC for the domain of the current open ldb
1429 bool samdb_is_pdc(struct ldb_context *ldb)
1431 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1433 struct ldb_result *dom_res;
1434 TALLOC_CTX *tmp_ctx;
1438 tmp_ctx = talloc_new(ldb);
1439 if (tmp_ctx == NULL) {
1440 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1444 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1446 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1447 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1448 ldb_errstring(ldb)));
1451 talloc_steal(tmp_ctx, dom_res);
1452 if (dom_res->count != 1) {
1456 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1458 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1464 talloc_free(tmp_ctx);
1469 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1470 talloc_free(tmp_ctx);
1475 /* Find a domain object in the parents of a particular DN. */
1476 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1477 struct ldb_dn **parent_dn, const char **errstring)
1479 TALLOC_CTX *local_ctx;
1480 struct ldb_dn *sdn = dn;
1481 struct ldb_result *res = NULL;
1483 const char *attrs[] = { NULL };
1485 local_ctx = talloc_new(mem_ctx);
1486 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1488 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1489 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1490 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1491 if (ret == LDB_SUCCESS) {
1492 talloc_steal(local_ctx, res);
1493 if (res->count == 1) {
1501 if (ret != LDB_SUCCESS) {
1502 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1503 ldb_dn_get_linearized(dn),
1504 ldb_dn_get_linearized(sdn),
1505 ldb_errstring(ldb));
1506 talloc_free(local_ctx);
1509 if (res->count != 1) {
1510 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1511 ldb_dn_get_linearized(dn));
1512 talloc_free(local_ctx);
1513 return LDB_ERR_CONSTRAINT_VIOLATION;
1516 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1517 talloc_free(local_ctx);
1522 check that a password is sufficiently complex
1524 static bool samdb_password_complexity_ok(const char *pass)
1526 return check_password_quality(pass);
1532 set the user password using plaintext, obeying any user or domain
1533 password restrictions
1535 note that this function doesn't actually store the result in the
1536 database, it just fills in the "mod" structure with ldb modify
1537 elements to setup the correct change when samdb_replace() is
1538 called. This allows the caller to combine the change with other
1539 changes (as is needed by some of the set user info levels)
1541 The caller should probably have a transaction wrapping this
1543 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1544 struct ldb_dn *user_dn,
1545 struct ldb_dn *domain_dn,
1546 struct ldb_message *mod,
1547 const char *new_pass,
1548 struct samr_Password *lmNewHash,
1549 struct samr_Password *ntNewHash,
1551 enum samr_RejectReason *reject_reason,
1552 struct samr_DomInfo1 **_dominfo)
1554 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1556 "dBCSPwd", "unicodePwd",
1558 "pwdLastSet", NULL };
1559 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1560 "maxPwdAge", "minPwdAge",
1561 "minPwdLength", NULL };
1564 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1565 uint_t userAccountControl;
1566 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1567 struct samr_Password local_lmNewHash, local_ntNewHash;
1568 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1569 struct dom_sid *domain_sid;
1570 struct ldb_message **res;
1573 time_t now = time(NULL);
1577 /* we need to know the time to compute password age */
1578 unix_to_nt_time(&now_nt, now);
1580 /* pull all the user parameters */
1581 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1583 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1585 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1586 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1587 "lmPwdHistory", &sambaLMPwdHistory);
1588 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1589 "ntPwdHistory", &sambaNTPwdHistory);
1590 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1591 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1592 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1594 /* Only non-trust accounts have restrictions (possibly this
1595 * test is the wrong way around, but I like to be restrictive
1597 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1598 |UF_WORKSTATION_TRUST_ACCOUNT
1599 |UF_SERVER_TRUST_ACCOUNT));
1602 /* pull the domain parameters */
1603 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1605 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1606 ldb_dn_get_linearized(domain_dn),
1607 ldb_dn_get_linearized(user_dn)));
1608 return NT_STATUS_NO_SUCH_DOMAIN;
1611 /* work out the domain sid, and pull the domain from there */
1612 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1613 if (domain_sid == NULL) {
1614 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1617 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1619 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1621 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1622 dom_sid_string(mem_ctx, domain_sid),
1623 ldb_dn_get_linearized(user_dn)));
1624 return NT_STATUS_NO_SUCH_DOMAIN;
1628 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1629 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1630 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1631 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1634 struct samr_DomInfo1 *dominfo;
1635 /* on failure we need to fill in the reject reasons */
1636 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1637 if (dominfo == NULL) {
1638 return NT_STATUS_NO_MEMORY;
1640 dominfo->min_password_length = minPwdLength;
1641 dominfo->password_properties = pwdProperties;
1642 dominfo->password_history_length = pwdHistoryLength;
1643 dominfo->max_password_age = minPwdAge;
1644 dominfo->min_password_age = minPwdAge;
1645 *_dominfo = dominfo;
1648 if (restrictions && new_pass) {
1650 /* check the various password restrictions */
1651 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1652 if (reject_reason) {
1653 *reject_reason = SAMR_REJECT_TOO_SHORT;
1655 return NT_STATUS_PASSWORD_RESTRICTION;
1658 /* possibly check password complexity */
1659 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1660 !samdb_password_complexity_ok(new_pass)) {
1661 if (reject_reason) {
1662 *reject_reason = SAMR_REJECT_COMPLEXITY;
1664 return NT_STATUS_PASSWORD_RESTRICTION;
1667 /* compute the new nt and lm hashes */
1668 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1669 lmNewHash = &local_lmNewHash;
1671 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1672 /* If we can't convert this password to UCS2, then we should not accept it */
1673 if (reject_reason) {
1674 *reject_reason = SAMR_REJECT_OTHER;
1676 return NT_STATUS_PASSWORD_RESTRICTION;
1678 ntNewHash = &local_ntNewHash;
1682 /* are all password changes disallowed? */
1683 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1684 if (reject_reason) {
1685 *reject_reason = SAMR_REJECT_OTHER;
1687 return NT_STATUS_PASSWORD_RESTRICTION;
1690 /* can this user change password? */
1691 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1692 if (reject_reason) {
1693 *reject_reason = SAMR_REJECT_OTHER;
1695 return NT_STATUS_PASSWORD_RESTRICTION;
1698 /* yes, this is a minus. The ages are in negative 100nsec units! */
1699 if (pwdLastSet - minPwdAge > now_nt) {
1700 if (reject_reason) {
1701 *reject_reason = SAMR_REJECT_OTHER;
1703 return NT_STATUS_PASSWORD_RESTRICTION;
1706 /* check the immediately past password */
1707 if (pwdHistoryLength > 0) {
1708 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1709 if (reject_reason) {
1710 *reject_reason = SAMR_REJECT_IN_HISTORY;
1712 return NT_STATUS_PASSWORD_RESTRICTION;
1714 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1715 if (reject_reason) {
1716 *reject_reason = SAMR_REJECT_IN_HISTORY;
1718 return NT_STATUS_PASSWORD_RESTRICTION;
1722 /* check the password history */
1723 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1724 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1726 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1727 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1728 if (reject_reason) {
1729 *reject_reason = SAMR_REJECT_IN_HISTORY;
1731 return NT_STATUS_PASSWORD_RESTRICTION;
1734 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1735 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1736 if (reject_reason) {
1737 *reject_reason = SAMR_REJECT_IN_HISTORY;
1739 return NT_STATUS_PASSWORD_RESTRICTION;
1744 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1746 /* the password is acceptable. Start forming the new fields */
1748 /* if we know the cleartext, then only set it.
1749 * Modules in ldb will set all the appropriate
1751 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1752 "sambaPassword", new_pass));
1754 /* We don't have the cleartext, so delete the old one
1755 * and set what we have of the hashes */
1756 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1759 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1761 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1765 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1767 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1771 return NT_STATUS_OK;
1776 set the user password using plaintext, obeying any user or domain
1777 password restrictions
1779 This wrapper function takes a SID as input, rather than a user DN,
1780 and actually performs the password change
1783 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1784 const struct dom_sid *user_sid,
1785 const char *new_pass,
1786 struct samr_Password *lmNewHash,
1787 struct samr_Password *ntNewHash,
1789 enum samr_RejectReason *reject_reason,
1790 struct samr_DomInfo1 **_dominfo)
1793 struct ldb_dn *user_dn;
1794 struct ldb_message *msg;
1797 ret = ldb_transaction_start(ctx);
1799 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1800 return NT_STATUS_TRANSACTION_ABORTED;
1803 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1804 "(&(objectSid=%s)(objectClass=user))",
1805 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1807 ldb_transaction_cancel(ctx);
1808 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1809 dom_sid_string(mem_ctx, user_sid)));
1810 return NT_STATUS_NO_SUCH_USER;
1813 msg = ldb_msg_new(mem_ctx);
1815 ldb_transaction_cancel(ctx);
1816 return NT_STATUS_NO_MEMORY;
1819 msg->dn = ldb_dn_copy(msg, user_dn);
1821 ldb_transaction_cancel(ctx);
1822 return NT_STATUS_NO_MEMORY;
1825 nt_status = samdb_set_password(ctx, mem_ctx,
1828 lmNewHash, ntNewHash,
1829 user_change, /* This is a password set, not change */
1830 reject_reason, _dominfo);
1831 if (!NT_STATUS_IS_OK(nt_status)) {
1832 ldb_transaction_cancel(ctx);
1836 /* modify the samdb record */
1837 ret = samdb_replace(ctx, mem_ctx, msg);
1839 ldb_transaction_cancel(ctx);
1840 return NT_STATUS_ACCESS_DENIED;
1843 ret = ldb_transaction_commit(ctx);
1845 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1846 ldb_dn_get_linearized(msg->dn),
1847 ldb_errstring(ctx)));
1848 return NT_STATUS_TRANSACTION_ABORTED;
1850 return NT_STATUS_OK;
1853 /****************************************************************************
1854 Create the SID list for this user.
1855 ****************************************************************************/
1856 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1857 struct dom_sid *user_sid,
1858 struct dom_sid *group_sid,
1860 struct dom_sid **groupSIDs,
1861 bool is_authenticated,
1862 struct security_token **token)
1864 struct security_token *ptoken;
1868 ptoken = security_token_initialise(mem_ctx);
1869 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1871 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1872 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1874 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1875 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1876 ptoken->privilege_mask = 0;
1878 ptoken->sids[0] = ptoken->user_sid;
1879 ptoken->sids[1] = ptoken->group_sid;
1882 * Finally add the "standard" SIDs.
1883 * The only difference between guest and "anonymous"
1884 * is the addition of Authenticated_Users.
1886 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1887 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1888 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1889 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1890 ptoken->num_sids = 4;
1892 if (is_authenticated) {
1893 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1894 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1898 for (i = 0; i < n_groupSIDs; i++) {
1899 size_t check_sid_idx;
1900 for (check_sid_idx = 1;
1901 check_sid_idx < ptoken->num_sids;
1903 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1908 if (check_sid_idx == ptoken->num_sids) {
1909 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1913 /* setup the privilege mask for this token */
1914 status = samdb_privilege_setup(ptoken);
1915 if (!NT_STATUS_IS_OK(status)) {
1916 talloc_free(ptoken);
1920 security_token_debug(10, ptoken);
1924 return NT_STATUS_OK;
1928 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1929 struct dom_sid *sid, struct ldb_dn **ret_dn)
1931 struct ldb_message *msg;
1932 struct ldb_dn *basedn;
1936 sidstr = dom_sid_string(mem_ctx, sid);
1937 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1939 /* We might have to create a ForeignSecurityPrincipal, even if this user
1940 * is in our own domain */
1942 msg = ldb_msg_new(mem_ctx);
1944 return NT_STATUS_NO_MEMORY;
1947 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1948 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1949 * not work, this is wrong for the Builtin domain, there's no
1950 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1953 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1954 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1956 if (basedn == NULL) {
1957 DEBUG(0, ("Failed to find DN for "
1958 "ForeignSecurityPrincipal container\n"));
1959 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1962 /* add core elements to the ldb_message for the alias */
1963 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1964 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1965 return NT_STATUS_NO_MEMORY;
1967 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1969 "foreignSecurityPrincipal");
1971 /* create the alias */
1972 ret = ldb_add(sam_ctx, msg);
1974 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1976 ldb_dn_get_linearized(msg->dn),
1977 ldb_errstring(sam_ctx)));
1978 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1981 return NT_STATUS_OK;
1986 Find the DN of a domain, assuming it to be a dotted.dns name
1989 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1992 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1993 const char *binary_encoded;
1994 const char **split_realm;
2001 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
2003 talloc_free(tmp_ctx);
2006 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2007 for (i=0; split_realm[i]; i++) {
2008 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2009 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2010 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2011 binary_encoded, ldb_dn_get_linearized(dn)));
2012 talloc_free(tmp_ctx);
2016 if (!ldb_dn_validate(dn)) {
2017 DEBUG(2, ("Failed to validated DN %s\n",
2018 ldb_dn_get_linearized(dn)));
2024 Find the DN of a domain, be it the netbios or DNS name
2027 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2028 const char *domain_name)
2030 const char * const domain_ref_attrs[] = {
2033 const char * const domain_ref2_attrs[] = {
2036 struct ldb_result *res_domain_ref;
2037 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2038 /* find the domain's DN */
2039 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2041 samdb_partitions_dn(ldb, mem_ctx),
2044 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2046 if (ret_domain != 0) {
2050 if (res_domain_ref->count == 0) {
2051 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2053 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2056 "(objectclass=domain)");
2057 if (ret_domain != 0) {
2061 if (res_domain_ref->count == 1) {
2062 return res_domain_ref->msgs[0]->dn;
2067 if (res_domain_ref->count > 1) {
2068 DEBUG(0,("Found %d records matching domain [%s]\n",
2069 ret_domain, domain_name));
2073 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);