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 auth_session_info *session_info)
76 struct ldb_context *ldb;
77 ldb = ldb_wrap_connect(mem_ctx, global_loadparm,
78 lp_sam_url(global_loadparm), session_info,
83 dsdb_make_schema_global(ldb);
88 search the sam for the specified attributes in a specific domain, filter on
89 objectSid being in domain_sid.
91 int samdb_search_domain(struct ldb_context *sam_ldb,
93 struct ldb_dn *basedn,
94 struct ldb_message ***res,
95 const char * const *attrs,
96 const struct dom_sid *domain_sid,
97 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
102 va_start(ap, format);
103 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
104 res, attrs, format, ap);
110 struct dom_sid *entry_sid;
112 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
114 if ((entry_sid == NULL) ||
115 (!dom_sid_in_domain(domain_sid, entry_sid))) {
116 /* Delete that entry from the result set */
117 (*res)[i] = (*res)[count-1];
119 talloc_free(entry_sid);
122 talloc_free(entry_sid);
130 search the sam for a single string attribute in exactly 1 record
132 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
134 struct ldb_dn *basedn,
135 const char *attr_name,
136 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
139 const char *attrs[2] = { NULL, NULL };
140 struct ldb_message **res = NULL;
142 attrs[0] = attr_name;
144 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
146 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
147 attr_name, format, count));
154 return samdb_result_string(res[0], attr_name, NULL);
159 search the sam for a single string attribute in exactly 1 record
161 const char *samdb_search_string(struct ldb_context *sam_ldb,
163 struct ldb_dn *basedn,
164 const char *attr_name,
165 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
170 va_start(ap, format);
171 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
177 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
179 struct ldb_dn *basedn,
180 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
184 struct ldb_message **res = NULL;
187 va_start(ap, format);
188 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
191 if (count != 1) return NULL;
193 ret = talloc_steal(mem_ctx, res[0]->dn);
200 search the sam for a dom_sid attribute in exactly 1 record
202 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
204 struct ldb_dn *basedn,
205 const char *attr_name,
206 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
210 struct ldb_message **res;
211 const char *attrs[2] = { NULL, NULL };
214 attrs[0] = attr_name;
216 va_start(ap, format);
217 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
220 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
221 attr_name, format, count));
227 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
233 return the count of the number of records in the sam matching the query
235 int samdb_search_count(struct ldb_context *sam_ldb,
237 struct ldb_dn *basedn,
238 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
241 struct ldb_message **res;
242 const char * const attrs[] = { NULL };
245 va_start(ap, format);
246 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
254 search the sam for a single integer attribute in exactly 1 record
256 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
258 uint_t default_value,
259 struct ldb_dn *basedn,
260 const char *attr_name,
261 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
265 struct ldb_message **res;
266 const char *attrs[2] = { NULL, NULL };
268 attrs[0] = attr_name;
270 va_start(ap, format);
271 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
275 return default_value;
278 return samdb_result_uint(res[0], attr_name, default_value);
282 search the sam for a single signed 64 bit integer attribute in exactly 1 record
284 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
286 int64_t default_value,
287 struct ldb_dn *basedn,
288 const char *attr_name,
289 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
293 struct ldb_message **res;
294 const char *attrs[2] = { NULL, NULL };
296 attrs[0] = attr_name;
298 va_start(ap, format);
299 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
303 return default_value;
306 return samdb_result_int64(res[0], attr_name, default_value);
310 search the sam for multipe records each giving a single string attribute
311 return the number of matches, or -1 on error
313 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
315 struct ldb_dn *basedn,
317 const char *attr_name,
318 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
322 const char *attrs[2] = { NULL, NULL };
323 struct ldb_message **res = NULL;
325 attrs[0] = attr_name;
327 va_start(ap, format);
328 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
335 /* make sure its single valued */
336 for (i=0;i<count;i++) {
337 if (res[i]->num_elements != 1) {
338 DEBUG(1,("samdb: search for %s %s not single valued\n",
345 *strs = talloc_array(mem_ctx, const char *, count+1);
351 for (i=0;i<count;i++) {
352 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
354 (*strs)[count] = NULL;
360 pull a uint from a result set.
362 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
364 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
368 pull a (signed) int64 from a result set.
370 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
372 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
376 pull a string from a result set.
378 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
379 const char *default_value)
381 return ldb_msg_find_attr_as_string(msg, attr, default_value);
384 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
385 const char *attr, struct ldb_dn *default_value)
387 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
389 return default_value;
395 pull a rid from a objectSid in a result set.
397 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
398 const char *attr, uint32_t default_value)
403 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
405 return default_value;
407 rid = sid->sub_auths[sid->num_auths-1];
413 pull a dom_sid structure from a objectSid in a result set.
415 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
418 const struct ldb_val *v;
420 enum ndr_err_code ndr_err;
421 v = ldb_msg_find_ldb_val(msg, attr);
425 sid = talloc(mem_ctx, struct dom_sid);
429 ndr_err = ndr_pull_struct_blob(v, sid, sid,
430 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
431 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
439 pull a guid structure from a objectGUID in a result set.
441 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
443 const struct ldb_val *v;
444 enum ndr_err_code ndr_err;
450 v = ldb_msg_find_ldb_val(msg, attr);
453 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
454 if (!mem_ctx) return guid;
455 ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid,
456 (ndr_pull_flags_fn_t)ndr_pull_GUID);
457 talloc_free(mem_ctx);
458 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
466 pull a sid prefix from a objectSid in a result set.
467 this is used to find the domain sid for a user
469 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
472 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
473 if (!sid || sid->num_auths < 1) return NULL;
479 pull a NTTIME in a result set.
481 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
483 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
487 pull a uint64_t from a result set.
489 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
491 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
496 construct the allow_password_change field from the PwdLastSet attribute and the
497 domain password settings
499 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
501 struct ldb_dn *domain_dn,
502 struct ldb_message *msg,
505 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
508 if (attr_time == 0) {
512 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
514 /* yes, this is a -= not a += as minPwdAge is stored as the negative
515 of the number of 100-nano-seconds */
516 attr_time -= minPwdAge;
522 construct the force_password_change field from the PwdLastSet attribute and the
523 domain password settings
525 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
527 struct ldb_dn *domain_dn,
528 struct ldb_message *msg)
530 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
531 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
534 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
535 return 0x7FFFFFFFFFFFFFFFULL;
538 if (attr_time == 0) {
542 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
543 if (maxPwdAge == 0) {
546 attr_time -= maxPwdAge;
553 pull a samr_Password structutre from a result set.
555 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
557 struct samr_Password *hash = NULL;
558 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
559 if (val && (val->length >= sizeof(hash->hash))) {
560 hash = talloc(mem_ctx, struct samr_Password);
561 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
567 pull an array of samr_Password structutres from a result set.
569 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
570 const char *attr, struct samr_Password **hashes)
573 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
580 count = val->length / 16;
585 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
590 for (i=0;i<count;i++) {
591 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
597 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
598 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
600 struct samr_Password *lmPwdHash, *ntPwdHash;
603 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
606 } else if (num_nt > 1) {
607 return NT_STATUS_INTERNAL_DB_CORRUPTION;
609 *nt_pwd = &ntPwdHash[0];
614 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
617 } else if (num_lm > 1) {
618 return NT_STATUS_INTERNAL_DB_CORRUPTION;
620 *lm_pwd = &lmPwdHash[0];
627 pull a samr_LogonHours structutre from a result set.
629 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
631 struct samr_LogonHours hours;
632 const int units_per_week = 168;
633 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
635 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
639 hours.units_per_week = units_per_week;
640 memset(hours.bits, 0xFF, units_per_week);
642 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
648 pull a set of account_flags from a result set.
650 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
652 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
653 return samdb_uf2acb(userAccountControl);
657 /* Find an attribute, with a particular value */
659 /* The current callers of this function expect a very specific
660 * behaviour: In particular, objectClass subclass equivilance is not
661 * wanted. This means that we should not lookup the schema for the
662 * comparison function */
663 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
664 const struct ldb_message *msg,
665 const char *name, const char *value)
668 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
674 for (i=0;i<el->num_values;i++) {
675 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
683 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
685 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
686 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
691 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
693 struct ldb_message_element *el;
695 el = ldb_msg_find_element(msg, name);
700 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
705 copy from a template record to a message
707 int samdb_copy_template(struct ldb_context *ldb,
708 struct ldb_message *msg, const char *name,
709 const char **errstring)
711 struct ldb_result *res;
712 struct ldb_message *t;
714 struct ldb_context *templates_ldb;
715 char *templates_ldb_path;
716 struct ldb_dn *basedn;
718 templates_ldb = talloc_get_type(ldb_get_opaque(ldb, "templates_ldb"), struct ldb_context);
720 if (!templates_ldb) {
721 templates_ldb_path = samdb_relative_path(ldb,
724 if (!templates_ldb_path) {
725 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct path for template db");
726 return LDB_ERR_OPERATIONS_ERROR;
729 templates_ldb = ldb_wrap_connect(ldb, global_loadparm,
730 templates_ldb_path, NULL,
732 talloc_free(templates_ldb_path);
733 if (!templates_ldb) {
734 return LDB_ERR_OPERATIONS_ERROR;
737 ret = ldb_set_opaque(ldb, "templates_ldb", templates_ldb);
738 if (ret != LDB_SUCCESS) {
744 basedn = ldb_dn_new(templates_ldb, ldb, "cn=Templates");
745 if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) {
747 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'",
749 return LDB_ERR_OPERATIONS_ERROR;
752 /* pull the template record */
753 ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "(dn=*)", NULL, &res);
755 if (ret != LDB_SUCCESS) {
756 *errstring = talloc_steal(msg, ldb_errstring(templates_ldb));
759 if (res->count != 1) {
760 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1",
764 return LDB_ERR_OPERATIONS_ERROR;
768 for (i = 0; i < t->num_elements; i++) {
769 struct ldb_message_element *el = &t->elements[i];
770 /* some elements should not be copied from the template */
771 if (ldb_attr_cmp(el->name, "cn") == 0 ||
772 ldb_attr_cmp(el->name, "name") == 0 ||
773 ldb_attr_cmp(el->name, "objectClass") == 0 ||
774 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
775 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
776 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
777 ldb_attr_cmp(el->name, "objectGUID") == 0) {
780 for (j = 0; j < el->num_values; j++) {
781 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
782 (char *)el->values[j].data);
784 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name);
798 add a string element to a message
800 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
801 const char *attr_name, const char *str)
803 char *s = talloc_strdup(mem_ctx, str);
804 char *a = talloc_strdup(mem_ctx, attr_name);
805 if (s == NULL || a == NULL) {
806 return LDB_ERR_OPERATIONS_ERROR;
808 return ldb_msg_add_string(msg, a, s);
812 add a dom_sid element to a message
814 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
815 const char *attr_name, struct dom_sid *sid)
818 enum ndr_err_code ndr_err;
820 ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid,
821 (ndr_push_flags_fn_t)ndr_push_dom_sid);
822 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
825 return ldb_msg_add_value(msg, attr_name, &v, NULL);
830 add a delete element operation to a message
832 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
833 const char *attr_name)
835 /* we use an empty replace rather than a delete, as it allows for
836 samdb_replace() to be used everywhere */
837 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
841 add a add attribute value to a message
843 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
844 const char *attr_name, const char *value)
846 struct ldb_message_element *el;
849 a = talloc_strdup(mem_ctx, attr_name);
852 v = talloc_strdup(mem_ctx, value);
855 ret = ldb_msg_add_string(msg, a, v);
858 el = ldb_msg_find_element(msg, a);
861 el->flags = LDB_FLAG_MOD_ADD;
866 add a delete attribute value to a message
868 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
869 const char *attr_name, const char *value)
871 struct ldb_message_element *el;
874 a = talloc_strdup(mem_ctx, attr_name);
877 v = talloc_strdup(mem_ctx, value);
880 ret = ldb_msg_add_string(msg, a, v);
883 el = ldb_msg_find_element(msg, a);
886 el->flags = LDB_FLAG_MOD_DELETE;
891 add a int element to a message
893 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
894 const char *attr_name, int v)
896 const char *s = talloc_asprintf(mem_ctx, "%d", v);
897 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
901 add a uint_t element to a message
903 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
904 const char *attr_name, uint_t v)
906 const char *s = talloc_asprintf(mem_ctx, "%u", v);
907 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
911 add a (signed) int64_t element to a message
913 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
914 const char *attr_name, int64_t v)
916 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
917 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
921 add a uint64_t element to a message
923 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
924 const char *attr_name, uint64_t v)
926 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
927 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
931 add a samr_Password element to a message
933 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
934 const char *attr_name, struct samr_Password *hash)
937 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
942 return ldb_msg_add_value(msg, attr_name, &val, NULL);
946 add a samr_Password array to a message
948 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
949 const char *attr_name, struct samr_Password *hashes, uint_t count)
953 val.data = talloc_array_size(mem_ctx, 16, count);
954 val.length = count*16;
958 for (i=0;i<count;i++) {
959 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
961 return ldb_msg_add_value(msg, attr_name, &val, NULL);
965 add a acct_flags element to a message
967 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
968 const char *attr_name, uint32_t v)
970 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
974 add a logon_hours element to a message
976 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
977 const char *attr_name, struct samr_LogonHours *hours)
980 val.length = hours->units_per_week / 8;
981 val.data = hours->bits;
982 return ldb_msg_add_value(msg, attr_name, &val, NULL);
986 add a general value element to a message
988 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
989 const char *attr_name, const struct ldb_val *val)
991 return ldb_msg_add_value(msg, attr_name, val, NULL);
995 sets a general value element to a message
997 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
998 const char *attr_name, const struct ldb_val *val)
1000 struct ldb_message_element *el;
1002 el = ldb_msg_find_element(msg, attr_name);
1006 return ldb_msg_add_value(msg, attr_name, val, NULL);
1010 set a string element in a message
1012 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1013 const char *attr_name, const char *str)
1015 struct ldb_message_element *el;
1017 el = ldb_msg_find_element(msg, attr_name);
1021 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
1027 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1029 return ldb_add(sam_ldb, msg);
1035 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1037 return ldb_delete(sam_ldb, dn);
1043 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1045 return ldb_modify(sam_ldb, msg);
1049 replace elements in a record
1051 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1055 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1056 for (i=0;i<msg->num_elements;i++) {
1057 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1060 /* modify the samdb record */
1061 return samdb_modify(sam_ldb, mem_ctx, msg);
1065 return a default security descriptor
1067 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1069 struct security_descriptor *sd;
1071 sd = security_descriptor_initialise(mem_ctx);
1076 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1078 return ldb_get_default_basedn(sam_ctx);
1081 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1083 return ldb_get_config_basedn(sam_ctx);
1086 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1088 return ldb_get_schema_basedn(sam_ctx);
1091 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1093 return ldb_get_root_basedn(sam_ctx);
1096 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1098 struct ldb_dn *new_dn;
1100 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1101 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1102 talloc_free(new_dn);
1108 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1110 struct ldb_dn *new_dn;
1112 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1113 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1114 talloc_free(new_dn);
1121 work out the domain sid for the current open ldb
1123 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1125 TALLOC_CTX *tmp_ctx;
1126 struct dom_sid *domain_sid;
1128 /* see if we have a cached copy */
1129 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1134 tmp_ctx = talloc_new(ldb);
1135 if (tmp_ctx == NULL) {
1139 /* find the domain_sid */
1140 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1141 "objectSid", "objectClass=domainDNS");
1142 if (domain_sid == NULL) {
1146 /* cache the domain_sid in the ldb */
1147 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1151 talloc_steal(ldb, domain_sid);
1152 talloc_free(tmp_ctx);
1157 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1158 talloc_free(tmp_ctx);
1162 /* Obtain the short name of the flexible single master operator
1163 * (FSMO), such as the PDC Emulator */
1164 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1167 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1168 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1169 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1170 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1172 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1173 /* Ensure this matches the format. This gives us a
1174 * bit more confidence that a 'cn' value will be a
1179 return (char *)val->data;
1185 work out the ntds settings dn for the current open ldb
1187 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1189 TALLOC_CTX *tmp_ctx;
1190 const char *root_attrs[] = { "dsServiceName", NULL };
1192 struct ldb_result *root_res;
1193 struct ldb_dn *settings_dn;
1195 /* see if we have a cached copy */
1196 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1201 tmp_ctx = talloc_new(ldb);
1202 if (tmp_ctx == NULL) {
1207 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1209 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1210 ldb_errstring(ldb)));
1213 talloc_steal(tmp_ctx, root_res);
1215 if (root_res->count != 1) {
1219 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1221 /* cache the domain_sid in the ldb */
1222 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1226 talloc_steal(ldb, settings_dn);
1227 talloc_free(tmp_ctx);
1232 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1233 talloc_free(tmp_ctx);
1238 work out the ntds settings invocationId for the current open ldb
1240 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1242 TALLOC_CTX *tmp_ctx;
1243 const char *attrs[] = { "invocationId", NULL };
1245 struct ldb_result *res;
1246 struct GUID *invocation_id;
1248 /* see if we have a cached copy */
1249 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1250 if (invocation_id) {
1251 return invocation_id;
1254 tmp_ctx = talloc_new(ldb);
1255 if (tmp_ctx == NULL) {
1259 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1263 talloc_steal(tmp_ctx, res);
1265 if (res->count != 1) {
1269 invocation_id = talloc(tmp_ctx, struct GUID);
1270 if (!invocation_id) {
1274 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1276 /* cache the domain_sid in the ldb */
1277 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1281 talloc_steal(ldb, invocation_id);
1282 talloc_free(tmp_ctx);
1284 return invocation_id;
1287 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1288 talloc_free(tmp_ctx);
1292 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1294 TALLOC_CTX *tmp_ctx;
1295 struct GUID *invocation_id_new;
1296 struct GUID *invocation_id_old;
1298 /* see if we have a cached copy */
1299 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1300 "cache.invocation_id");
1302 tmp_ctx = talloc_new(ldb);
1303 if (tmp_ctx == NULL) {
1307 invocation_id_new = talloc(tmp_ctx, struct GUID);
1308 if (!invocation_id_new) {
1312 *invocation_id_new = *invocation_id_in;
1314 /* cache the domain_sid in the ldb */
1315 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1319 talloc_steal(ldb, invocation_id_new);
1320 talloc_free(tmp_ctx);
1321 talloc_free(invocation_id_old);
1326 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1327 talloc_free(tmp_ctx);
1332 work out the ntds settings objectGUID for the current open ldb
1334 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1336 TALLOC_CTX *tmp_ctx;
1337 const char *attrs[] = { "objectGUID", NULL };
1339 struct ldb_result *res;
1340 struct GUID *ntds_guid;
1342 /* see if we have a cached copy */
1343 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1348 tmp_ctx = talloc_new(ldb);
1349 if (tmp_ctx == NULL) {
1353 ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res);
1357 talloc_steal(tmp_ctx, res);
1359 if (res->count != 1) {
1363 ntds_guid = talloc(tmp_ctx, struct GUID);
1368 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1370 /* cache the domain_sid in the ldb */
1371 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1375 talloc_steal(ldb, ntds_guid);
1376 talloc_free(tmp_ctx);
1381 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1382 talloc_free(tmp_ctx);
1386 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1388 TALLOC_CTX *tmp_ctx;
1389 struct GUID *ntds_guid_new;
1390 struct GUID *ntds_guid_old;
1392 /* see if we have a cached copy */
1393 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1395 tmp_ctx = talloc_new(ldb);
1396 if (tmp_ctx == NULL) {
1400 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1401 if (!ntds_guid_new) {
1405 *ntds_guid_new = *ntds_guid_in;
1407 /* cache the domain_sid in the ldb */
1408 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1412 talloc_steal(ldb, ntds_guid_new);
1413 talloc_free(tmp_ctx);
1414 talloc_free(ntds_guid_old);
1419 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1420 talloc_free(tmp_ctx);
1425 work out the server dn for the current open ldb
1427 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1429 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1433 work out the server dn for the current open ldb
1435 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1437 struct ldb_dn *server_dn;
1438 struct ldb_dn *server_site_dn;
1440 server_dn = samdb_server_dn(ldb, mem_ctx);
1441 if (!server_dn) return NULL;
1443 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1445 talloc_free(server_dn);
1446 return server_site_dn;
1450 work out if we are the PDC for the domain of the current open ldb
1452 bool samdb_is_pdc(struct ldb_context *ldb)
1454 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1456 struct ldb_result *dom_res;
1457 TALLOC_CTX *tmp_ctx;
1461 tmp_ctx = talloc_new(ldb);
1462 if (tmp_ctx == NULL) {
1463 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1467 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1469 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1470 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1471 ldb_errstring(ldb)));
1474 talloc_steal(tmp_ctx, dom_res);
1475 if (dom_res->count != 1) {
1479 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1481 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1487 talloc_free(tmp_ctx);
1492 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1493 talloc_free(tmp_ctx);
1498 /* Find a domain object in the parents of a particular DN. */
1499 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1500 struct ldb_dn **parent_dn, const char **errstring)
1502 TALLOC_CTX *local_ctx;
1503 struct ldb_dn *sdn = dn;
1504 struct ldb_result *res = NULL;
1506 const char *attrs[] = { NULL };
1508 local_ctx = talloc_new(mem_ctx);
1509 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1511 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1512 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1513 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1514 if (ret == LDB_SUCCESS) {
1515 talloc_steal(local_ctx, res);
1516 if (res->count == 1) {
1524 if (ret != LDB_SUCCESS) {
1525 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1526 ldb_dn_get_linearized(dn),
1527 ldb_dn_get_linearized(sdn),
1528 ldb_errstring(ldb));
1529 talloc_free(local_ctx);
1532 if (res->count != 1) {
1533 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1534 ldb_dn_get_linearized(dn));
1535 talloc_free(local_ctx);
1536 return LDB_ERR_CONSTRAINT_VIOLATION;
1539 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1540 talloc_free(local_ctx);
1545 check that a password is sufficiently complex
1547 static bool samdb_password_complexity_ok(const char *pass)
1549 return check_password_quality(pass);
1555 set the user password using plaintext, obeying any user or domain
1556 password restrictions
1558 note that this function doesn't actually store the result in the
1559 database, it just fills in the "mod" structure with ldb modify
1560 elements to setup the correct change when samdb_replace() is
1561 called. This allows the caller to combine the change with other
1562 changes (as is needed by some of the set user info levels)
1564 The caller should probably have a transaction wrapping this
1566 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1567 struct ldb_dn *user_dn,
1568 struct ldb_dn *domain_dn,
1569 struct ldb_message *mod,
1570 const char *new_pass,
1571 struct samr_Password *lmNewHash,
1572 struct samr_Password *ntNewHash,
1574 enum samr_RejectReason *reject_reason,
1575 struct samr_DomInfo1 **_dominfo)
1577 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1579 "dBCSPwd", "unicodePwd",
1581 "pwdLastSet", NULL };
1582 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1583 "maxPwdAge", "minPwdAge",
1584 "minPwdLength", NULL };
1587 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1588 uint_t userAccountControl;
1589 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1590 struct samr_Password local_lmNewHash, local_ntNewHash;
1591 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1592 struct dom_sid *domain_sid;
1593 struct ldb_message **res;
1596 time_t now = time(NULL);
1600 /* we need to know the time to compute password age */
1601 unix_to_nt_time(&now_nt, now);
1603 /* pull all the user parameters */
1604 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1606 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1608 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1609 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1610 "lmPwdHistory", &sambaLMPwdHistory);
1611 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1612 "ntPwdHistory", &sambaNTPwdHistory);
1613 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1614 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1615 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1617 /* Only non-trust accounts have restrictions (possibly this
1618 * test is the wrong way around, but I like to be restrictive
1620 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1621 |UF_WORKSTATION_TRUST_ACCOUNT
1622 |UF_SERVER_TRUST_ACCOUNT));
1625 /* pull the domain parameters */
1626 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1628 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1629 ldb_dn_get_linearized(domain_dn),
1630 ldb_dn_get_linearized(user_dn)));
1631 return NT_STATUS_NO_SUCH_DOMAIN;
1634 /* work out the domain sid, and pull the domain from there */
1635 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1636 if (domain_sid == NULL) {
1637 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1640 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1642 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1644 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1645 dom_sid_string(mem_ctx, domain_sid),
1646 ldb_dn_get_linearized(user_dn)));
1647 return NT_STATUS_NO_SUCH_DOMAIN;
1651 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1652 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1653 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1654 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1657 struct samr_DomInfo1 *dominfo;
1658 /* on failure we need to fill in the reject reasons */
1659 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1660 if (dominfo == NULL) {
1661 return NT_STATUS_NO_MEMORY;
1663 dominfo->min_password_length = minPwdLength;
1664 dominfo->password_properties = pwdProperties;
1665 dominfo->password_history_length = pwdHistoryLength;
1666 dominfo->max_password_age = minPwdAge;
1667 dominfo->min_password_age = minPwdAge;
1668 *_dominfo = dominfo;
1671 if (restrictions && new_pass) {
1673 /* check the various password restrictions */
1674 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1675 if (reject_reason) {
1676 *reject_reason = SAMR_REJECT_TOO_SHORT;
1678 return NT_STATUS_PASSWORD_RESTRICTION;
1681 /* possibly check password complexity */
1682 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1683 !samdb_password_complexity_ok(new_pass)) {
1684 if (reject_reason) {
1685 *reject_reason = SAMR_REJECT_COMPLEXITY;
1687 return NT_STATUS_PASSWORD_RESTRICTION;
1690 /* compute the new nt and lm hashes */
1691 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1692 lmNewHash = &local_lmNewHash;
1694 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1695 /* If we can't convert this password to UCS2, then we should not accept it */
1696 if (reject_reason) {
1697 *reject_reason = SAMR_REJECT_OTHER;
1699 return NT_STATUS_PASSWORD_RESTRICTION;
1701 ntNewHash = &local_ntNewHash;
1705 /* are all password changes disallowed? */
1706 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1707 if (reject_reason) {
1708 *reject_reason = SAMR_REJECT_OTHER;
1710 return NT_STATUS_PASSWORD_RESTRICTION;
1713 /* can this user change password? */
1714 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1715 if (reject_reason) {
1716 *reject_reason = SAMR_REJECT_OTHER;
1718 return NT_STATUS_PASSWORD_RESTRICTION;
1721 /* yes, this is a minus. The ages are in negative 100nsec units! */
1722 if (pwdLastSet - minPwdAge > now_nt) {
1723 if (reject_reason) {
1724 *reject_reason = SAMR_REJECT_OTHER;
1726 return NT_STATUS_PASSWORD_RESTRICTION;
1729 /* check the immediately past password */
1730 if (pwdHistoryLength > 0) {
1731 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1732 if (reject_reason) {
1733 *reject_reason = SAMR_REJECT_IN_HISTORY;
1735 return NT_STATUS_PASSWORD_RESTRICTION;
1737 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1738 if (reject_reason) {
1739 *reject_reason = SAMR_REJECT_IN_HISTORY;
1741 return NT_STATUS_PASSWORD_RESTRICTION;
1745 /* check the password history */
1746 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1747 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1749 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1750 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1751 if (reject_reason) {
1752 *reject_reason = SAMR_REJECT_IN_HISTORY;
1754 return NT_STATUS_PASSWORD_RESTRICTION;
1757 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1758 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1759 if (reject_reason) {
1760 *reject_reason = SAMR_REJECT_IN_HISTORY;
1762 return NT_STATUS_PASSWORD_RESTRICTION;
1767 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1769 /* the password is acceptable. Start forming the new fields */
1771 /* if we know the cleartext, then only set it.
1772 * Modules in ldb will set all the appropriate
1774 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1775 "sambaPassword", new_pass));
1777 /* We don't have the cleartext, so delete the old one
1778 * and set what we have of the hashes */
1779 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1782 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1784 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1788 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1790 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1794 return NT_STATUS_OK;
1799 set the user password using plaintext, obeying any user or domain
1800 password restrictions
1802 This wrapper function takes a SID as input, rather than a user DN,
1803 and actually performs the password change
1806 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1807 const struct dom_sid *user_sid,
1808 const char *new_pass,
1809 struct samr_Password *lmNewHash,
1810 struct samr_Password *ntNewHash,
1812 enum samr_RejectReason *reject_reason,
1813 struct samr_DomInfo1 **_dominfo)
1816 struct ldb_dn *user_dn;
1817 struct ldb_message *msg;
1820 ret = ldb_transaction_start(ctx);
1822 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1823 return NT_STATUS_TRANSACTION_ABORTED;
1826 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1827 "(&(objectSid=%s)(objectClass=user))",
1828 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1830 ldb_transaction_cancel(ctx);
1831 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1832 dom_sid_string(mem_ctx, user_sid)));
1833 return NT_STATUS_NO_SUCH_USER;
1836 msg = ldb_msg_new(mem_ctx);
1838 ldb_transaction_cancel(ctx);
1839 return NT_STATUS_NO_MEMORY;
1842 msg->dn = ldb_dn_copy(msg, user_dn);
1844 ldb_transaction_cancel(ctx);
1845 return NT_STATUS_NO_MEMORY;
1848 nt_status = samdb_set_password(ctx, mem_ctx,
1851 lmNewHash, ntNewHash,
1852 user_change, /* This is a password set, not change */
1853 reject_reason, _dominfo);
1854 if (!NT_STATUS_IS_OK(nt_status)) {
1855 ldb_transaction_cancel(ctx);
1859 /* modify the samdb record */
1860 ret = samdb_replace(ctx, mem_ctx, msg);
1862 ldb_transaction_cancel(ctx);
1863 return NT_STATUS_ACCESS_DENIED;
1866 ret = ldb_transaction_commit(ctx);
1868 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1869 ldb_dn_get_linearized(msg->dn),
1870 ldb_errstring(ctx)));
1871 return NT_STATUS_TRANSACTION_ABORTED;
1873 return NT_STATUS_OK;
1876 /****************************************************************************
1877 Create the SID list for this user.
1878 ****************************************************************************/
1879 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1880 struct dom_sid *user_sid,
1881 struct dom_sid *group_sid,
1883 struct dom_sid **groupSIDs,
1884 bool is_authenticated,
1885 struct security_token **token)
1887 struct security_token *ptoken;
1891 ptoken = security_token_initialise(mem_ctx);
1892 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1894 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1895 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1897 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1898 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1899 ptoken->privilege_mask = 0;
1901 ptoken->sids[0] = ptoken->user_sid;
1902 ptoken->sids[1] = ptoken->group_sid;
1905 * Finally add the "standard" SIDs.
1906 * The only difference between guest and "anonymous"
1907 * is the addition of Authenticated_Users.
1909 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1910 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1911 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1912 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1913 ptoken->num_sids = 4;
1915 if (is_authenticated) {
1916 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1917 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1921 for (i = 0; i < n_groupSIDs; i++) {
1922 size_t check_sid_idx;
1923 for (check_sid_idx = 1;
1924 check_sid_idx < ptoken->num_sids;
1926 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1931 if (check_sid_idx == ptoken->num_sids) {
1932 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1936 /* setup the privilege mask for this token */
1937 status = samdb_privilege_setup(ptoken);
1938 if (!NT_STATUS_IS_OK(status)) {
1939 talloc_free(ptoken);
1943 security_token_debug(10, ptoken);
1947 return NT_STATUS_OK;
1951 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1952 struct dom_sid *sid, struct ldb_dn **ret_dn)
1954 struct ldb_message *msg;
1955 struct ldb_dn *basedn;
1959 sidstr = dom_sid_string(mem_ctx, sid);
1960 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1962 /* We might have to create a ForeignSecurityPrincipal, even if this user
1963 * is in our own domain */
1965 msg = ldb_msg_new(mem_ctx);
1967 return NT_STATUS_NO_MEMORY;
1970 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1971 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1972 * not work, this is wrong for the Builtin domain, there's no
1973 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1976 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1977 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1979 if (basedn == NULL) {
1980 DEBUG(0, ("Failed to find DN for "
1981 "ForeignSecurityPrincipal container\n"));
1982 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1985 /* add core elements to the ldb_message for the alias */
1986 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1987 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1988 return NT_STATUS_NO_MEMORY;
1990 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1992 "foreignSecurityPrincipal");
1994 /* create the alias */
1995 ret = samdb_add(sam_ctx, mem_ctx, msg);
1997 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1999 ldb_dn_get_linearized(msg->dn),
2000 ldb_errstring(sam_ctx)));
2001 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2004 return NT_STATUS_OK;
2009 Find the DN of a domain, assuming it to be a dotted.dns name
2012 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2015 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2016 const char *binary_encoded;
2017 const char **split_realm;
2024 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
2026 talloc_free(tmp_ctx);
2029 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2030 for (i=0; split_realm[i]; i++) {
2031 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2032 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2033 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2034 binary_encoded, ldb_dn_get_linearized(dn)));
2035 talloc_free(tmp_ctx);
2039 if (!ldb_dn_validate(dn)) {
2040 DEBUG(2, ("Failed to validated DN %s\n",
2041 ldb_dn_get_linearized(dn)));
2047 Find the DN of a domain, be it the netbios or DNS name
2050 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2051 const char *domain_name)
2053 const char * const domain_ref_attrs[] = {
2056 const char * const domain_ref2_attrs[] = {
2059 struct ldb_result *res_domain_ref;
2060 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2061 /* find the domain's DN */
2062 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2064 samdb_partitions_dn(ldb, mem_ctx),
2067 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2069 if (ret_domain != 0) {
2073 if (res_domain_ref->count == 0) {
2074 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
2076 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2079 "(objectclass=domain)");
2080 if (ret_domain != 0) {
2084 if (res_domain_ref->count == 1) {
2085 return res_domain_ref->msgs[0]->dn;
2090 if (res_domain_ref->count > 1) {
2091 DEBUG(0,("Found %d records matching domain [%s]\n",
2092 ret_domain, domain_name));
2096 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);