2 Unix SMB/CIFS implementation.
4 interface functions for the sam database
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "librpc/gen_ndr/ndr_netlogon.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "libcli/security/security.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "libcli/ldap/ldap.h"
33 #include "system/time.h"
34 #include "system/filesys.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/common/flags.h"
40 connect to the SAM database
41 return an opaque context pointer on success, or NULL on failure
43 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
44 struct auth_session_info *session_info)
46 struct ldb_context *ldb;
47 ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
52 dsdb_make_schema_global(ldb);
57 search the sam for the specified attributes in a specific domain, filter on
58 objectSid being in domain_sid.
60 int samdb_search_domain(struct ldb_context *sam_ldb,
62 struct ldb_dn *basedn,
63 struct ldb_message ***res,
64 const char * const *attrs,
65 const struct dom_sid *domain_sid,
66 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
72 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73 res, attrs, format, ap);
79 struct dom_sid *entry_sid;
81 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
83 if ((entry_sid == NULL) ||
84 (!dom_sid_in_domain(domain_sid, entry_sid))) {
85 /* Delete that entry from the result set */
86 (*res)[i] = (*res)[count-1];
88 talloc_free(entry_sid);
91 talloc_free(entry_sid);
99 search the sam for a single string attribute in exactly 1 record
101 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
103 struct ldb_dn *basedn,
104 const char *attr_name,
105 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
108 const char *attrs[2] = { NULL, NULL };
109 struct ldb_message **res = NULL;
111 attrs[0] = attr_name;
113 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
115 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
116 attr_name, format, count));
123 return samdb_result_string(res[0], attr_name, NULL);
128 search the sam for a single string attribute in exactly 1 record
130 const char *samdb_search_string(struct ldb_context *sam_ldb,
132 struct ldb_dn *basedn,
133 const char *attr_name,
134 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
139 va_start(ap, format);
140 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
148 struct ldb_dn *basedn,
149 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
153 struct ldb_message **res = NULL;
156 va_start(ap, format);
157 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
160 if (count != 1) return NULL;
162 ret = talloc_steal(mem_ctx, res[0]->dn);
169 search the sam for a dom_sid attribute in exactly 1 record
171 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
173 struct ldb_dn *basedn,
174 const char *attr_name,
175 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
179 struct ldb_message **res;
180 const char *attrs[2] = { NULL, NULL };
183 attrs[0] = attr_name;
185 va_start(ap, format);
186 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
189 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
190 attr_name, format, count));
196 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
202 return the count of the number of records in the sam matching the query
204 int samdb_search_count(struct ldb_context *sam_ldb,
206 struct ldb_dn *basedn,
207 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
210 struct ldb_message **res;
211 const char * const attrs[] = { NULL };
214 va_start(ap, format);
215 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
223 search the sam for a single integer attribute in exactly 1 record
225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
227 uint_t default_value,
228 struct ldb_dn *basedn,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
234 struct ldb_message **res;
235 const char *attrs[2] = { NULL, NULL };
237 attrs[0] = attr_name;
239 va_start(ap, format);
240 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
244 return default_value;
247 return samdb_result_uint(res[0], attr_name, default_value);
251 search the sam for a single signed 64 bit integer attribute in exactly 1 record
253 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
255 int64_t default_value,
256 struct ldb_dn *basedn,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
262 struct ldb_message **res;
263 const char *attrs[2] = { NULL, NULL };
265 attrs[0] = attr_name;
267 va_start(ap, format);
268 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
272 return default_value;
275 return samdb_result_int64(res[0], attr_name, default_value);
279 search the sam for multipe records each giving a single string attribute
280 return the number of matches, or -1 on error
282 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
284 struct ldb_dn *basedn,
286 const char *attr_name,
287 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
291 const char *attrs[2] = { NULL, NULL };
292 struct ldb_message **res = NULL;
294 attrs[0] = attr_name;
296 va_start(ap, format);
297 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
304 /* make sure its single valued */
305 for (i=0;i<count;i++) {
306 if (res[i]->num_elements != 1) {
307 DEBUG(1,("samdb: search for %s %s not single valued\n",
314 *strs = talloc_array(mem_ctx, const char *, count+1);
320 for (i=0;i<count;i++) {
321 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
323 (*strs)[count] = NULL;
329 pull a uint from a result set.
331 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
333 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
337 pull a (signed) int64 from a result set.
339 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
341 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
345 pull a string from a result set.
347 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
348 const char *default_value)
350 return ldb_msg_find_attr_as_string(msg, attr, default_value);
353 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354 const char *attr, struct ldb_dn *default_value)
356 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
358 return default_value;
364 pull a rid from a objectSid in a result set.
366 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
367 const char *attr, uint32_t default_value)
372 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
374 return default_value;
376 rid = sid->sub_auths[sid->num_auths-1];
382 pull a dom_sid structure from a objectSid in a result set.
384 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
387 const struct ldb_val *v;
390 v = ldb_msg_find_ldb_val(msg, attr);
394 sid = talloc(mem_ctx, struct dom_sid);
398 status = ndr_pull_struct_blob(v, sid, sid,
399 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
400 if (!NT_STATUS_IS_OK(status)) {
408 pull a guid structure from a objectGUID in a result set.
410 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
412 const struct ldb_val *v;
419 v = ldb_msg_find_ldb_val(msg, attr);
422 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
423 if (!mem_ctx) return guid;
424 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
425 (ndr_pull_flags_fn_t)ndr_pull_GUID);
426 talloc_free(mem_ctx);
427 if (!NT_STATUS_IS_OK(status)) {
435 pull a sid prefix from a objectSid in a result set.
436 this is used to find the domain sid for a user
438 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
441 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
442 if (!sid || sid->num_auths < 1) return NULL;
448 pull a NTTIME in a result set.
450 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
452 const char *str = ldb_msg_find_attr_as_string(msg, attr, NULL);
453 if (!str) return default_value;
454 return nttime_from_string(str);
458 pull a uint64_t from a result set.
460 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
462 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
467 construct the allow_password_change field from the PwdLastSet attribute and the
468 domain password settings
470 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
472 struct ldb_dn *domain_dn,
473 struct ldb_message *msg,
476 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
479 if (attr_time == 0) {
483 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
485 /* yes, this is a -= not a += as minPwdAge is stored as the negative
486 of the number of 100-nano-seconds */
487 attr_time -= minPwdAge;
493 construct the force_password_change field from the PwdLastSet attribute and the
494 domain password settings
496 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
498 struct ldb_dn *domain_dn,
499 struct ldb_message *msg)
501 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
502 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
505 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
506 return 0x7FFFFFFFFFFFFFFFULL;
509 if (attr_time == 0) {
513 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
514 if (maxPwdAge == 0) {
517 attr_time -= maxPwdAge;
524 pull a samr_Password structutre from a result set.
526 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
528 struct samr_Password *hash = NULL;
529 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
530 if (val && (val->length >= sizeof(hash->hash))) {
531 hash = talloc(mem_ctx, struct samr_Password);
532 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
538 pull an array of samr_Password structutres from a result set.
540 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
541 const char *attr, struct samr_Password **hashes)
544 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
551 count = val->length / 16;
556 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
561 for (i=0;i<count;i++) {
562 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
568 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
569 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
571 struct samr_Password *lmPwdHash, *ntPwdHash;
574 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
577 } else if (num_nt > 1) {
578 return NT_STATUS_INTERNAL_DB_CORRUPTION;
580 *nt_pwd = &ntPwdHash[0];
585 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
588 } else if (num_lm > 1) {
589 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591 *lm_pwd = &lmPwdHash[0];
598 pull a samr_LogonHours structutre from a result set.
600 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
602 struct samr_LogonHours hours;
603 const int units_per_week = 168;
604 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
606 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
610 hours.units_per_week = units_per_week;
611 memset(hours.bits, 0xFF, units_per_week);
613 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
619 pull a set of account_flags from a result set.
621 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
623 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
624 return samdb_uf2acb(userAccountControl);
628 /* Find an attribute, with a particular value */
630 /* The current callers of this function expect a very specific
631 * behaviour: In particular, objectClass subclass equivilance is not
632 * wanted. This means that we should not lookup the schema for the
633 * comparison function */
634 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
635 const struct ldb_message *msg,
636 const char *name, const char *value)
639 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
642 v.data = discard_const_p(uint8_t, value);
643 v.length = strlen(value);
649 for (i=0;i<el->num_values;i++) {
650 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
658 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
660 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
661 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
666 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
668 struct ldb_message_element *el;
670 el = ldb_msg_find_element(msg, name);
675 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
680 copy from a template record to a message
682 int samdb_copy_template(struct ldb_context *ldb,
683 struct ldb_message *msg, const char *filter,
684 const char **errstring)
686 struct ldb_result *res;
687 struct ldb_message *t;
689 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
693 /* pull the template record */
694 ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
696 if (ret != LDB_SUCCESS) {
697 *errstring = talloc_steal(msg, ldb_errstring(ldb));
700 if (res->count != 1) {
701 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
704 return LDB_ERR_OPERATIONS_ERROR;
708 for (i = 0; i < t->num_elements; i++) {
709 struct ldb_message_element *el = &t->elements[i];
710 /* some elements should not be copied from the template */
711 if (strcasecmp(el->name, "cn") == 0 ||
712 strcasecmp(el->name, "name") == 0 ||
713 strcasecmp(el->name, "sAMAccountName") == 0 ||
714 strcasecmp(el->name, "sAMAccountName") == 0 ||
715 strcasecmp(el->name, "distinguishedName") == 0 ||
716 strcasecmp(el->name, "objectGUID") == 0) {
719 for (j = 0; j < el->num_values; j++) {
720 if (strcasecmp(el->name, "objectClass") == 0) {
721 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
722 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
723 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
724 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
725 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
726 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
727 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
730 ret = samdb_find_or_add_value(ldb, msg, el->name,
731 (char *)el->values[j].data);
733 *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
738 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
739 (char *)el->values[j].data);
741 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
756 add a string element to a message
758 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
759 const char *attr_name, const char *str)
761 char *s = talloc_strdup(mem_ctx, str);
762 char *a = talloc_strdup(mem_ctx, attr_name);
763 if (s == NULL || a == NULL) {
764 return LDB_ERR_OPERATIONS_ERROR;
766 return ldb_msg_add_string(msg, a, s);
770 add a dom_sid element to a message
772 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
773 const char *attr_name, struct dom_sid *sid)
777 status = ndr_push_struct_blob(&v, mem_ctx, sid,
778 (ndr_push_flags_fn_t)ndr_push_dom_sid);
779 if (!NT_STATUS_IS_OK(status)) {
782 return ldb_msg_add_value(msg, attr_name, &v, NULL);
787 add a delete element operation to a message
789 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
790 const char *attr_name)
792 /* we use an empty replace rather than a delete, as it allows for
793 samdb_replace() to be used everywhere */
794 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
798 add a add attribute value to a message
800 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
801 const char *attr_name, const char *value)
803 struct ldb_message_element *el;
806 a = talloc_strdup(mem_ctx, attr_name);
809 v = talloc_strdup(mem_ctx, value);
812 ret = ldb_msg_add_string(msg, a, v);
815 el = ldb_msg_find_element(msg, a);
818 el->flags = LDB_FLAG_MOD_ADD;
823 add a delete attribute value to a message
825 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
826 const char *attr_name, const char *value)
828 struct ldb_message_element *el;
831 a = talloc_strdup(mem_ctx, attr_name);
834 v = talloc_strdup(mem_ctx, value);
837 ret = ldb_msg_add_string(msg, a, v);
840 el = ldb_msg_find_element(msg, a);
843 el->flags = LDB_FLAG_MOD_DELETE;
848 add a int element to a message
850 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
851 const char *attr_name, int v)
853 const char *s = talloc_asprintf(mem_ctx, "%d", v);
854 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
858 add a uint_t element to a message
860 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
861 const char *attr_name, uint_t v)
863 const char *s = talloc_asprintf(mem_ctx, "%u", v);
864 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
868 add a (signed) int64_t element to a message
870 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
871 const char *attr_name, int64_t v)
873 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
874 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
878 add a uint64_t element to a message
880 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
881 const char *attr_name, uint64_t v)
883 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
884 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
888 add a samr_Password element to a message
890 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891 const char *attr_name, struct samr_Password *hash)
894 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
899 return ldb_msg_add_value(msg, attr_name, &val, NULL);
903 add a samr_Password array to a message
905 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
906 const char *attr_name, struct samr_Password *hashes, uint_t count)
910 val.data = talloc_array_size(mem_ctx, 16, count);
911 val.length = count*16;
915 for (i=0;i<count;i++) {
916 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
918 return ldb_msg_add_value(msg, attr_name, &val, NULL);
922 add a acct_flags element to a message
924 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
925 const char *attr_name, uint32_t v)
927 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
931 add a logon_hours element to a message
933 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
934 const char *attr_name, struct samr_LogonHours *hours)
937 val.length = hours->units_per_week / 8;
938 val.data = hours->bits;
939 return ldb_msg_add_value(msg, attr_name, &val, NULL);
943 add a general value element to a message
945 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
946 const char *attr_name, const struct ldb_val *val)
948 return ldb_msg_add_value(msg, attr_name, val, NULL);
952 sets a general value element to a message
954 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955 const char *attr_name, const struct ldb_val *val)
957 struct ldb_message_element *el;
959 el = ldb_msg_find_element(msg, attr_name);
963 return ldb_msg_add_value(msg, attr_name, val, NULL);
967 set a string element in a message
969 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970 const char *attr_name, const char *str)
972 struct ldb_message_element *el;
974 el = ldb_msg_find_element(msg, attr_name);
978 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
984 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
986 return ldb_add(sam_ldb, msg);
992 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
994 return ldb_delete(sam_ldb, dn);
1000 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1002 return ldb_modify(sam_ldb, msg);
1006 replace elements in a record
1008 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1012 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1013 for (i=0;i<msg->num_elements;i++) {
1014 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1017 /* modify the samdb record */
1018 return samdb_modify(sam_ldb, mem_ctx, msg);
1022 return a default security descriptor
1024 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1026 struct security_descriptor *sd;
1028 sd = security_descriptor_initialise(mem_ctx);
1033 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1035 return ldb_get_default_basedn(sam_ctx);
1038 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1040 return ldb_get_config_basedn(sam_ctx);
1043 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1045 return ldb_get_schema_basedn(sam_ctx);
1048 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1050 return ldb_get_root_basedn(sam_ctx);
1053 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1055 struct ldb_dn *new_dn;
1057 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1058 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1059 talloc_free(new_dn);
1065 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1067 struct ldb_dn *new_dn;
1069 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1070 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1071 talloc_free(new_dn);
1078 work out the domain sid for the current open ldb
1080 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1082 TALLOC_CTX *tmp_ctx;
1083 struct dom_sid *domain_sid;
1085 /* see if we have a cached copy */
1086 domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1091 tmp_ctx = talloc_new(ldb);
1092 if (tmp_ctx == NULL) {
1096 /* find the domain_sid */
1097 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1098 "objectSid", "objectClass=domainDNS");
1099 if (domain_sid == NULL) {
1103 /* cache the domain_sid in the ldb */
1104 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1108 talloc_steal(ldb, domain_sid);
1109 talloc_free(tmp_ctx);
1114 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1115 talloc_free(tmp_ctx);
1119 /* Obtain the short name of the flexible single master operator
1120 * (FSMO), such as the PDC Emulator */
1121 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1124 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1125 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1126 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1127 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1129 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1130 /* Ensure this matches the format. This gives us a
1131 * bit more confidence that a 'cn' value will be a
1136 return (char *)val->data;
1142 work out the ntds settings dn for the current open ldb
1144 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1146 TALLOC_CTX *tmp_ctx;
1147 const char *root_attrs[] = { "dsServiceName", NULL };
1149 struct ldb_result *root_res;
1150 struct ldb_dn *settings_dn;
1152 /* see if we have a cached copy */
1153 settings_dn = ldb_get_opaque(ldb, "cache.settings_dn");
1158 tmp_ctx = talloc_new(ldb);
1159 if (tmp_ctx == NULL) {
1164 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1166 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1167 ldb_errstring(ldb)));
1170 talloc_steal(tmp_ctx, root_res);
1172 if (root_res->count != 1) {
1176 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1178 /* cache the domain_sid in the ldb */
1179 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1183 talloc_steal(ldb, settings_dn);
1184 talloc_free(tmp_ctx);
1189 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1190 talloc_free(tmp_ctx);
1195 work out the ntds settings invocationId for the current open ldb
1197 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1199 TALLOC_CTX *tmp_ctx;
1200 const char *attrs[] = { "invocationId", NULL };
1202 struct ldb_result *res;
1203 struct GUID *invocation_id;
1205 /* see if we have a cached copy */
1206 invocation_id = ldb_get_opaque(ldb, "cache.invocation_id");
1207 if (invocation_id) {
1208 return invocation_id;
1211 tmp_ctx = talloc_new(ldb);
1212 if (tmp_ctx == NULL) {
1216 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1220 talloc_steal(tmp_ctx, res);
1222 if (res->count != 1) {
1226 invocation_id = talloc(tmp_ctx, struct GUID);
1227 if (!invocation_id) {
1231 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1233 /* cache the domain_sid in the ldb */
1234 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1238 talloc_steal(ldb, invocation_id);
1239 talloc_free(tmp_ctx);
1241 return invocation_id;
1244 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1245 talloc_free(tmp_ctx);
1249 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1251 TALLOC_CTX *tmp_ctx;
1252 struct GUID *invocation_id_new;
1253 struct GUID *invocation_id_old;
1255 /* see if we have a cached copy */
1256 invocation_id_old = ldb_get_opaque(ldb, "cache.invocation_id");
1258 tmp_ctx = talloc_new(ldb);
1259 if (tmp_ctx == NULL) {
1263 invocation_id_new = talloc(tmp_ctx, struct GUID);
1264 if (!invocation_id_new) {
1268 *invocation_id_new = *invocation_id_in;
1270 /* cache the domain_sid in the ldb */
1271 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1275 talloc_steal(ldb, invocation_id_new);
1276 talloc_free(tmp_ctx);
1277 talloc_free(invocation_id_old);
1282 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1283 talloc_free(tmp_ctx);
1288 work out the ntds settings objectGUID for the current open ldb
1290 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1292 TALLOC_CTX *tmp_ctx;
1293 const char *attrs[] = { "objectGUID", NULL };
1295 struct ldb_result *res;
1296 struct GUID *ntds_guid;
1298 /* see if we have a cached copy */
1299 ntds_guid = ldb_get_opaque(ldb, "cache.ntds_guid");
1304 tmp_ctx = talloc_new(ldb);
1305 if (tmp_ctx == NULL) {
1309 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1313 talloc_steal(tmp_ctx, res);
1315 if (res->count != 1) {
1319 ntds_guid = talloc(tmp_ctx, struct GUID);
1324 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1326 /* cache the domain_sid in the ldb */
1327 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1331 talloc_steal(ldb, ntds_guid);
1332 talloc_free(tmp_ctx);
1337 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1338 talloc_free(tmp_ctx);
1342 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1344 TALLOC_CTX *tmp_ctx;
1345 struct GUID *ntds_guid_new;
1346 struct GUID *ntds_guid_old;
1348 /* see if we have a cached copy */
1349 ntds_guid_old = ldb_get_opaque(ldb, "cache.ntds_guid");
1351 tmp_ctx = talloc_new(ldb);
1352 if (tmp_ctx == NULL) {
1356 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1357 if (!ntds_guid_new) {
1361 *ntds_guid_new = *ntds_guid_in;
1363 /* cache the domain_sid in the ldb */
1364 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1368 talloc_steal(ldb, ntds_guid_new);
1369 talloc_free(tmp_ctx);
1370 talloc_free(ntds_guid_old);
1375 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1376 talloc_free(tmp_ctx);
1381 work out the server dn for the current open ldb
1383 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1385 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1389 work out the server dn for the current open ldb
1391 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1393 struct ldb_dn *server_dn;
1394 struct ldb_dn *server_site_dn;
1396 server_dn = samdb_server_dn(ldb, mem_ctx);
1397 if (!server_dn) return NULL;
1399 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1401 talloc_free(server_dn);
1402 return server_site_dn;
1406 work out if we are the PDC for the domain of the current open ldb
1408 BOOL samdb_is_pdc(struct ldb_context *ldb)
1410 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1412 struct ldb_result *dom_res;
1413 TALLOC_CTX *tmp_ctx;
1417 tmp_ctx = talloc_new(ldb);
1418 if (tmp_ctx == NULL) {
1419 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1423 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1425 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1426 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1427 ldb_errstring(ldb)));
1430 talloc_steal(tmp_ctx, dom_res);
1431 if (dom_res->count != 1) {
1435 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1437 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1443 talloc_free(tmp_ctx);
1448 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1449 talloc_free(tmp_ctx);
1454 /* Find a domain object in the parents of a particular DN. */
1455 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1457 TALLOC_CTX *local_ctx;
1458 struct ldb_dn *sdn = dn;
1459 struct ldb_result *res = NULL;
1461 const char *attrs[] = { NULL };
1463 local_ctx = talloc_new(mem_ctx);
1464 if (local_ctx == NULL) return NULL;
1466 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1467 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1468 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1469 if (ret == LDB_SUCCESS) {
1470 talloc_steal(local_ctx, res);
1471 if (res->count == 1) {
1477 if (ret != LDB_SUCCESS || res->count != 1) {
1478 talloc_free(local_ctx);
1482 talloc_steal(mem_ctx, sdn);
1483 talloc_free(local_ctx);
1489 check that a password is sufficiently complex
1491 static BOOL samdb_password_complexity_ok(const char *pass)
1493 return check_password_quality(pass);
1499 set the user password using plaintext, obeying any user or domain
1500 password restrictions
1502 note that this function doesn't actually store the result in the
1503 database, it just fills in the "mod" structure with ldb modify
1504 elements to setup the correct change when samdb_replace() is
1505 called. This allows the caller to combine the change with other
1506 changes (as is needed by some of the set user info levels)
1508 The caller should probably have a transaction wrapping this
1510 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1511 struct ldb_dn *user_dn,
1512 struct ldb_dn *domain_dn,
1513 struct ldb_message *mod,
1514 const char *new_pass,
1515 struct samr_Password *lmNewHash,
1516 struct samr_Password *ntNewHash,
1519 enum samr_RejectReason *reject_reason,
1520 struct samr_DomInfo1 **_dominfo)
1522 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1524 "dBCSPwd", "unicodePwd",
1526 "pwdLastSet", NULL };
1527 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1528 "maxPwdAge", "minPwdAge",
1529 "minPwdLength", NULL };
1532 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1533 uint_t userAccountControl;
1534 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1535 struct samr_Password local_lmNewHash, local_ntNewHash;
1536 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1537 struct dom_sid *domain_sid;
1538 struct ldb_message **res;
1540 time_t now = time(NULL);
1544 /* we need to know the time to compute password age */
1545 unix_to_nt_time(&now_nt, now);
1547 /* pull all the user parameters */
1548 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1550 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1552 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1553 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1554 "lmPwdHistory", &sambaLMPwdHistory);
1555 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1556 "ntPwdHistory", &sambaNTPwdHistory);
1557 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1558 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1559 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1562 /* pull the domain parameters */
1563 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1565 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1566 ldb_dn_get_linearized(domain_dn),
1567 ldb_dn_get_linearized(user_dn)));
1568 return NT_STATUS_NO_SUCH_DOMAIN;
1571 /* work out the domain sid, and pull the domain from there */
1572 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1573 if (domain_sid == NULL) {
1574 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1577 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1579 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1581 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1582 dom_sid_string(mem_ctx, domain_sid),
1583 ldb_dn_get_linearized(user_dn)));
1584 return NT_STATUS_NO_SUCH_DOMAIN;
1588 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1589 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1590 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1591 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1594 struct samr_DomInfo1 *dominfo;
1595 /* on failure we need to fill in the reject reasons */
1596 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1597 if (dominfo == NULL) {
1598 return NT_STATUS_NO_MEMORY;
1600 dominfo->min_password_length = minPwdLength;
1601 dominfo->password_properties = pwdProperties;
1602 dominfo->password_history_length = pwdHistoryLength;
1603 dominfo->max_password_age = minPwdAge;
1604 dominfo->min_password_age = minPwdAge;
1605 *_dominfo = dominfo;
1609 /* check the various password restrictions */
1610 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1611 if (reject_reason) {
1612 *reject_reason = SAMR_REJECT_TOO_SHORT;
1614 return NT_STATUS_PASSWORD_RESTRICTION;
1617 /* possibly check password complexity */
1618 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1619 !samdb_password_complexity_ok(new_pass)) {
1620 if (reject_reason) {
1621 *reject_reason = SAMR_REJECT_COMPLEXITY;
1623 return NT_STATUS_PASSWORD_RESTRICTION;
1626 /* compute the new nt and lm hashes */
1627 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1628 lmNewHash = &local_lmNewHash;
1630 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1631 /* If we can't convert this password to UCS2, then we should not accept it */
1632 if (reject_reason) {
1633 *reject_reason = SAMR_REJECT_OTHER;
1635 return NT_STATUS_PASSWORD_RESTRICTION;
1637 ntNewHash = &local_ntNewHash;
1640 if (restrictions && user_change) {
1641 /* are all password changes disallowed? */
1642 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1643 if (reject_reason) {
1644 *reject_reason = SAMR_REJECT_OTHER;
1646 return NT_STATUS_PASSWORD_RESTRICTION;
1649 /* can this user change password? */
1650 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1651 if (reject_reason) {
1652 *reject_reason = SAMR_REJECT_OTHER;
1654 return NT_STATUS_PASSWORD_RESTRICTION;
1657 /* yes, this is a minus. The ages are in negative 100nsec units! */
1658 if (pwdLastSet - minPwdAge > now_nt) {
1659 if (reject_reason) {
1660 *reject_reason = SAMR_REJECT_OTHER;
1662 return NT_STATUS_PASSWORD_RESTRICTION;
1665 /* check the immediately past password */
1666 if (pwdHistoryLength > 0) {
1667 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1668 if (reject_reason) {
1669 *reject_reason = SAMR_REJECT_IN_HISTORY;
1671 return NT_STATUS_PASSWORD_RESTRICTION;
1673 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1674 if (reject_reason) {
1675 *reject_reason = SAMR_REJECT_IN_HISTORY;
1677 return NT_STATUS_PASSWORD_RESTRICTION;
1681 /* check the password history */
1682 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1683 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1685 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1686 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1687 if (reject_reason) {
1688 *reject_reason = SAMR_REJECT_IN_HISTORY;
1690 return NT_STATUS_PASSWORD_RESTRICTION;
1693 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1694 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1695 if (reject_reason) {
1696 *reject_reason = SAMR_REJECT_IN_HISTORY;
1698 return NT_STATUS_PASSWORD_RESTRICTION;
1703 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1705 /* the password is acceptable. Start forming the new fields */
1707 /* if we know the cleartext, then only set it.
1708 * Modules in ldb will set all the appropriate
1710 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1711 "sambaPassword", new_pass));
1713 /* We don't have the cleartext, so delete the old one
1714 * and set what we have of the hashes */
1715 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1718 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1720 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1724 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1726 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1730 return NT_STATUS_OK;
1735 set the user password using plaintext, obeying any user or domain
1736 password restrictions
1738 This wrapper function takes a SID as input, rather than a user DN,
1739 and actually performs the password change
1742 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1743 const struct dom_sid *user_sid,
1744 const char *new_pass,
1745 struct samr_Password *lmNewHash,
1746 struct samr_Password *ntNewHash,
1749 enum samr_RejectReason *reject_reason,
1750 struct samr_DomInfo1 **_dominfo)
1753 struct ldb_dn *user_dn;
1754 struct ldb_message *msg;
1757 ret = ldb_transaction_start(ctx);
1759 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1760 return NT_STATUS_TRANSACTION_ABORTED;
1763 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1764 "(&(objectSid=%s)(objectClass=user))",
1765 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1767 ldb_transaction_cancel(ctx);
1768 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1769 dom_sid_string(mem_ctx, user_sid)));
1770 return NT_STATUS_NO_SUCH_USER;
1773 msg = ldb_msg_new(mem_ctx);
1775 ldb_transaction_cancel(ctx);
1776 return NT_STATUS_NO_MEMORY;
1779 msg->dn = ldb_dn_copy(msg, user_dn);
1781 ldb_transaction_cancel(ctx);
1782 return NT_STATUS_NO_MEMORY;
1785 nt_status = samdb_set_password(ctx, mem_ctx,
1788 lmNewHash, ntNewHash,
1789 user_change, /* This is a password set, not change */
1790 restrictions, /* run restriction tests */
1791 reject_reason, _dominfo);
1792 if (!NT_STATUS_IS_OK(nt_status)) {
1793 ldb_transaction_cancel(ctx);
1797 /* modify the samdb record */
1798 ret = samdb_replace(ctx, mem_ctx, msg);
1800 ldb_transaction_cancel(ctx);
1801 return NT_STATUS_ACCESS_DENIED;
1804 ret = ldb_transaction_commit(ctx);
1806 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1807 ldb_dn_get_linearized(msg->dn),
1808 ldb_errstring(ctx)));
1809 return NT_STATUS_TRANSACTION_ABORTED;
1811 return NT_STATUS_OK;
1814 /****************************************************************************
1815 Create the SID list for this user.
1816 ****************************************************************************/
1817 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1818 struct dom_sid *user_sid,
1819 struct dom_sid *group_sid,
1821 struct dom_sid **groupSIDs,
1822 BOOL is_authenticated,
1823 struct security_token **token)
1825 struct security_token *ptoken;
1829 ptoken = security_token_initialise(mem_ctx);
1830 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1832 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1833 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1835 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1836 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1837 ptoken->privilege_mask = 0;
1839 ptoken->sids[0] = ptoken->user_sid;
1840 ptoken->sids[1] = ptoken->group_sid;
1843 * Finally add the "standard" SIDs.
1844 * The only difference between guest and "anonymous"
1845 * is the addition of Authenticated_Users.
1847 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1848 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1849 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1850 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1851 ptoken->num_sids = 4;
1853 if (is_authenticated) {
1854 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1855 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1859 for (i = 0; i < n_groupSIDs; i++) {
1860 size_t check_sid_idx;
1861 for (check_sid_idx = 1;
1862 check_sid_idx < ptoken->num_sids;
1864 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1869 if (check_sid_idx == ptoken->num_sids) {
1870 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1874 /* setup the privilege mask for this token */
1875 status = samdb_privilege_setup(ptoken);
1876 if (!NT_STATUS_IS_OK(status)) {
1877 talloc_free(ptoken);
1881 security_token_debug(10, ptoken);
1885 return NT_STATUS_OK;
1889 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1890 struct dom_sid *sid, struct ldb_dn **ret_dn)
1892 struct ldb_message *msg;
1893 struct ldb_dn *basedn;
1897 sidstr = dom_sid_string(mem_ctx, sid);
1898 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1900 /* We might have to create a ForeignSecurityPrincipal, even if this user
1901 * is in our own domain */
1903 msg = ldb_msg_new(mem_ctx);
1905 return NT_STATUS_NO_MEMORY;
1908 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1909 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1910 * not work, this is wrong for the Builtin domain, there's no
1911 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1914 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1915 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1917 if (basedn == NULL) {
1918 DEBUG(0, ("Failed to find DN for "
1919 "ForeignSecurityPrincipal container\n"));
1920 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1923 /* add core elements to the ldb_message for the alias */
1924 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1925 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1926 return NT_STATUS_NO_MEMORY;
1928 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1930 "foreignSecurityPrincipal");
1932 /* create the alias */
1933 ret = samdb_add(sam_ctx, mem_ctx, msg);
1935 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1937 ldb_dn_get_linearized(msg->dn),
1938 ldb_errstring(sam_ctx)));
1939 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1942 return NT_STATUS_OK;
1947 Find the DN of a domain, assuming it to be a dotted.dns name
1950 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1953 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1954 const char *binary_encoded;
1955 const char **split_realm;
1962 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1964 talloc_free(tmp_ctx);
1967 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1968 for (i=0; split_realm[i]; i++) {
1969 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1970 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1971 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1972 binary_encoded, ldb_dn_get_linearized(dn)));
1973 talloc_free(tmp_ctx);
1977 if (!ldb_dn_validate(dn)) {
1978 DEBUG(2, ("Failed to validated DN %s\n",
1979 ldb_dn_get_linearized(dn)));
1985 Find the DN of a domain, be it the netbios or DNS name
1988 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1989 const char *domain_name)
1991 const char * const domain_ref_attrs[] = {
1994 const char * const domain_ref2_attrs[] = {
1997 struct ldb_result *res_domain_ref;
1998 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1999 /* find the domain's DN */
2000 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2002 samdb_partitions_dn(ldb, mem_ctx),
2005 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2007 if (ret_domain != 0) {
2011 if (res_domain_ref->count == 0) {
2012 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2014 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2017 "(objectclass=domain)");
2018 if (ret_domain != 0) {
2022 if (res_domain_ref->count == 1) {
2023 return res_domain_ref->msgs[0]->dn;
2028 if (res_domain_ref->count > 1) {
2029 DEBUG(0,("Found %d records matching domain [%s]\n",
2030 ret_domain, domain_name));
2034 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);