2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
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/>.
26 #include "ldb_errors.h"
27 #include "lib/util/util_ldb.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "libcli/security/security.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "dsdb/common/flags.h"
32 #include "dsdb/common/proto.h"
33 #include "libcli/ldap/ldap_ndr.h"
34 #include "libcli/auth/libcli_auth.h"
37 search the sam for the specified attributes in a specific domain, filter on
38 objectSid being in domain_sid.
40 int samdb_search_domain(struct ldb_context *sam_ldb,
42 struct ldb_dn *basedn,
43 struct ldb_message ***res,
44 const char * const *attrs,
45 const struct dom_sid *domain_sid,
46 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
52 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
53 res, attrs, format, ap);
59 struct dom_sid *entry_sid;
61 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
63 if ((entry_sid == NULL) ||
64 (!dom_sid_in_domain(domain_sid, entry_sid))) {
65 /* Delete that entry from the result set */
66 (*res)[i] = (*res)[count-1];
68 talloc_free(entry_sid);
71 talloc_free(entry_sid);
79 search the sam for a single string attribute in exactly 1 record
81 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
83 struct ldb_dn *basedn,
84 const char *attr_name,
85 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
88 const char *attrs[2] = { NULL, NULL };
89 struct ldb_message **res = NULL;
93 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
95 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
96 attr_name, format, count));
103 return samdb_result_string(res[0], attr_name, NULL);
108 search the sam for a single string attribute in exactly 1 record
110 const char *samdb_search_string(struct ldb_context *sam_ldb,
112 struct ldb_dn *basedn,
113 const char *attr_name,
114 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
119 va_start(ap, format);
120 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
126 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
128 struct ldb_dn *basedn,
129 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
133 struct ldb_message **res = NULL;
136 va_start(ap, format);
137 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
140 if (count != 1) return NULL;
142 ret = talloc_steal(mem_ctx, res[0]->dn);
149 search the sam for a dom_sid attribute in exactly 1 record
151 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
153 struct ldb_dn *basedn,
154 const char *attr_name,
155 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
159 struct ldb_message **res;
160 const char *attrs[2] = { NULL, NULL };
163 attrs[0] = attr_name;
165 va_start(ap, format);
166 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
169 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
170 attr_name, format, count));
176 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
182 return the count of the number of records in the sam matching the query
184 int samdb_search_count(struct ldb_context *sam_ldb,
186 struct ldb_dn *basedn,
187 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
190 struct ldb_message **res;
191 const char * const attrs[] = { NULL };
194 va_start(ap, format);
195 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
203 search the sam for a single integer attribute in exactly 1 record
205 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
207 uint_t default_value,
208 struct ldb_dn *basedn,
209 const char *attr_name,
210 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
214 struct ldb_message **res;
215 const char *attrs[2] = { NULL, NULL };
217 attrs[0] = attr_name;
219 va_start(ap, format);
220 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
224 return default_value;
227 return samdb_result_uint(res[0], attr_name, default_value);
231 search the sam for a single signed 64 bit integer attribute in exactly 1 record
233 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
235 int64_t default_value,
236 struct ldb_dn *basedn,
237 const char *attr_name,
238 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
242 struct ldb_message **res;
243 const char *attrs[2] = { NULL, NULL };
245 attrs[0] = attr_name;
247 va_start(ap, format);
248 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
252 return default_value;
255 return samdb_result_int64(res[0], attr_name, default_value);
259 search the sam for multipe records each giving a single string attribute
260 return the number of matches, or -1 on error
262 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
264 struct ldb_dn *basedn,
266 const char *attr_name,
267 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
271 const char *attrs[2] = { NULL, NULL };
272 struct ldb_message **res = NULL;
274 attrs[0] = attr_name;
276 va_start(ap, format);
277 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
284 /* make sure its single valued */
285 for (i=0;i<count;i++) {
286 if (res[i]->num_elements != 1) {
287 DEBUG(1,("samdb: search for %s %s not single valued\n",
294 *strs = talloc_array(mem_ctx, const char *, count+1);
300 for (i=0;i<count;i++) {
301 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
303 (*strs)[count] = NULL;
309 pull a uint from a result set.
311 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
313 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
317 pull a (signed) int64 from a result set.
319 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
321 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
325 pull a string from a result set.
327 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
328 const char *default_value)
330 return ldb_msg_find_attr_as_string(msg, attr, default_value);
333 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
334 const char *attr, struct ldb_dn *default_value)
336 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
338 return default_value;
344 pull a rid from a objectSid in a result set.
346 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
347 const char *attr, uint32_t default_value)
352 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
354 return default_value;
356 rid = sid->sub_auths[sid->num_auths-1];
362 pull a dom_sid structure from a objectSid in a result set.
364 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
367 const struct ldb_val *v;
369 enum ndr_err_code ndr_err;
370 v = ldb_msg_find_ldb_val(msg, attr);
374 sid = talloc(mem_ctx, struct dom_sid);
378 ndr_err = ndr_pull_struct_blob(v, sid, sid,
379 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
380 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
388 pull a guid structure from a objectGUID in a result set.
390 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
392 const struct ldb_val *v;
393 enum ndr_err_code ndr_err;
399 v = ldb_msg_find_ldb_val(msg, attr);
402 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
403 if (!mem_ctx) return guid;
404 ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid,
405 (ndr_pull_flags_fn_t)ndr_pull_GUID);
406 talloc_free(mem_ctx);
407 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
415 pull a sid prefix from a objectSid in a result set.
416 this is used to find the domain sid for a user
418 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
421 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
422 if (!sid || sid->num_auths < 1) return NULL;
428 pull a NTTIME in a result set.
430 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
432 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
436 pull a uint64_t from a result set.
438 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
440 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
445 construct the allow_password_change field from the PwdLastSet attribute and the
446 domain password settings
448 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
450 struct ldb_dn *domain_dn,
451 struct ldb_message *msg,
454 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
457 if (attr_time == 0) {
461 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
463 /* yes, this is a -= not a += as minPwdAge is stored as the negative
464 of the number of 100-nano-seconds */
465 attr_time -= minPwdAge;
471 construct the force_password_change field from the PwdLastSet attribute and the
472 domain password settings
474 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
476 struct ldb_dn *domain_dn,
477 struct ldb_message *msg)
479 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
480 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
483 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
484 return 0x7FFFFFFFFFFFFFFFULL;
487 if (attr_time == 0) {
491 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
492 if (maxPwdAge == 0) {
495 attr_time -= maxPwdAge;
502 pull a samr_Password structutre from a result set.
504 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
506 struct samr_Password *hash = NULL;
507 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
508 if (val && (val->length >= sizeof(hash->hash))) {
509 hash = talloc(mem_ctx, struct samr_Password);
510 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
516 pull an array of samr_Password structutres from a result set.
518 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
519 const char *attr, struct samr_Password **hashes)
522 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
529 count = val->length / 16;
534 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
539 for (i=0;i<count;i++) {
540 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
546 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
547 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
549 struct samr_Password *lmPwdHash, *ntPwdHash;
552 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
555 } else if (num_nt > 1) {
556 return NT_STATUS_INTERNAL_DB_CORRUPTION;
558 *nt_pwd = &ntPwdHash[0];
563 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
566 } else if (num_lm > 1) {
567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
569 *lm_pwd = &lmPwdHash[0];
576 pull a samr_LogonHours structutre from a result set.
578 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
580 struct samr_LogonHours hours;
581 const int units_per_week = 168;
582 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
584 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
588 hours.units_per_week = units_per_week;
589 memset(hours.bits, 0xFF, units_per_week);
591 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
597 pull a set of account_flags from a result set.
599 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
601 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
602 return samdb_uf2acb(userAccountControl);
606 /* Find an attribute, with a particular value */
608 /* The current callers of this function expect a very specific
609 * behaviour: In particular, objectClass subclass equivilance is not
610 * wanted. This means that we should not lookup the schema for the
611 * comparison function */
612 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
613 const struct ldb_message *msg,
614 const char *name, const char *value)
617 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
623 for (i=0;i<el->num_values;i++) {
624 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
632 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
634 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
635 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
640 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
642 struct ldb_message_element *el;
644 el = ldb_msg_find_element(msg, name);
649 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
655 add a string element to a message
657 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
658 const char *attr_name, const char *str)
660 char *s = talloc_strdup(mem_ctx, str);
661 char *a = talloc_strdup(mem_ctx, attr_name);
662 if (s == NULL || a == NULL) {
663 return LDB_ERR_OPERATIONS_ERROR;
665 return ldb_msg_add_string(msg, a, s);
669 add a dom_sid element to a message
671 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
672 const char *attr_name, struct dom_sid *sid)
675 enum ndr_err_code ndr_err;
677 ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid,
678 (ndr_push_flags_fn_t)ndr_push_dom_sid);
679 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
682 return ldb_msg_add_value(msg, attr_name, &v, NULL);
687 add a delete element operation to a message
689 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
690 const char *attr_name)
692 /* we use an empty replace rather than a delete, as it allows for
693 samdb_replace() to be used everywhere */
694 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
698 add a add attribute value to a message
700 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
701 const char *attr_name, const char *value)
703 struct ldb_message_element *el;
706 a = talloc_strdup(mem_ctx, attr_name);
709 v = talloc_strdup(mem_ctx, value);
712 ret = ldb_msg_add_string(msg, a, v);
715 el = ldb_msg_find_element(msg, a);
718 el->flags = LDB_FLAG_MOD_ADD;
723 add a delete attribute value to a message
725 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
726 const char *attr_name, const char *value)
728 struct ldb_message_element *el;
731 a = talloc_strdup(mem_ctx, attr_name);
734 v = talloc_strdup(mem_ctx, value);
737 ret = ldb_msg_add_string(msg, a, v);
740 el = ldb_msg_find_element(msg, a);
743 el->flags = LDB_FLAG_MOD_DELETE;
748 add a int element to a message
750 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
751 const char *attr_name, int v)
753 const char *s = talloc_asprintf(mem_ctx, "%d", v);
754 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
758 add a uint_t element to a message
760 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
761 const char *attr_name, uint_t v)
763 const char *s = talloc_asprintf(mem_ctx, "%u", v);
764 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
768 add a (signed) int64_t element to a message
770 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
771 const char *attr_name, int64_t v)
773 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
774 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
778 add a uint64_t element to a message
780 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
781 const char *attr_name, uint64_t v)
783 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
784 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
788 add a samr_Password element to a message
790 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
791 const char *attr_name, struct samr_Password *hash)
794 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
799 return ldb_msg_add_value(msg, attr_name, &val, NULL);
803 add a samr_Password array to a message
805 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
806 const char *attr_name, struct samr_Password *hashes, uint_t count)
810 val.data = talloc_array_size(mem_ctx, 16, count);
811 val.length = count*16;
815 for (i=0;i<count;i++) {
816 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
818 return ldb_msg_add_value(msg, attr_name, &val, NULL);
822 add a acct_flags element to a message
824 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
825 const char *attr_name, uint32_t v)
827 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
831 add a logon_hours element to a message
833 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
834 const char *attr_name, struct samr_LogonHours *hours)
837 val.length = hours->units_per_week / 8;
838 val.data = hours->bits;
839 return ldb_msg_add_value(msg, attr_name, &val, NULL);
843 add a general value element to a message
845 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846 const char *attr_name, const struct ldb_val *val)
848 return ldb_msg_add_value(msg, attr_name, val, NULL);
852 sets a general value element to a message
854 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
855 const char *attr_name, const struct ldb_val *val)
857 struct ldb_message_element *el;
859 el = ldb_msg_find_element(msg, attr_name);
863 return ldb_msg_add_value(msg, attr_name, val, NULL);
867 set a string element in a message
869 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
870 const char *attr_name, const char *str)
872 struct ldb_message_element *el;
874 el = ldb_msg_find_element(msg, attr_name);
878 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
882 replace elements in a record
884 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
888 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
889 for (i=0;i<msg->num_elements;i++) {
890 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
893 /* modify the samdb record */
894 return ldb_modify(sam_ldb, msg);
898 return a default security descriptor
900 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
902 struct security_descriptor *sd;
904 sd = security_descriptor_initialise(mem_ctx);
909 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
911 return ldb_get_default_basedn(sam_ctx);
914 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
916 return ldb_get_config_basedn(sam_ctx);
919 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
921 return ldb_get_schema_basedn(sam_ctx);
924 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
926 return ldb_get_root_basedn(sam_ctx);
929 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
931 struct ldb_dn *new_dn;
933 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
934 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
941 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
943 struct ldb_dn *new_dn;
945 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
946 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
954 work out the domain sid for the current open ldb
956 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
959 struct dom_sid *domain_sid;
961 /* see if we have a cached copy */
962 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
967 tmp_ctx = talloc_new(ldb);
968 if (tmp_ctx == NULL) {
972 /* find the domain_sid */
973 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
974 "objectSid", "objectClass=domainDNS");
975 if (domain_sid == NULL) {
979 /* cache the domain_sid in the ldb */
980 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
984 talloc_steal(ldb, domain_sid);
985 talloc_free(tmp_ctx);
990 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
991 talloc_free(tmp_ctx);
995 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
998 struct dom_sid *dom_sid_new;
999 struct dom_sid *dom_sid_old;
1001 /* see if we have a cached copy */
1002 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1003 "cache.domain_sid"), struct dom_sid);
1005 tmp_ctx = talloc_new(ldb);
1006 if (tmp_ctx == NULL) {
1010 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1015 /* cache the domain_sid in the ldb */
1016 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1020 talloc_steal(ldb, dom_sid_new);
1021 talloc_free(tmp_ctx);
1022 talloc_free(dom_sid_old);
1027 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1028 talloc_free(tmp_ctx);
1032 /* Obtain the short name of the flexible single master operator
1033 * (FSMO), such as the PDC Emulator */
1034 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1037 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1038 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1039 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1040 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1042 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1043 /* Ensure this matches the format. This gives us a
1044 * bit more confidence that a 'cn' value will be a
1049 return (char *)val->data;
1055 work out the ntds settings dn for the current open ldb
1057 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1059 TALLOC_CTX *tmp_ctx;
1060 const char *root_attrs[] = { "dsServiceName", NULL };
1062 struct ldb_result *root_res;
1063 struct ldb_dn *settings_dn;
1065 /* see if we have a cached copy */
1066 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1071 tmp_ctx = talloc_new(ldb);
1072 if (tmp_ctx == NULL) {
1077 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1079 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1080 ldb_errstring(ldb)));
1083 talloc_steal(tmp_ctx, root_res);
1085 if (root_res->count != 1) {
1089 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1091 /* cache the domain_sid in the ldb */
1092 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1096 talloc_steal(ldb, settings_dn);
1097 talloc_free(tmp_ctx);
1102 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1103 talloc_free(tmp_ctx);
1108 work out the ntds settings invocationId for the current open ldb
1110 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1112 TALLOC_CTX *tmp_ctx;
1113 const char *attrs[] = { "invocationId", NULL };
1115 struct ldb_result *res;
1116 struct GUID *invocation_id;
1118 /* see if we have a cached copy */
1119 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1120 if (invocation_id) {
1121 return invocation_id;
1124 tmp_ctx = talloc_new(ldb);
1125 if (tmp_ctx == NULL) {
1129 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1133 talloc_steal(tmp_ctx, res);
1135 if (res->count != 1) {
1139 invocation_id = talloc(tmp_ctx, struct GUID);
1140 if (!invocation_id) {
1144 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1146 /* cache the domain_sid in the ldb */
1147 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1151 talloc_steal(ldb, invocation_id);
1152 talloc_free(tmp_ctx);
1154 return invocation_id;
1157 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1158 talloc_free(tmp_ctx);
1162 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1164 TALLOC_CTX *tmp_ctx;
1165 struct GUID *invocation_id_new;
1166 struct GUID *invocation_id_old;
1168 /* see if we have a cached copy */
1169 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1170 "cache.invocation_id");
1172 tmp_ctx = talloc_new(ldb);
1173 if (tmp_ctx == NULL) {
1177 invocation_id_new = talloc(tmp_ctx, struct GUID);
1178 if (!invocation_id_new) {
1182 *invocation_id_new = *invocation_id_in;
1184 /* cache the domain_sid in the ldb */
1185 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1189 talloc_steal(ldb, invocation_id_new);
1190 talloc_free(tmp_ctx);
1191 talloc_free(invocation_id_old);
1196 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1197 talloc_free(tmp_ctx);
1202 work out the ntds settings objectGUID for the current open ldb
1204 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1206 TALLOC_CTX *tmp_ctx;
1207 const char *attrs[] = { "objectGUID", NULL };
1209 struct ldb_result *res;
1210 struct GUID *ntds_guid;
1212 /* see if we have a cached copy */
1213 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1218 tmp_ctx = talloc_new(ldb);
1219 if (tmp_ctx == NULL) {
1223 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1227 talloc_steal(tmp_ctx, res);
1229 if (res->count != 1) {
1233 ntds_guid = talloc(tmp_ctx, struct GUID);
1238 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1240 /* cache the domain_sid in the ldb */
1241 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1245 talloc_steal(ldb, ntds_guid);
1246 talloc_free(tmp_ctx);
1251 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1252 talloc_free(tmp_ctx);
1256 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1258 TALLOC_CTX *tmp_ctx;
1259 struct GUID *ntds_guid_new;
1260 struct GUID *ntds_guid_old;
1262 /* see if we have a cached copy */
1263 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1265 tmp_ctx = talloc_new(ldb);
1266 if (tmp_ctx == NULL) {
1270 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1271 if (!ntds_guid_new) {
1275 *ntds_guid_new = *ntds_guid_in;
1277 /* cache the domain_sid in the ldb */
1278 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1282 talloc_steal(ldb, ntds_guid_new);
1283 talloc_free(tmp_ctx);
1284 talloc_free(ntds_guid_old);
1289 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1290 talloc_free(tmp_ctx);
1295 work out the server dn for the current open ldb
1297 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1299 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1303 work out the server dn for the current open ldb
1305 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1307 struct ldb_dn *server_dn;
1308 struct ldb_dn *server_site_dn;
1310 server_dn = samdb_server_dn(ldb, mem_ctx);
1311 if (!server_dn) return NULL;
1313 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1315 talloc_free(server_dn);
1316 return server_site_dn;
1320 work out if we are the PDC for the domain of the current open ldb
1322 bool samdb_is_pdc(struct ldb_context *ldb)
1324 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1326 struct ldb_result *dom_res;
1327 TALLOC_CTX *tmp_ctx;
1331 tmp_ctx = talloc_new(ldb);
1332 if (tmp_ctx == NULL) {
1333 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1337 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1339 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1340 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1341 ldb_errstring(ldb)));
1344 talloc_steal(tmp_ctx, dom_res);
1345 if (dom_res->count != 1) {
1349 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1351 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1357 talloc_free(tmp_ctx);
1362 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1363 talloc_free(tmp_ctx);
1368 /* Find a domain object in the parents of a particular DN. */
1369 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1370 struct ldb_dn **parent_dn, const char **errstring)
1372 TALLOC_CTX *local_ctx;
1373 struct ldb_dn *sdn = dn;
1374 struct ldb_result *res = NULL;
1376 const char *attrs[] = { NULL };
1378 local_ctx = talloc_new(mem_ctx);
1379 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1381 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1382 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1383 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1384 if (ret == LDB_SUCCESS) {
1385 talloc_steal(local_ctx, res);
1386 if (res->count == 1) {
1394 if (ret != LDB_SUCCESS) {
1395 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1396 ldb_dn_get_linearized(dn),
1397 ldb_dn_get_linearized(sdn),
1398 ldb_errstring(ldb));
1399 talloc_free(local_ctx);
1402 if (res->count != 1) {
1403 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1404 ldb_dn_get_linearized(dn));
1405 talloc_free(local_ctx);
1406 return LDB_ERR_CONSTRAINT_VIOLATION;
1409 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1410 talloc_free(local_ctx);
1415 check that a password is sufficiently complex
1417 static bool samdb_password_complexity_ok(const char *pass)
1419 return check_password_quality(pass);
1425 set the user password using plaintext, obeying any user or domain
1426 password restrictions
1428 note that this function doesn't actually store the result in the
1429 database, it just fills in the "mod" structure with ldb modify
1430 elements to setup the correct change when samdb_replace() is
1431 called. This allows the caller to combine the change with other
1432 changes (as is needed by some of the set user info levels)
1434 The caller should probably have a transaction wrapping this
1436 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1437 struct ldb_dn *user_dn,
1438 struct ldb_dn *domain_dn,
1439 struct ldb_message *mod,
1440 const char *new_pass,
1441 struct samr_Password *lmNewHash,
1442 struct samr_Password *ntNewHash,
1444 enum samr_RejectReason *reject_reason,
1445 struct samr_DomInfo1 **_dominfo)
1447 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1449 "dBCSPwd", "unicodePwd",
1451 "pwdLastSet", NULL };
1452 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1453 "maxPwdAge", "minPwdAge",
1454 "minPwdLength", NULL };
1457 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1458 uint_t userAccountControl;
1459 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1460 struct samr_Password local_lmNewHash, local_ntNewHash;
1461 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1462 struct dom_sid *domain_sid;
1463 struct ldb_message **res;
1466 time_t now = time(NULL);
1470 /* we need to know the time to compute password age */
1471 unix_to_nt_time(&now_nt, now);
1473 /* pull all the user parameters */
1474 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1476 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1478 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1479 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1480 "lmPwdHistory", &sambaLMPwdHistory);
1481 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1482 "ntPwdHistory", &sambaNTPwdHistory);
1483 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1484 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1485 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1487 /* Only non-trust accounts have restrictions (possibly this
1488 * test is the wrong way around, but I like to be restrictive
1490 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1491 |UF_WORKSTATION_TRUST_ACCOUNT
1492 |UF_SERVER_TRUST_ACCOUNT));
1495 /* pull the domain parameters */
1496 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1498 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1499 ldb_dn_get_linearized(domain_dn),
1500 ldb_dn_get_linearized(user_dn)));
1501 return NT_STATUS_NO_SUCH_DOMAIN;
1504 /* work out the domain sid, and pull the domain from there */
1505 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1506 if (domain_sid == NULL) {
1507 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1510 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1512 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1514 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1515 dom_sid_string(mem_ctx, domain_sid),
1516 ldb_dn_get_linearized(user_dn)));
1517 return NT_STATUS_NO_SUCH_DOMAIN;
1521 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1522 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1523 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1524 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1527 struct samr_DomInfo1 *dominfo;
1528 /* on failure we need to fill in the reject reasons */
1529 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1530 if (dominfo == NULL) {
1531 return NT_STATUS_NO_MEMORY;
1533 dominfo->min_password_length = minPwdLength;
1534 dominfo->password_properties = pwdProperties;
1535 dominfo->password_history_length = pwdHistoryLength;
1536 dominfo->max_password_age = minPwdAge;
1537 dominfo->min_password_age = minPwdAge;
1538 *_dominfo = dominfo;
1541 if (restrictions && new_pass) {
1543 /* check the various password restrictions */
1544 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1545 if (reject_reason) {
1546 *reject_reason = SAMR_REJECT_TOO_SHORT;
1548 return NT_STATUS_PASSWORD_RESTRICTION;
1551 /* possibly check password complexity */
1552 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1553 !samdb_password_complexity_ok(new_pass)) {
1554 if (reject_reason) {
1555 *reject_reason = SAMR_REJECT_COMPLEXITY;
1557 return NT_STATUS_PASSWORD_RESTRICTION;
1560 /* compute the new nt and lm hashes */
1561 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1562 lmNewHash = &local_lmNewHash;
1564 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1565 /* If we can't convert this password to UCS2, then we should not accept it */
1566 if (reject_reason) {
1567 *reject_reason = SAMR_REJECT_OTHER;
1569 return NT_STATUS_PASSWORD_RESTRICTION;
1571 ntNewHash = &local_ntNewHash;
1575 /* are all password changes disallowed? */
1576 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1577 if (reject_reason) {
1578 *reject_reason = SAMR_REJECT_OTHER;
1580 return NT_STATUS_PASSWORD_RESTRICTION;
1583 /* can this user change password? */
1584 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1585 if (reject_reason) {
1586 *reject_reason = SAMR_REJECT_OTHER;
1588 return NT_STATUS_PASSWORD_RESTRICTION;
1591 /* yes, this is a minus. The ages are in negative 100nsec units! */
1592 if (pwdLastSet - minPwdAge > now_nt) {
1593 if (reject_reason) {
1594 *reject_reason = SAMR_REJECT_OTHER;
1596 return NT_STATUS_PASSWORD_RESTRICTION;
1599 /* check the immediately past password */
1600 if (pwdHistoryLength > 0) {
1601 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1602 if (reject_reason) {
1603 *reject_reason = SAMR_REJECT_IN_HISTORY;
1605 return NT_STATUS_PASSWORD_RESTRICTION;
1607 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1608 if (reject_reason) {
1609 *reject_reason = SAMR_REJECT_IN_HISTORY;
1611 return NT_STATUS_PASSWORD_RESTRICTION;
1615 /* check the password history */
1616 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1617 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1619 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1620 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1621 if (reject_reason) {
1622 *reject_reason = SAMR_REJECT_IN_HISTORY;
1624 return NT_STATUS_PASSWORD_RESTRICTION;
1627 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1628 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1629 if (reject_reason) {
1630 *reject_reason = SAMR_REJECT_IN_HISTORY;
1632 return NT_STATUS_PASSWORD_RESTRICTION;
1637 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1639 /* the password is acceptable. Start forming the new fields */
1641 /* if we know the cleartext, then only set it.
1642 * Modules in ldb will set all the appropriate
1644 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1645 "sambaPassword", new_pass));
1647 /* We don't have the cleartext, so delete the old one
1648 * and set what we have of the hashes */
1649 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1652 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1654 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1658 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1660 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1664 return NT_STATUS_OK;
1669 set the user password using plaintext, obeying any user or domain
1670 password restrictions
1672 This wrapper function takes a SID as input, rather than a user DN,
1673 and actually performs the password change
1676 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1677 const struct dom_sid *user_sid,
1678 const char *new_pass,
1679 struct samr_Password *lmNewHash,
1680 struct samr_Password *ntNewHash,
1682 enum samr_RejectReason *reject_reason,
1683 struct samr_DomInfo1 **_dominfo)
1686 struct ldb_dn *user_dn;
1687 struct ldb_message *msg;
1690 ret = ldb_transaction_start(ctx);
1692 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1693 return NT_STATUS_TRANSACTION_ABORTED;
1696 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1697 "(&(objectSid=%s)(objectClass=user))",
1698 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1700 ldb_transaction_cancel(ctx);
1701 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1702 dom_sid_string(mem_ctx, user_sid)));
1703 return NT_STATUS_NO_SUCH_USER;
1706 msg = ldb_msg_new(mem_ctx);
1708 ldb_transaction_cancel(ctx);
1709 return NT_STATUS_NO_MEMORY;
1712 msg->dn = ldb_dn_copy(msg, user_dn);
1714 ldb_transaction_cancel(ctx);
1715 return NT_STATUS_NO_MEMORY;
1718 nt_status = samdb_set_password(ctx, mem_ctx,
1721 lmNewHash, ntNewHash,
1722 user_change, /* This is a password set, not change */
1723 reject_reason, _dominfo);
1724 if (!NT_STATUS_IS_OK(nt_status)) {
1725 ldb_transaction_cancel(ctx);
1729 /* modify the samdb record */
1730 ret = samdb_replace(ctx, mem_ctx, msg);
1732 ldb_transaction_cancel(ctx);
1733 return NT_STATUS_ACCESS_DENIED;
1736 ret = ldb_transaction_commit(ctx);
1738 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1739 ldb_dn_get_linearized(msg->dn),
1740 ldb_errstring(ctx)));
1741 return NT_STATUS_TRANSACTION_ABORTED;
1743 return NT_STATUS_OK;
1748 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1749 struct dom_sid *sid, struct ldb_dn **ret_dn)
1751 struct ldb_message *msg;
1752 struct ldb_dn *basedn;
1756 sidstr = dom_sid_string(mem_ctx, sid);
1757 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1759 /* We might have to create a ForeignSecurityPrincipal, even if this user
1760 * is in our own domain */
1762 msg = ldb_msg_new(mem_ctx);
1764 return NT_STATUS_NO_MEMORY;
1767 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1768 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1769 * not work, this is wrong for the Builtin domain, there's no
1770 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1773 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1774 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1776 if (basedn == NULL) {
1777 DEBUG(0, ("Failed to find DN for "
1778 "ForeignSecurityPrincipal container\n"));
1779 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1782 /* add core elements to the ldb_message for the alias */
1783 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1784 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1785 return NT_STATUS_NO_MEMORY;
1787 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1789 "foreignSecurityPrincipal");
1791 /* create the alias */
1792 ret = ldb_add(sam_ctx, msg);
1794 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1796 ldb_dn_get_linearized(msg->dn),
1797 ldb_errstring(sam_ctx)));
1798 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1801 return NT_STATUS_OK;
1806 Find the DN of a domain, assuming it to be a dotted.dns name
1809 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1812 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1813 const char *binary_encoded;
1814 const char **split_realm;
1821 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1823 talloc_free(tmp_ctx);
1826 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1827 for (i=0; split_realm[i]; i++) {
1828 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1829 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1830 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1831 binary_encoded, ldb_dn_get_linearized(dn)));
1832 talloc_free(tmp_ctx);
1836 if (!ldb_dn_validate(dn)) {
1837 DEBUG(2, ("Failed to validated DN %s\n",
1838 ldb_dn_get_linearized(dn)));
1844 Find the DN of a domain, be it the netbios or DNS name
1847 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1848 const char *domain_name)
1850 const char * const domain_ref_attrs[] = {
1853 const char * const domain_ref2_attrs[] = {
1856 struct ldb_result *res_domain_ref;
1857 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1858 /* find the domain's DN */
1859 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1861 samdb_partitions_dn(ldb, mem_ctx),
1864 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1866 if (ret_domain != 0) {
1870 if (res_domain_ref->count == 0) {
1871 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1873 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1876 "(objectclass=domain)");
1877 if (ret_domain != 0) {
1881 if (res_domain_ref->count == 1) {
1882 return res_domain_ref->msgs[0]->dn;
1887 if (res_domain_ref->count > 1) {
1888 DEBUG(0,("Found %d records matching domain [%s]\n",
1889 ret_domain, domain_name));
1893 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);