s4:dsdb:common: Fix code spelling
[Samba.git] / source4 / dsdb / common / util.c
blob7b771a1a5c35db651c27abe11774be14a37d3363
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "events/events.h"
26 #include "ldb.h"
27 #include "ldb_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "system/filesys.h"
43 #include "lib/util/tsort.h"
44 #include "dsdb/common/util.h"
45 #include "lib/socket/socket.h"
46 #include "librpc/gen_ndr/irpc.h"
47 #include "libds/common/flag_mapping.h"
48 #include "lib/util/access.h"
49 #include "lib/util/sys_rw_data.h"
50 #include "libcli/util/ntstatus.h"
51 #include "lib/util/smb_strtox.h"
52 #include "auth/auth.h"
54 #undef strncasecmp
55 #undef strcasecmp
58 * This included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
59 * dsdb_request_add_controls()
61 #include "dsdb/samdb/ldb_modules/util.h"
63 /* default is 30 minutes: -1e7 * 30 * 60 */
64 #define DEFAULT_OBSERVATION_WINDOW -18000000000
67 search the sam for the specified attributes in a specific domain, filter on
68 objectSid being in domain_sid.
70 int samdb_search_domain(struct ldb_context *sam_ldb,
71 TALLOC_CTX *mem_ctx,
72 struct ldb_dn *basedn,
73 struct ldb_message ***res,
74 const char * const *attrs,
75 const struct dom_sid *domain_sid,
76 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
78 va_list ap;
79 int i, count;
81 va_start(ap, format);
82 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
83 res, attrs, format, ap);
84 va_end(ap);
86 i=0;
88 while (i<count) {
89 struct dom_sid *entry_sid;
91 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
93 if ((entry_sid == NULL) ||
94 (!dom_sid_in_domain(domain_sid, entry_sid))) {
95 /* Delete that entry from the result set */
96 (*res)[i] = (*res)[count-1];
97 count -= 1;
98 talloc_free(entry_sid);
99 continue;
101 talloc_free(entry_sid);
102 i += 1;
105 return count;
109 search the sam for a single string attribute in exactly 1 record
111 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
112 TALLOC_CTX *mem_ctx,
113 struct ldb_dn *basedn,
114 const char *attr_name,
115 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
117 int count;
118 const char *attrs[2] = { NULL, NULL };
119 struct ldb_message **res = NULL;
121 attrs[0] = attr_name;
123 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
124 if (count > 1) {
125 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
126 attr_name, format, count));
128 if (count != 1) {
129 talloc_free(res);
130 return NULL;
133 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
137 search the sam for a single string attribute in exactly 1 record
139 const char *samdb_search_string(struct ldb_context *sam_ldb,
140 TALLOC_CTX *mem_ctx,
141 struct ldb_dn *basedn,
142 const char *attr_name,
143 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
145 va_list ap;
146 const char *str;
148 va_start(ap, format);
149 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
150 va_end(ap);
152 return str;
155 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
156 TALLOC_CTX *mem_ctx,
157 struct ldb_dn *basedn,
158 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
160 va_list ap;
161 struct ldb_dn *ret;
162 struct ldb_message **res = NULL;
163 int count;
165 va_start(ap, format);
166 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
167 va_end(ap);
169 if (count != 1) return NULL;
171 ret = talloc_steal(mem_ctx, res[0]->dn);
172 talloc_free(res);
174 return ret;
178 search the sam for a dom_sid attribute in exactly 1 record
180 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
181 TALLOC_CTX *mem_ctx,
182 struct ldb_dn *basedn,
183 const char *attr_name,
184 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
186 va_list ap;
187 int count;
188 struct ldb_message **res;
189 const char *attrs[2] = { NULL, NULL };
190 struct dom_sid *sid;
192 attrs[0] = attr_name;
194 va_start(ap, format);
195 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
196 va_end(ap);
197 if (count > 1) {
198 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
199 attr_name, format, count));
201 if (count != 1) {
202 talloc_free(res);
203 return NULL;
205 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
206 talloc_free(res);
207 return sid;
211 search the sam for a single integer attribute in exactly 1 record
213 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
214 TALLOC_CTX *mem_ctx,
215 unsigned int default_value,
216 struct ldb_dn *basedn,
217 const char *attr_name,
218 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
220 va_list ap;
221 int count;
222 struct ldb_message **res;
223 const char *attrs[2] = { NULL, NULL };
225 attrs[0] = attr_name;
227 va_start(ap, format);
228 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
229 va_end(ap);
231 if (count != 1) {
232 return default_value;
235 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
239 search the sam for a single signed 64 bit integer attribute in exactly 1 record
241 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
242 TALLOC_CTX *mem_ctx,
243 int64_t default_value,
244 struct ldb_dn *basedn,
245 const char *attr_name,
246 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
248 va_list ap;
249 int count;
250 struct ldb_message **res;
251 const char *attrs[2] = { NULL, NULL };
253 attrs[0] = attr_name;
255 va_start(ap, format);
256 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
257 va_end(ap);
259 if (count != 1) {
260 return default_value;
263 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
267 search the sam for multiple records each giving a single string attribute
268 return the number of matches, or -1 on error
270 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
271 TALLOC_CTX *mem_ctx,
272 struct ldb_dn *basedn,
273 const char ***strs,
274 const char *attr_name,
275 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
277 va_list ap;
278 int count, i;
279 const char *attrs[2] = { NULL, NULL };
280 struct ldb_message **res = NULL;
282 attrs[0] = attr_name;
284 va_start(ap, format);
285 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
286 va_end(ap);
288 if (count <= 0) {
289 return count;
292 /* make sure its single valued */
293 for (i=0;i<count;i++) {
294 if (res[i]->num_elements != 1) {
295 DEBUG(1,("samdb: search for %s %s not single valued\n",
296 attr_name, format));
297 talloc_free(res);
298 return -1;
302 *strs = talloc_array(mem_ctx, const char *, count+1);
303 if (! *strs) {
304 talloc_free(res);
305 return -1;
308 for (i=0;i<count;i++) {
309 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
311 (*strs)[count] = NULL;
313 return count;
316 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
317 const char *attr, struct ldb_dn *default_value)
319 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
320 if (!ret_dn) {
321 return default_value;
323 return ret_dn;
327 pull a rid from a objectSid in a result set.
329 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
330 const char *attr, uint32_t default_value)
332 struct dom_sid *sid;
333 uint32_t rid;
335 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
336 if (sid == NULL) {
337 return default_value;
339 rid = sid->sub_auths[sid->num_auths-1];
340 talloc_free(sid);
341 return rid;
345 pull a dom_sid structure from a objectSid in a result set.
347 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
348 const char *attr)
350 ssize_t ret;
351 const struct ldb_val *v;
352 struct dom_sid *sid;
353 v = ldb_msg_find_ldb_val(msg, attr);
354 if (v == NULL) {
355 return NULL;
357 sid = talloc(mem_ctx, struct dom_sid);
358 if (sid == NULL) {
359 return NULL;
361 ret = sid_parse(v->data, v->length, sid);
362 if (ret == -1) {
363 talloc_free(sid);
364 return NULL;
366 return sid;
371 * Makes an auth_SidAttr structure from a objectSid in a result set and a
372 * supplied attribute value.
374 * @param [in] mem_ctx Talloc memory context on which to allocate the auth_SidAttr.
375 * @param [in] msg The message from which to take the objectSid.
376 * @param [in] attr The attribute name, usually "objectSid".
377 * @param [in] attrs SE_GROUP_* flags to go with the SID.
378 * @returns A pointer to the auth_SidAttr structure, or NULL on failure.
380 struct auth_SidAttr *samdb_result_dom_sid_attrs(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
381 const char *attr, uint32_t attrs)
383 ssize_t ret;
384 const struct ldb_val *v;
385 struct auth_SidAttr *sid;
386 v = ldb_msg_find_ldb_val(msg, attr);
387 if (v == NULL) {
388 return NULL;
390 sid = talloc(mem_ctx, struct auth_SidAttr);
391 if (sid == NULL) {
392 return NULL;
394 ret = sid_parse(v->data, v->length, &sid->sid);
395 if (ret == -1) {
396 talloc_free(sid);
397 return NULL;
399 sid->attrs = attrs;
400 return sid;
404 pull a dom_sid structure from a objectSid in a result set.
406 int samdb_result_dom_sid_buf(const struct ldb_message *msg,
407 const char *attr,
408 struct dom_sid *sid)
410 ssize_t ret;
411 const struct ldb_val *v = NULL;
412 v = ldb_msg_find_ldb_val(msg, attr);
413 if (v == NULL) {
414 return LDB_ERR_NO_SUCH_ATTRIBUTE;
416 ret = sid_parse(v->data, v->length, sid);
417 if (ret == -1) {
418 return LDB_ERR_OPERATIONS_ERROR;
420 return LDB_SUCCESS;
424 pull a guid structure from a objectGUID in a result set.
426 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
428 const struct ldb_val *v;
429 struct GUID guid;
430 NTSTATUS status;
432 v = ldb_msg_find_ldb_val(msg, attr);
433 if (!v) return GUID_zero();
435 status = GUID_from_ndr_blob(v, &guid);
436 if (!NT_STATUS_IS_OK(status)) {
437 return GUID_zero();
440 return guid;
444 pull a sid prefix from a objectSid in a result set.
445 this is used to find the domain sid for a user
447 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
448 const char *attr)
450 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
451 if (!sid || sid->num_auths < 1) return NULL;
452 sid->num_auths--;
453 return sid;
457 pull a NTTIME in a result set.
459 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
460 NTTIME default_value)
462 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
466 * Windows stores 0 for lastLogoff.
467 * But when a MS DC return the lastLogoff (as Logoff Time)
468 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
469 * cause windows 2008 and newer version to fail for SMB requests
471 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
473 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
475 if (ret == 0)
476 ret = 0x7FFFFFFFFFFFFFFFULL;
478 return ret;
482 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
483 * indicate an account doesn't expire.
485 * When Windows initially creates an account, it sets
486 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
487 * when changing from an account having a specific expiration date to
488 * that account never expiring, it sets accountExpires = 0.
490 * Consolidate that logic here to allow clearer logic for account expiry in
491 * the rest of the code.
493 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
495 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
498 if (ret == 0)
499 ret = 0x7FFFFFFFFFFFFFFFULL;
501 return ret;
505 construct the allow_password_change field from the PwdLastSet attribute and the
506 domain password settings
508 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
509 TALLOC_CTX *mem_ctx,
510 struct ldb_dn *domain_dn,
511 const struct ldb_message *msg,
512 const char *attr)
514 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
515 int64_t minPwdAge;
517 if (attr_time == 0) {
518 return 0;
521 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
523 /* yes, this is a -= not a += as minPwdAge is stored as the negative
524 of the number of 100-nano-seconds */
525 attr_time -= minPwdAge;
527 return attr_time;
531 pull a samr_Password structutre from a result set.
533 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
535 struct samr_Password *hash = NULL;
536 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
537 if (val && (val->length >= sizeof(hash->hash))) {
538 hash = talloc(mem_ctx, struct samr_Password);
539 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
541 return hash;
545 pull an array of samr_Password structures from a result set.
547 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
548 const char *attr, struct samr_Password **hashes)
550 unsigned int count, i;
551 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
553 *hashes = NULL;
554 if (!val) {
555 return 0;
557 count = val->length / 16;
558 if (count == 0) {
559 return 0;
562 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
563 if (! *hashes) {
564 return 0;
566 talloc_keep_secret(*hashes);
568 for (i=0;i<count;i++) {
569 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
572 return count;
575 NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
576 struct loadparm_context *lp_ctx,
577 const struct ldb_message *msg,
578 unsigned int idx,
579 const struct samr_Password **lm_pwd,
580 const struct samr_Password **nt_pwd)
582 struct samr_Password *lmPwdHash, *ntPwdHash;
584 if (nt_pwd) {
585 unsigned int num_nt;
586 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
587 if (num_nt <= idx) {
588 *nt_pwd = NULL;
589 } else {
590 *nt_pwd = &ntPwdHash[idx];
593 if (lm_pwd) {
594 /* Ensure that if we have turned off LM
595 * authentication, that we never use the LM hash, even
596 * if we store it */
597 if (lpcfg_lanman_auth(lp_ctx)) {
598 unsigned int num_lm;
599 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
600 if (num_lm <= idx) {
601 *lm_pwd = NULL;
602 } else {
603 *lm_pwd = &lmPwdHash[idx];
605 } else {
606 *lm_pwd = NULL;
609 return NT_STATUS_OK;
612 NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
613 struct loadparm_context *lp_ctx,
614 const struct ldb_message *msg,
615 struct samr_Password **nt_pwd)
617 struct samr_Password *ntPwdHash;
619 if (nt_pwd) {
620 unsigned int num_nt;
621 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
622 if (num_nt == 0) {
623 *nt_pwd = NULL;
624 } else if (num_nt > 1) {
625 return NT_STATUS_INTERNAL_DB_CORRUPTION;
626 } else {
627 *nt_pwd = &ntPwdHash[0];
630 return NT_STATUS_OK;
633 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
634 struct loadparm_context *lp_ctx,
635 const struct ldb_message *msg,
636 struct samr_Password **nt_pwd)
638 uint16_t acct_flags;
640 acct_flags = samdb_result_acct_flags(msg,
641 "msDS-User-Account-Control-Computed");
642 /* Quit if the account was locked out. */
643 if (acct_flags & ACB_AUTOLOCK) {
644 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
645 ldb_dn_get_linearized(msg->dn)));
646 return NT_STATUS_ACCOUNT_LOCKED_OUT;
649 return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
650 nt_pwd);
654 pull a samr_LogonHours structutre from a result set.
656 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
658 struct samr_LogonHours hours;
659 size_t units_per_week = 168;
660 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
662 ZERO_STRUCT(hours);
664 if (val) {
665 units_per_week = val->length * 8;
668 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
669 if (!hours.bits) {
670 return hours;
672 hours.units_per_week = units_per_week;
673 memset(hours.bits, 0xFF, units_per_week/8);
674 if (val) {
675 memcpy(hours.bits, val->data, val->length);
678 return hours;
682 pull a set of account_flags from a result set.
684 Naturally, this requires that userAccountControl and
685 (if not null) the attributes 'attr' be already
686 included in msg
688 uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
690 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
691 uint32_t attr_flags = 0;
692 uint32_t acct_flags = ds_uf2acb(userAccountControl);
693 if (attr) {
694 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
695 if (attr_flags == UF_ACCOUNTDISABLE) {
696 DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
697 ldb_dn_get_linearized(msg->dn)));
699 acct_flags |= ds_uf2acb(attr_flags);
702 return acct_flags;
705 NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
706 struct ldb_message *msg,
707 const char *attr,
708 struct lsa_BinaryString *s)
710 int i;
711 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
713 ZERO_STRUCTP(s);
715 if (!val) {
716 return NT_STATUS_OK;
719 if ((val->length % 2) != 0) {
721 * If the on-disk data is not even in length, we know
722 * it is corrupt, and can not be safely pushed. We
723 * would either truncate, send either a un-initilaised
724 * byte or send a forced zero byte
726 return NT_STATUS_INTERNAL_DB_CORRUPTION;
729 s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
730 if (!s->array) {
731 return NT_STATUS_NO_MEMORY;
733 s->length = s->size = val->length;
735 /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
736 for (i = 0; i < s->length / 2; i++) {
737 s->array[i] = SVAL(val->data, i * 2);
740 return NT_STATUS_OK;
743 /* Find an attribute, with a particular value */
745 /* The current callers of this function expect a very specific
746 * behaviour: In particular, objectClass subclass equivalence is not
747 * wanted. This means that we should not lookup the schema for the
748 * comparison function */
749 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
750 const struct ldb_message *msg,
751 const char *name, const char *value)
753 unsigned int i;
754 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
756 if (!el) {
757 return NULL;
760 for (i=0;i<el->num_values;i++) {
761 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
762 return el;
766 return NULL;
769 static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
770 struct ldb_message *msg,
771 const char *name,
772 const char *set_value,
773 unsigned attr_flags,
774 bool *added)
776 int ret;
777 struct ldb_message_element *el;
779 SMB_ASSERT(attr_flags != 0);
781 el = ldb_msg_find_element(msg, name);
782 if (el) {
783 if (added != NULL) {
784 *added = false;
787 return LDB_SUCCESS;
790 ret = ldb_msg_add_empty(msg, name,
791 attr_flags,
792 &el);
793 if (ret != LDB_SUCCESS) {
794 return ret;
797 if (set_value != NULL) {
798 ret = ldb_msg_add_string(msg, name, set_value);
799 if (ret != LDB_SUCCESS) {
800 return ret;
804 if (added != NULL) {
805 *added = true;
807 return LDB_SUCCESS;
810 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
812 return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
816 add a dom_sid element to a message
818 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
819 const char *attr_name, const struct dom_sid *sid)
821 struct ldb_val v;
822 enum ndr_err_code ndr_err;
824 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
825 sid,
826 (ndr_push_flags_fn_t)ndr_push_dom_sid);
827 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
828 return ldb_operr(sam_ldb);
830 return ldb_msg_add_value(msg, attr_name, &v, NULL);
835 add a delete element operation to a message
837 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
838 const char *attr_name)
840 /* we use an empty replace rather than a delete, as it allows for
841 dsdb_replace() to be used everywhere */
842 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
846 add an add attribute value to a message or enhance an existing attribute
847 which has the same name and the add flag set.
849 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
850 struct ldb_message *msg, const char *attr_name,
851 const char *value)
853 struct ldb_message_element *el;
854 struct ldb_val val;
855 char *v;
856 unsigned int i;
857 bool found = false;
858 int ret;
860 v = talloc_strdup(mem_ctx, value);
861 if (v == NULL) {
862 return ldb_oom(sam_ldb);
865 val.data = (uint8_t *) v;
866 val.length = strlen(v);
868 if (val.length == 0) {
869 /* allow empty strings as non-existent attributes */
870 return LDB_SUCCESS;
873 for (i = 0; i < msg->num_elements; i++) {
874 el = &msg->elements[i];
875 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
876 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
877 found = true;
878 break;
881 if (!found) {
882 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
883 &el);
884 if (ret != LDB_SUCCESS) {
885 return ret;
889 ret = ldb_msg_element_add_value(msg->elements, el, &val);
890 if (ret != LDB_SUCCESS) {
891 return ldb_oom(sam_ldb);
894 return LDB_SUCCESS;
898 add a delete attribute value to a message or enhance an existing attribute
899 which has the same name and the delete flag set.
901 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
902 struct ldb_message *msg, const char *attr_name,
903 const char *value)
905 struct ldb_message_element *el;
906 struct ldb_val val;
907 char *v;
908 unsigned int i;
909 bool found = false;
910 int ret;
912 v = talloc_strdup(mem_ctx, value);
913 if (v == NULL) {
914 return ldb_oom(sam_ldb);
917 val.data = (uint8_t *) v;
918 val.length = strlen(v);
920 if (val.length == 0) {
921 /* allow empty strings as non-existent attributes */
922 return LDB_SUCCESS;
925 for (i = 0; i < msg->num_elements; i++) {
926 el = &msg->elements[i];
927 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
928 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
929 found = true;
930 break;
933 if (!found) {
934 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
935 &el);
936 if (ret != LDB_SUCCESS) {
937 return ret;
941 ret = ldb_msg_element_add_value(msg->elements, el, &val);
942 if (ret != LDB_SUCCESS) {
943 return ldb_oom(sam_ldb);
946 return LDB_SUCCESS;
950 add a int element to a message
952 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
953 const char *attr_name, int v)
955 const char *s = talloc_asprintf(mem_ctx, "%d", v);
956 if (s == NULL) {
957 return ldb_oom(sam_ldb);
959 return ldb_msg_add_string(msg, attr_name, s);
962 int samdb_msg_add_int_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, int v, int flags)
965 const char *s = talloc_asprintf(mem_ctx, "%d", v);
966 if (s == NULL) {
967 return ldb_oom(sam_ldb);
969 return ldb_msg_add_string_flags(msg, attr_name, s, flags);
973 * Add an unsigned int element to a message
975 * The issue here is that we have not yet first cast to int32_t explicitly,
976 * before we cast to an signed int to printf() into the %d or cast to a
977 * int64_t before we then cast to a long long to printf into a %lld.
979 * There are *no* unsigned integers in Active Directory LDAP, even the RID
980 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
981 * (See the schema, and the syntax definitions in schema_syntax.c).
984 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
985 const char *attr_name, unsigned int v)
987 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
990 int samdb_msg_add_uint_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
991 const char *attr_name, unsigned int v, int flags)
993 return samdb_msg_add_int_flags(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
997 add a (signed) int64_t element to a message
999 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1000 const char *attr_name, int64_t v)
1002 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
1003 if (s == NULL) {
1004 return ldb_oom(sam_ldb);
1006 return ldb_msg_add_string(msg, attr_name, s);
1010 * Add an unsigned int64_t (uint64_t) element to a message
1012 * The issue here is that we have not yet first cast to int32_t explicitly,
1013 * before we cast to an signed int to printf() into the %d or cast to a
1014 * int64_t before we then cast to a long long to printf into a %lld.
1016 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1017 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1018 * (See the schema, and the syntax definitions in schema_syntax.c).
1021 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1022 const char *attr_name, uint64_t v)
1024 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
1028 append a int element to a message
1030 int samdb_msg_append_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1031 const char *attr_name, int v, int flags)
1033 const char *s = talloc_asprintf(mem_ctx, "%d", v);
1034 if (s == NULL) {
1035 return ldb_oom(sam_ldb);
1037 return ldb_msg_append_string(msg, attr_name, s, flags);
1041 * Append an unsigned int element to a message
1043 * The issue here is that we have not yet first cast to int32_t explicitly,
1044 * before we cast to an signed int to printf() into the %d or cast to a
1045 * int64_t before we then cast to a long long to printf into a %lld.
1047 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1048 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1049 * (See the schema, and the syntax definitions in schema_syntax.c).
1052 int samdb_msg_append_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1053 const char *attr_name, unsigned int v, int flags)
1055 return samdb_msg_append_int(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
1059 append a (signed) int64_t element to a message
1061 int samdb_msg_append_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1062 const char *attr_name, int64_t v, int flags)
1064 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
1065 if (s == NULL) {
1066 return ldb_oom(sam_ldb);
1068 return ldb_msg_append_string(msg, attr_name, s, flags);
1072 * Append an unsigned int64_t (uint64_t) element to a message
1074 * The issue here is that we have not yet first cast to int32_t explicitly,
1075 * before we cast to an signed int to printf() into the %d or cast to a
1076 * int64_t before we then cast to a long long to printf into a %lld.
1078 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1079 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1080 * (See the schema, and the syntax definitions in schema_syntax.c).
1083 int samdb_msg_append_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1084 const char *attr_name, uint64_t v, int flags)
1086 return samdb_msg_append_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v, flags);
1090 add a samr_Password element to a message
1092 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1093 const char *attr_name, const struct samr_Password *hash)
1095 struct ldb_val val;
1096 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1097 if (!val.data) {
1098 return ldb_oom(sam_ldb);
1100 val.length = 16;
1101 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1105 add a samr_Password array to a message
1107 int samdb_msg_add_hashes(struct ldb_context *ldb,
1108 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1109 const char *attr_name, struct samr_Password *hashes,
1110 unsigned int count)
1112 struct ldb_val val;
1113 unsigned int i;
1114 val.data = talloc_array_size(mem_ctx, 16, count);
1115 val.length = count*16;
1116 if (!val.data) {
1117 return ldb_oom(ldb);
1119 for (i=0;i<count;i++) {
1120 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1122 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1126 add a acct_flags element to a message
1128 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1129 const char *attr_name, uint32_t v)
1131 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1135 add a logon_hours element to a message
1137 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1138 const char *attr_name, struct samr_LogonHours *hours)
1140 struct ldb_val val;
1141 val.length = hours->units_per_week / 8;
1142 val.data = hours->bits;
1143 return ldb_msg_add_value(msg, attr_name, &val, NULL);
1147 add a parameters element to a message
1149 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1150 const char *attr_name, struct lsa_BinaryString *parameters)
1152 int i;
1153 struct ldb_val val;
1154 if ((parameters->length % 2) != 0) {
1155 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1158 val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1159 if (val.data == NULL) {
1160 return LDB_ERR_OPERATIONS_ERROR;
1162 val.length = parameters->length;
1163 for (i = 0; i < parameters->length / 2; i++) {
1165 * The on-disk format needs to be in the 'network'
1166 * format, parmeters->array is a uint16_t array of
1167 * length parameters->length / 2
1169 SSVAL(val.data, i * 2, parameters->array[i]);
1171 return ldb_msg_add_steal_value(msg, attr_name, &val);
1175 * Sets an unsigned int element in a message
1177 * The issue here is that we have not yet first cast to int32_t explicitly,
1178 * before we cast to an signed int to printf() into the %d or cast to a
1179 * int64_t before we then cast to a long long to printf into a %lld.
1181 * There are *no* unsigned integers in Active Directory LDAP, even the RID
1182 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1183 * (See the schema, and the syntax definitions in schema_syntax.c).
1186 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1187 struct ldb_message *msg, const char *attr_name,
1188 unsigned int v)
1190 struct ldb_message_element *el;
1192 el = ldb_msg_find_element(msg, attr_name);
1193 if (el) {
1194 el->num_values = 0;
1196 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1200 * Handle ldb_request in transaction
1202 int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1203 struct ldb_request *req)
1205 int ret;
1207 ret = ldb_transaction_start(sam_ldb);
1208 if (ret != LDB_SUCCESS) {
1209 return ret;
1212 ret = ldb_request(sam_ldb, req);
1213 if (ret == LDB_SUCCESS) {
1214 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1217 if (ret == LDB_SUCCESS) {
1218 return ldb_transaction_commit(sam_ldb);
1220 ldb_transaction_cancel(sam_ldb);
1222 return ret;
1226 return a default security descriptor
1228 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1230 struct security_descriptor *sd;
1232 sd = security_descriptor_initialise(mem_ctx);
1234 return sd;
1237 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1239 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1240 struct ldb_dn *aggregate_dn;
1241 if (!schema_dn) {
1242 return NULL;
1245 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1246 if (!aggregate_dn) {
1247 return NULL;
1249 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1250 return NULL;
1252 return aggregate_dn;
1255 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1257 struct ldb_dn *new_dn;
1259 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1260 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1261 talloc_free(new_dn);
1262 return NULL;
1264 return new_dn;
1267 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1269 struct ldb_dn *new_dn;
1271 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1272 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1273 talloc_free(new_dn);
1274 return NULL;
1276 return new_dn;
1279 struct ldb_dn *samdb_system_container_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1281 struct ldb_dn *new_dn = NULL;
1282 bool ok;
1284 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1285 if (new_dn == NULL) {
1286 return NULL;
1289 ok = ldb_dn_add_child_fmt(new_dn, "CN=System");
1290 if (!ok) {
1291 TALLOC_FREE(new_dn);
1292 return NULL;
1295 return new_dn;
1298 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1300 struct ldb_dn *new_dn;
1302 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1303 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1304 talloc_free(new_dn);
1305 return NULL;
1307 return new_dn;
1310 struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1312 struct ldb_dn *new_dn;
1314 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1315 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) {
1316 talloc_free(new_dn);
1317 return NULL;
1319 return new_dn;
1322 work out the domain sid for the current open ldb
1324 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1326 TALLOC_CTX *tmp_ctx;
1327 const struct dom_sid *domain_sid;
1328 const char *attrs[] = {
1329 "objectSid",
1330 NULL
1332 struct ldb_result *res;
1333 int ret;
1335 /* see if we have a cached copy */
1336 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1337 if (domain_sid) {
1338 return domain_sid;
1341 tmp_ctx = talloc_new(ldb);
1342 if (tmp_ctx == NULL) {
1343 goto failed;
1346 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1348 if (ret != LDB_SUCCESS) {
1349 goto failed;
1352 if (res->count != 1) {
1353 goto failed;
1356 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1357 if (domain_sid == NULL) {
1358 goto failed;
1361 /* cache the domain_sid in the ldb */
1362 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1363 goto failed;
1366 talloc_steal(ldb, domain_sid);
1367 talloc_free(tmp_ctx);
1369 return domain_sid;
1371 failed:
1372 talloc_free(tmp_ctx);
1373 return NULL;
1377 get domain sid from cache
1379 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1381 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1384 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1386 TALLOC_CTX *tmp_ctx;
1387 struct dom_sid *dom_sid_new;
1388 struct dom_sid *dom_sid_old;
1390 /* see if we have a cached copy */
1391 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1392 "cache.domain_sid"), struct dom_sid);
1394 tmp_ctx = talloc_new(ldb);
1395 if (tmp_ctx == NULL) {
1396 goto failed;
1399 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1400 if (!dom_sid_new) {
1401 goto failed;
1404 /* cache the domain_sid in the ldb */
1405 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1406 goto failed;
1409 talloc_steal(ldb, dom_sid_new);
1410 talloc_free(tmp_ctx);
1411 talloc_free(dom_sid_old);
1413 return true;
1415 failed:
1416 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1417 talloc_free(tmp_ctx);
1418 return false;
1422 work out the domain guid for the current open ldb
1424 const struct GUID *samdb_domain_guid(struct ldb_context *ldb)
1426 TALLOC_CTX *tmp_ctx = NULL;
1427 struct GUID *domain_guid = NULL;
1428 const char *attrs[] = {
1429 "objectGUID",
1430 NULL
1432 struct ldb_result *res = NULL;
1433 int ret;
1435 /* see if we have a cached copy */
1436 domain_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.domain_guid");
1437 if (domain_guid) {
1438 return domain_guid;
1441 tmp_ctx = talloc_new(ldb);
1442 if (tmp_ctx == NULL) {
1443 goto failed;
1446 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectGUID=*");
1447 if (ret != LDB_SUCCESS) {
1448 goto failed;
1451 if (res->count != 1) {
1452 goto failed;
1455 domain_guid = talloc(tmp_ctx, struct GUID);
1456 if (domain_guid == NULL) {
1457 goto failed;
1459 *domain_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1461 /* cache the domain_sid in the ldb */
1462 if (ldb_set_opaque(ldb, "cache.domain_guid", domain_guid) != LDB_SUCCESS) {
1463 goto failed;
1466 talloc_steal(ldb, domain_guid);
1467 talloc_free(tmp_ctx);
1469 return domain_guid;
1471 failed:
1472 talloc_free(tmp_ctx);
1473 return NULL;
1476 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1478 TALLOC_CTX *tmp_ctx;
1479 struct ldb_dn *ntds_settings_dn_new;
1480 struct ldb_dn *ntds_settings_dn_old;
1482 /* see if we have a forced copy from provision */
1483 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1484 "forced.ntds_settings_dn"), struct ldb_dn);
1486 tmp_ctx = talloc_new(ldb);
1487 if (tmp_ctx == NULL) {
1488 goto failed;
1491 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1492 if (!ntds_settings_dn_new) {
1493 goto failed;
1496 /* set the DN in the ldb to avoid lookups during provision */
1497 if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1498 goto failed;
1501 talloc_steal(ldb, ntds_settings_dn_new);
1502 talloc_free(tmp_ctx);
1503 talloc_free(ntds_settings_dn_old);
1505 return true;
1507 failed:
1508 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1509 talloc_free(tmp_ctx);
1510 return false;
1514 work out the ntds settings dn for the current open ldb
1516 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1518 TALLOC_CTX *tmp_ctx;
1519 const char *root_attrs[] = { "dsServiceName", NULL };
1520 int ret;
1521 struct ldb_result *root_res;
1522 struct ldb_dn *settings_dn;
1524 /* see if we have a cached copy */
1525 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1526 if (settings_dn) {
1527 return ldb_dn_copy(mem_ctx, settings_dn);
1530 tmp_ctx = talloc_new(mem_ctx);
1531 if (tmp_ctx == NULL) {
1532 goto failed;
1535 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1536 if (ret != LDB_SUCCESS) {
1537 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1538 ldb_errstring(ldb)));
1539 goto failed;
1542 if (root_res->count != 1) {
1543 goto failed;
1546 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1548 /* note that we do not cache the DN here, as that would mean
1549 * we could not handle server renames at runtime. Only
1550 * provision sets up forced.ntds_settings_dn */
1552 talloc_steal(mem_ctx, settings_dn);
1553 talloc_free(tmp_ctx);
1555 return settings_dn;
1557 failed:
1558 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1559 talloc_free(tmp_ctx);
1560 return NULL;
1564 work out the ntds settings invocationID/objectGUID for the current open ldb
1566 static const struct GUID *samdb_ntds_GUID(struct ldb_context *ldb,
1567 const char *attribute,
1568 const char *cache_name)
1570 TALLOC_CTX *tmp_ctx;
1571 const char *attrs[] = { attribute, NULL };
1572 int ret;
1573 struct ldb_result *res;
1574 struct GUID *ntds_guid;
1575 struct ldb_dn *ntds_settings_dn = NULL;
1576 const char *errstr = NULL;
1578 /* see if we have a cached copy */
1579 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1580 if (ntds_guid != NULL) {
1581 return ntds_guid;
1584 tmp_ctx = talloc_new(ldb);
1585 if (tmp_ctx == NULL) {
1586 goto failed;
1589 ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
1590 if (ntds_settings_dn == NULL) {
1591 errstr = "samdb_ntds_settings_dn() returned NULL";
1592 goto failed;
1595 ret = ldb_search(ldb, tmp_ctx, &res, ntds_settings_dn,
1596 LDB_SCOPE_BASE, attrs, NULL);
1597 if (ret) {
1598 errstr = ldb_errstring(ldb);
1599 goto failed;
1602 if (res->count != 1) {
1603 errstr = "incorrect number of results from base search";
1604 goto failed;
1607 ntds_guid = talloc(tmp_ctx, struct GUID);
1608 if (ntds_guid == NULL) {
1609 goto failed;
1612 *ntds_guid = samdb_result_guid(res->msgs[0], attribute);
1614 if (GUID_all_zero(ntds_guid)) {
1615 if (ldb_msg_find_ldb_val(res->msgs[0], attribute)) {
1616 errstr = "failed to find the GUID attribute";
1617 } else {
1618 errstr = "failed to parse the GUID";
1620 goto failed;
1623 /* cache the domain_sid in the ldb */
1624 if (ldb_set_opaque(ldb, cache_name, ntds_guid) != LDB_SUCCESS) {
1625 errstr = "ldb_set_opaque() failed";
1626 goto failed;
1629 talloc_steal(ldb, ntds_guid);
1630 talloc_free(tmp_ctx);
1632 return ntds_guid;
1634 failed:
1635 DBG_WARNING("Failed to find our own NTDS Settings %s in the ldb: %s!\n",
1636 attribute, errstr);
1637 talloc_free(tmp_ctx);
1638 return NULL;
1642 work out the ntds settings objectGUID for the current open ldb
1644 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1646 return samdb_ntds_GUID(ldb, "objectGUID", "cache.ntds_guid");
1650 work out the ntds settings invocationId for the current open ldb
1652 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1654 return samdb_ntds_GUID(ldb, "invocationId", "cache.invocation_id");
1657 static bool samdb_set_ntds_GUID(struct ldb_context *ldb,
1658 const struct GUID *ntds_guid_in,
1659 const char *attribute,
1660 const char *cache_name)
1662 TALLOC_CTX *tmp_ctx;
1663 struct GUID *ntds_guid_new;
1664 struct GUID *ntds_guid_old;
1666 /* see if we have a cached copy */
1667 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1669 tmp_ctx = talloc_new(ldb);
1670 if (tmp_ctx == NULL) {
1671 goto failed;
1674 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1675 if (!ntds_guid_new) {
1676 goto failed;
1679 *ntds_guid_new = *ntds_guid_in;
1681 /* cache the domain_sid in the ldb */
1682 if (ldb_set_opaque(ldb, cache_name, ntds_guid_new) != LDB_SUCCESS) {
1683 goto failed;
1686 talloc_steal(ldb, ntds_guid_new);
1687 talloc_free(tmp_ctx);
1688 talloc_free(ntds_guid_old);
1690 return true;
1692 failed:
1693 DBG_WARNING("Failed to set our own cached %s in the ldb!\n",
1694 attribute);
1695 talloc_free(tmp_ctx);
1696 return false;
1699 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1701 return samdb_set_ntds_GUID(ldb,
1702 ntds_guid_in,
1703 "objectGUID",
1704 "cache.ntds_guid");
1707 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1709 return samdb_set_ntds_GUID(ldb,
1710 invocation_id_in,
1711 "invocationId",
1712 "cache.invocation_id");
1716 work out the server dn for the current open ldb
1718 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1720 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1721 struct ldb_dn *dn;
1722 if (!tmp_ctx) {
1723 return NULL;
1725 dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1726 talloc_free(tmp_ctx);
1727 return dn;
1732 work out the server dn for the current open ldb
1734 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1736 struct ldb_dn *server_dn;
1737 struct ldb_dn *servers_dn;
1738 struct ldb_dn *server_site_dn;
1740 /* TODO: there must be a saner way to do this!! */
1741 server_dn = samdb_server_dn(ldb, mem_ctx);
1742 if (!server_dn) return NULL;
1744 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1745 talloc_free(server_dn);
1746 if (!servers_dn) return NULL;
1748 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1749 talloc_free(servers_dn);
1751 return server_site_dn;
1755 find the site name from a computers DN record
1757 int samdb_find_site_for_computer(struct ldb_context *ldb,
1758 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1759 const char **site_name)
1761 int ret;
1762 struct ldb_dn *dn;
1763 const struct ldb_val *rdn_val;
1765 *site_name = NULL;
1767 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1768 if (ret != LDB_SUCCESS) {
1769 return ret;
1772 if (!ldb_dn_remove_child_components(dn, 2)) {
1773 talloc_free(dn);
1774 return LDB_ERR_INVALID_DN_SYNTAX;
1777 rdn_val = ldb_dn_get_rdn_val(dn);
1778 if (rdn_val == NULL) {
1779 return LDB_ERR_OPERATIONS_ERROR;
1782 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1783 talloc_free(dn);
1784 if (!*site_name) {
1785 return LDB_ERR_OPERATIONS_ERROR;
1787 return LDB_SUCCESS;
1791 find the NTDS GUID from a computers DN record
1793 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1794 struct GUID *ntds_guid)
1796 int ret;
1797 struct ldb_dn *dn;
1799 *ntds_guid = GUID_zero();
1801 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1802 if (ret != LDB_SUCCESS) {
1803 return ret;
1806 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1807 talloc_free(dn);
1808 return LDB_ERR_OPERATIONS_ERROR;
1811 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1812 talloc_free(dn);
1813 return ret;
1817 find a 'reference' DN that points at another object
1818 (eg. serverReference, rIDManagerReference etc)
1820 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1821 const char *attribute, struct ldb_dn **dn)
1823 const char *attrs[2];
1824 struct ldb_result *res;
1825 int ret;
1827 attrs[0] = attribute;
1828 attrs[1] = NULL;
1830 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1831 if (ret != LDB_SUCCESS) {
1832 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1833 ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1834 return ret;
1837 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1838 if (!*dn) {
1839 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1840 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1841 ldb_dn_get_linearized(base));
1842 } else {
1843 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1844 ldb_dn_get_linearized(base));
1846 talloc_free(res);
1847 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1850 talloc_free(res);
1851 return LDB_SUCCESS;
1855 find if a DN (must have GUID component!) is our ntdsDsa
1857 int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1859 NTSTATUS status;
1860 struct GUID dn_guid;
1861 const struct GUID *our_ntds_guid;
1862 status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1863 if (!NT_STATUS_IS_OK(status)) {
1864 return LDB_ERR_OPERATIONS_ERROR;
1867 our_ntds_guid = samdb_ntds_objectGUID(ldb);
1868 if (!our_ntds_guid) {
1869 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1870 return LDB_ERR_OPERATIONS_ERROR;
1873 *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1874 return LDB_SUCCESS;
1878 find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1880 int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1881 const char *attribute, bool *is_ntdsa)
1883 int ret;
1884 struct ldb_dn *referenced_dn;
1885 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1886 if (tmp_ctx == NULL) {
1887 return LDB_ERR_OPERATIONS_ERROR;
1889 ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1890 if (ret != LDB_SUCCESS) {
1891 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1892 return ret;
1895 ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1897 talloc_free(tmp_ctx);
1898 return ret;
1902 find our machine account via the serverReference attribute in the
1903 server DN
1905 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1907 struct ldb_dn *server_dn;
1908 int ret;
1910 server_dn = samdb_server_dn(ldb, mem_ctx);
1911 if (server_dn == NULL) {
1912 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
1915 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1916 talloc_free(server_dn);
1918 return ret;
1922 find the RID Manager$ DN via the rIDManagerReference attribute in the
1923 base DN
1925 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1927 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1928 "rIDManagerReference", dn);
1932 find the RID Set DN via the rIDSetReferences attribute in our
1933 machine account DN
1935 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1937 struct ldb_dn *server_ref_dn = NULL;
1938 int ret;
1940 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1941 if (ret != LDB_SUCCESS) {
1942 return ret;
1944 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1945 talloc_free(server_ref_dn);
1946 return ret;
1949 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1951 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1952 mem_ctx));
1954 if (val == NULL) {
1955 return NULL;
1958 return (const char *) val->data;
1962 * Finds the client site by using the client's IP address.
1963 * The "subnet_name" returns the name of the subnet if parameter != NULL
1965 * Has a Windows-based fallback to provide the only site available, or an empty
1966 * string if there are multiple sites.
1968 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1969 const char *ip_address, char **subnet_name,
1970 bool fallback)
1972 const char *attrs[] = { "cn", "siteObject", NULL };
1973 struct ldb_dn *sites_container_dn = NULL;
1974 struct ldb_dn *subnets_dn = NULL;
1975 struct ldb_dn *sites_dn = NULL;
1976 struct ldb_result *res = NULL;
1977 const struct ldb_val *val = NULL;
1978 const char *site_name = NULL;
1979 const char *l_subnet_name = NULL;
1980 const char *allow_list[2] = { NULL, NULL };
1981 unsigned int i, count;
1982 int ret;
1985 * if we don't have a client ip e.g. ncalrpc
1986 * the server site is the client site
1988 if (ip_address == NULL) {
1989 return samdb_server_site_name(ldb, mem_ctx);
1992 sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1993 if (sites_container_dn == NULL) {
1994 goto exit;
1997 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1998 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1999 goto exit;
2002 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
2003 attrs, NULL);
2004 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2005 count = 0;
2006 } else if (ret != LDB_SUCCESS) {
2007 goto exit;
2008 } else {
2009 count = res->count;
2012 for (i = 0; i < count; i++) {
2013 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
2014 NULL);
2016 allow_list[0] = l_subnet_name;
2018 if (allow_access_nolog(NULL, allow_list, "", ip_address)) {
2019 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
2020 res->msgs[i],
2021 "siteObject");
2022 if (sites_dn == NULL) {
2023 /* No reference, maybe another subnet matches */
2024 continue;
2027 /* "val" cannot be NULL here since "sites_dn" != NULL */
2028 val = ldb_dn_get_rdn_val(sites_dn);
2029 site_name = talloc_strdup(mem_ctx,
2030 (const char *) val->data);
2032 TALLOC_FREE(sites_dn);
2034 break;
2038 if (site_name == NULL && fallback) {
2039 /* This is the Windows Server fallback rule: when no subnet
2040 * exists and we have only one site available then use it (it
2041 * is for sure the same as our server site). If more sites do
2042 * exist then we don't know which one to use and set the site
2043 * name to "". */
2044 size_t cnt = 0;
2045 ret = dsdb_domain_count(
2046 ldb,
2047 &cnt,
2048 sites_container_dn,
2049 NULL,
2050 LDB_SCOPE_SUBTREE,
2051 "(objectClass=site)");
2052 if (ret != LDB_SUCCESS) {
2053 goto exit;
2055 if (cnt == 1) {
2056 site_name = samdb_server_site_name(ldb, mem_ctx);
2057 } else {
2058 site_name = talloc_strdup(mem_ctx, "");
2060 l_subnet_name = NULL;
2063 if (subnet_name != NULL) {
2064 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
2067 exit:
2068 TALLOC_FREE(sites_container_dn);
2069 TALLOC_FREE(subnets_dn);
2070 TALLOC_FREE(res);
2072 return site_name;
2076 work out if we are the PDC for the domain of the current open ldb
2078 bool samdb_is_pdc(struct ldb_context *ldb)
2080 int ret;
2081 bool is_pdc;
2083 ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner",
2084 &is_pdc);
2085 if (ret != LDB_SUCCESS) {
2086 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n",
2087 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
2088 ldb_errstring(ldb)));
2089 return false;
2092 return is_pdc;
2096 work out if we are a Global Catalog server for the domain of the current open ldb
2098 bool samdb_is_gc(struct ldb_context *ldb)
2100 uint32_t options = 0;
2101 if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
2102 return false;
2104 return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
2107 /* Find a domain object in the parents of a particular DN. */
2108 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2109 struct ldb_dn **parent_dn, const char **errstring)
2111 TALLOC_CTX *local_ctx;
2112 struct ldb_dn *sdn = dn;
2113 struct ldb_result *res = NULL;
2114 int ret = LDB_SUCCESS;
2115 const char *attrs[] = { NULL };
2117 local_ctx = talloc_new(mem_ctx);
2118 if (local_ctx == NULL) return ldb_oom(ldb);
2120 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
2121 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
2122 "(|(objectClass=domain)(objectClass=builtinDomain))");
2123 if (ret == LDB_SUCCESS) {
2124 if (res->count == 1) {
2125 break;
2127 } else {
2128 break;
2132 if (ret != LDB_SUCCESS) {
2133 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2134 ldb_dn_get_linearized(dn),
2135 ldb_dn_get_linearized(sdn),
2136 ldb_errstring(ldb));
2137 talloc_free(local_ctx);
2138 return ret;
2140 /* should never be true with 'ret=LDB_SUCCESS', here to satisfy clang */
2141 if (res == NULL) {
2142 talloc_free(local_ctx);
2143 return LDB_ERR_OTHER;
2145 if (res->count != 1) {
2146 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2147 ldb_dn_get_linearized(dn));
2148 DEBUG(0,(__location__ ": %s\n", *errstring));
2149 talloc_free(local_ctx);
2150 return LDB_ERR_CONSTRAINT_VIOLATION;
2153 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2154 talloc_free(local_ctx);
2155 return ret;
2158 static void pwd_timeout_debug(struct tevent_context *unused1,
2159 struct tevent_timer *unused2,
2160 struct timeval unused3,
2161 void *unused4)
2163 DEBUG(0, ("WARNING: check_password_complexity: password script "
2164 "took more than 1 second to run\n"));
2169 * Performs checks on a user password (plaintext UNIX format - attribute
2170 * "password"). The remaining parameters have to be extracted from the domain
2171 * object in the AD.
2173 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2175 enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
2176 struct loadparm_context *lp_ctx,
2177 const char *account_name,
2178 const char *user_principal_name,
2179 const char *full_name,
2180 const DATA_BLOB *utf8_blob,
2181 const uint32_t pwdProperties,
2182 const uint32_t minPwdLength)
2184 const struct loadparm_substitution *lp_sub =
2185 lpcfg_noop_substitution();
2186 char *password_script = NULL;
2187 const char *utf8_pw = (const char *)utf8_blob->data;
2190 * This looks strange because it is.
2192 * The check for the number of characters in the password
2193 * should clearly not be against the byte length, or else a
2194 * single UTF8 character would count for more than one.
2196 * We have chosen to use the number of 16-bit units that the
2197 * password encodes to as the measure of length. This is not
2198 * the same as the number of codepoints, if a password
2199 * contains a character beyond the Basic Multilingual Plane
2200 * (above 65535) it will count for more than one "character".
2203 size_t password_characters_roughly = strlen_m(utf8_pw);
2205 /* checks if the "minPwdLength" property is satisfied */
2206 if (minPwdLength > password_characters_roughly) {
2207 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2210 /* We might not be asked to check the password complexity */
2211 if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2212 return SAMR_VALIDATION_STATUS_SUCCESS;
2215 if (password_characters_roughly == 0) {
2216 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2219 password_script = lpcfg_check_password_script(lp_ctx, lp_sub, mem_ctx);
2220 if (password_script != NULL && *password_script != '\0') {
2221 int check_ret = 0;
2222 int error = 0;
2223 ssize_t nwritten = 0;
2224 struct tevent_context *event_ctx = NULL;
2225 struct tevent_req *req = NULL;
2226 int cps_stdin = -1;
2227 const char * const cmd[4] = {
2228 "/bin/sh", "-c",
2229 password_script,
2230 NULL
2233 event_ctx = tevent_context_init(mem_ctx);
2234 if (event_ctx == NULL) {
2235 TALLOC_FREE(password_script);
2236 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2239 /* Gives a warning after 1 second, terminates after 10 */
2240 tevent_add_timer(event_ctx, event_ctx,
2241 tevent_timeval_current_ofs(1, 0),
2242 pwd_timeout_debug, NULL);
2244 check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", account_name, 1);
2245 if (check_ret != 0) {
2246 TALLOC_FREE(password_script);
2247 TALLOC_FREE(event_ctx);
2248 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2250 if (user_principal_name != NULL) {
2251 check_ret = setenv("SAMBA_CPS_USER_PRINCIPAL_NAME",
2252 user_principal_name, 1);
2253 } else {
2254 unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2256 if (check_ret != 0) {
2257 TALLOC_FREE(password_script);
2258 TALLOC_FREE(event_ctx);
2259 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2261 if (full_name != NULL) {
2262 check_ret = setenv("SAMBA_CPS_FULL_NAME", full_name, 1);
2263 } else {
2264 unsetenv("SAMBA_CPS_FULL_NAME");
2266 if (check_ret != 0) {
2267 TALLOC_FREE(password_script);
2268 TALLOC_FREE(event_ctx);
2269 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2272 req = samba_runcmd_send(event_ctx, event_ctx,
2273 tevent_timeval_current_ofs(10, 0),
2274 100, 100, cmd, NULL);
2275 unsetenv("SAMBA_CPS_ACCOUNT_NAME");
2276 unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2277 unsetenv("SAMBA_CPS_FULL_NAME");
2278 if (req == NULL) {
2279 TALLOC_FREE(password_script);
2280 TALLOC_FREE(event_ctx);
2281 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2284 cps_stdin = samba_runcmd_export_stdin(req);
2286 nwritten = write_data(
2287 cps_stdin, utf8_blob->data, utf8_blob->length);
2288 if (nwritten == -1) {
2289 close(cps_stdin);
2290 TALLOC_FREE(password_script);
2291 TALLOC_FREE(event_ctx);
2292 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2295 close(cps_stdin);
2297 if (!tevent_req_poll(req, event_ctx)) {
2298 TALLOC_FREE(password_script);
2299 TALLOC_FREE(event_ctx);
2300 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2303 check_ret = samba_runcmd_recv(req, &error);
2304 TALLOC_FREE(event_ctx);
2306 if (error == ETIMEDOUT) {
2307 DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
2308 TALLOC_FREE(password_script);
2309 return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2311 DEBUG(5,("check_password_complexity: check password script (%s) "
2312 "returned [%d]\n", password_script, check_ret));
2314 if (check_ret != 0) {
2315 DEBUG(1,("check_password_complexity: "
2316 "check password script said new password is not good "
2317 "enough!\n"));
2318 TALLOC_FREE(password_script);
2319 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2322 TALLOC_FREE(password_script);
2323 return SAMR_VALIDATION_STATUS_SUCCESS;
2326 TALLOC_FREE(password_script);
2329 * Here are the standard AD password quality rules, which we
2330 * run after the script.
2333 if (!check_password_quality(utf8_pw)) {
2334 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2337 return SAMR_VALIDATION_STATUS_SUCCESS;
2341 * Callback for "samdb_set_password" password change
2343 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2345 int ret;
2347 if (!ares) {
2348 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2351 if (ares->error != LDB_SUCCESS) {
2352 ret = ares->error;
2353 req->context = talloc_steal(req,
2354 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2355 talloc_free(ares);
2356 return ldb_request_done(req, ret);
2359 if (ares->type != LDB_REPLY_DONE) {
2360 talloc_free(ares);
2361 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2364 req->context = talloc_steal(req,
2365 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2366 talloc_free(ares);
2367 return ldb_request_done(req, LDB_SUCCESS);
2371 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2372 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2373 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2374 * user change or not. The "rejectReason" gives some more information if the
2375 * change failed.
2377 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2378 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2379 * NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
2381 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2382 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2383 const DATA_BLOB *new_password,
2384 const struct samr_Password *ntNewHash,
2385 enum dsdb_password_checked old_password_checked,
2386 enum samPwdChangeReason *reject_reason,
2387 struct samr_DomInfo1 **_dominfo,
2388 bool permit_interdomain_trust)
2390 struct ldb_message *msg;
2391 struct ldb_message_element *el;
2392 struct ldb_request *req;
2393 struct dsdb_control_password_change_status *pwd_stat = NULL;
2394 int ret;
2395 bool hash_values = false;
2396 NTSTATUS status = NT_STATUS_OK;
2398 #define CHECK_RET(x) \
2399 if (x != LDB_SUCCESS) { \
2400 talloc_free(msg); \
2401 return NT_STATUS_NO_MEMORY; \
2404 msg = ldb_msg_new(mem_ctx);
2405 if (msg == NULL) {
2406 return NT_STATUS_NO_MEMORY;
2408 msg->dn = user_dn;
2409 if ((new_password != NULL)
2410 && ((ntNewHash == NULL))) {
2411 /* we have the password as plaintext UTF16 */
2412 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2413 new_password, NULL));
2414 el = ldb_msg_find_element(msg, "clearTextPassword");
2415 el->flags = LDB_FLAG_MOD_REPLACE;
2416 } else if ((new_password == NULL)
2417 && ((ntNewHash != NULL))) {
2418 /* we have a password as NT hash */
2419 if (ntNewHash != NULL) {
2420 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2421 "unicodePwd", ntNewHash));
2422 el = ldb_msg_find_element(msg, "unicodePwd");
2423 el->flags = LDB_FLAG_MOD_REPLACE;
2425 hash_values = true;
2426 } else {
2427 /* the password wasn't specified correctly */
2428 talloc_free(msg);
2429 return NT_STATUS_INVALID_PARAMETER;
2432 /* build modify request */
2433 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2434 samdb_set_password_callback, NULL);
2435 if (ret != LDB_SUCCESS) {
2436 talloc_free(msg);
2437 return NT_STATUS_NO_MEMORY;
2440 /* A password change operation */
2441 if (old_password_checked == DSDB_PASSWORD_CHECKED_AND_CORRECT) {
2442 struct dsdb_control_password_change *change;
2444 change = talloc(req, struct dsdb_control_password_change);
2445 if (change == NULL) {
2446 talloc_free(req);
2447 talloc_free(msg);
2448 return NT_STATUS_NO_MEMORY;
2451 change->old_password_checked = old_password_checked;
2453 ret = ldb_request_add_control(req,
2454 DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID,
2455 true, change);
2456 if (ret != LDB_SUCCESS) {
2457 talloc_free(req);
2458 talloc_free(msg);
2459 return NT_STATUS_NO_MEMORY;
2462 if (hash_values) {
2463 ret = ldb_request_add_control(req,
2464 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2465 true, NULL);
2466 if (ret != LDB_SUCCESS) {
2467 talloc_free(req);
2468 talloc_free(msg);
2469 return NT_STATUS_NO_MEMORY;
2472 if (permit_interdomain_trust) {
2473 ret = ldb_request_add_control(req,
2474 DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2475 false, NULL);
2476 if (ret != LDB_SUCCESS) {
2477 talloc_free(req);
2478 talloc_free(msg);
2479 return NT_STATUS_NO_MEMORY;
2482 ret = ldb_request_add_control(req,
2483 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2484 true, NULL);
2485 if (ret != LDB_SUCCESS) {
2486 talloc_free(req);
2487 talloc_free(msg);
2488 return NT_STATUS_NO_MEMORY;
2491 ret = ldb_request(ldb, req);
2492 if (ret == LDB_SUCCESS) {
2493 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2496 if (req->context != NULL) {
2497 struct ldb_control *control = talloc_get_type_abort(req->context,
2498 struct ldb_control);
2499 pwd_stat = talloc_get_type_abort(control->data,
2500 struct dsdb_control_password_change_status);
2501 talloc_steal(mem_ctx, pwd_stat);
2504 talloc_free(req);
2505 talloc_free(msg);
2507 /* Sets the domain info (if requested) */
2508 if (_dominfo != NULL) {
2509 struct samr_DomInfo1 *dominfo;
2511 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2512 if (dominfo == NULL) {
2513 return NT_STATUS_NO_MEMORY;
2516 if (pwd_stat != NULL) {
2517 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2518 dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2519 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2520 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2521 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2524 *_dominfo = dominfo;
2527 if (reject_reason != NULL) {
2528 if (pwd_stat != NULL) {
2529 *reject_reason = pwd_stat->reject_reason;
2530 } else {
2531 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2535 if (pwd_stat != NULL) {
2536 talloc_free(pwd_stat);
2539 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2540 const char *errmsg = ldb_errstring(ldb);
2541 char *endptr = NULL;
2542 WERROR werr = WERR_GEN_FAILURE;
2543 status = NT_STATUS_UNSUCCESSFUL;
2544 if (errmsg != NULL) {
2545 werr = W_ERROR(strtol(errmsg, &endptr, 16));
2546 DBG_WARNING("%s\n", errmsg);
2548 if (endptr != errmsg) {
2549 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2550 status = NT_STATUS_WRONG_PASSWORD;
2552 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2553 status = NT_STATUS_PASSWORD_RESTRICTION;
2555 if (W_ERROR_EQUAL(werr, WERR_ACCOUNT_LOCKED_OUT)) {
2556 status = NT_STATUS_ACCOUNT_LOCKED_OUT;
2559 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2560 /* don't let the caller know if an account doesn't exist */
2561 status = NT_STATUS_WRONG_PASSWORD;
2562 } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2563 status = NT_STATUS_ACCESS_DENIED;
2564 } else if (ret != LDB_SUCCESS) {
2565 DEBUG(1, ("Failed to set password on %s: %s\n",
2566 ldb_dn_get_linearized(user_dn),
2567 ldb_errstring(ldb)));
2568 status = NT_STATUS_UNSUCCESSFUL;
2571 return status;
2574 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2575 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2576 const DATA_BLOB *new_password,
2577 const struct samr_Password *ntNewHash,
2578 enum dsdb_password_checked old_password_checked,
2579 enum samPwdChangeReason *reject_reason,
2580 struct samr_DomInfo1 **_dominfo)
2582 return samdb_set_password_internal(ldb, mem_ctx,
2583 user_dn, domain_dn,
2584 new_password,
2585 ntNewHash,
2586 old_password_checked,
2587 reject_reason, _dominfo,
2588 false); /* reject trusts */
2592 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2593 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2594 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2595 * user change or not. The "rejectReason" gives some more information if the
2596 * change failed.
2598 * This wrapper function for "samdb_set_password" takes a SID as input rather
2599 * than a user DN.
2601 * This call encapsulates a new LDB transaction for changing the password;
2602 * therefore the user hasn't to start a new one.
2604 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2605 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2606 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2607 * NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
2608 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2610 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2611 const struct dom_sid *user_sid,
2612 const uint32_t *new_version, /* optional for trusts */
2613 const DATA_BLOB *new_password,
2614 const struct samr_Password *ntNewHash,
2615 enum dsdb_password_checked old_password_checked,
2616 enum samPwdChangeReason *reject_reason,
2617 struct samr_DomInfo1 **_dominfo)
2619 TALLOC_CTX *frame = talloc_stackframe();
2620 NTSTATUS nt_status;
2621 static const char * const attrs[] = {
2622 "userAccountControl",
2623 "sAMAccountName",
2624 NULL
2626 struct ldb_message *user_msg = NULL;
2627 int ret;
2628 uint32_t uac = 0;
2630 ret = ldb_transaction_start(ldb);
2631 if (ret != LDB_SUCCESS) {
2632 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2633 TALLOC_FREE(frame);
2634 return NT_STATUS_TRANSACTION_ABORTED;
2637 ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2638 LDB_SCOPE_SUBTREE, attrs, 0,
2639 "(&(objectSid=%s)(objectClass=user))",
2640 ldap_encode_ndr_dom_sid(frame, user_sid));
2641 if (ret != LDB_SUCCESS) {
2642 ldb_transaction_cancel(ldb);
2643 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2644 "returning NO_SUCH_USER\n",
2645 dom_sid_string(frame, user_sid),
2646 ldb_strerror(ret), ldb_errstring(ldb)));
2647 TALLOC_FREE(frame);
2648 return NT_STATUS_NO_SUCH_USER;
2651 uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2652 if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2653 ldb_transaction_cancel(ldb);
2654 DEBUG(1, ("samdb_set_password_sid: invalid "
2655 "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2656 "returning NO_SUCH_USER\n",
2657 (unsigned)uac, dom_sid_string(frame, user_sid),
2658 ldb_dn_get_linearized(user_msg->dn)));
2659 TALLOC_FREE(frame);
2660 return NT_STATUS_NO_SUCH_USER;
2663 if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2664 static const char * const tdo_attrs[] = {
2665 "trustAuthIncoming",
2666 "trustDirection",
2667 NULL
2669 struct ldb_message *tdo_msg = NULL;
2670 const char *account_name = NULL;
2671 uint32_t trust_direction;
2672 uint32_t i;
2673 const struct ldb_val *old_val = NULL;
2674 struct trustAuthInOutBlob old_blob = {
2675 .count = 0,
2677 uint32_t old_version = 0;
2678 struct AuthenticationInformation *old_version_a = NULL;
2679 uint32_t _new_version = 0;
2680 struct trustAuthInOutBlob new_blob = {
2681 .count = 0,
2683 struct ldb_val new_val = {
2684 .length = 0,
2686 struct timeval tv = timeval_current();
2687 NTTIME now = timeval_to_nttime(&tv);
2688 enum ndr_err_code ndr_err;
2690 if (new_password == NULL && ntNewHash == NULL) {
2691 ldb_transaction_cancel(ldb);
2692 DEBUG(1, ("samdb_set_password_sid: "
2693 "no new password provided "
2694 "sAMAccountName for SID[%s] DN[%s], "
2695 "returning INVALID_PARAMETER\n",
2696 dom_sid_string(frame, user_sid),
2697 ldb_dn_get_linearized(user_msg->dn)));
2698 TALLOC_FREE(frame);
2699 return NT_STATUS_INVALID_PARAMETER;
2702 if (new_password != NULL && ntNewHash != NULL) {
2703 ldb_transaction_cancel(ldb);
2704 DEBUG(1, ("samdb_set_password_sid: "
2705 "two new passwords provided "
2706 "sAMAccountName for SID[%s] DN[%s], "
2707 "returning INVALID_PARAMETER\n",
2708 dom_sid_string(frame, user_sid),
2709 ldb_dn_get_linearized(user_msg->dn)));
2710 TALLOC_FREE(frame);
2711 return NT_STATUS_INVALID_PARAMETER;
2714 if (new_password != NULL && (new_password->length % 2)) {
2715 ldb_transaction_cancel(ldb);
2716 DEBUG(2, ("samdb_set_password_sid: "
2717 "invalid utf16 length (%zu) "
2718 "sAMAccountName for SID[%s] DN[%s], "
2719 "returning WRONG_PASSWORD\n",
2720 new_password->length,
2721 dom_sid_string(frame, user_sid),
2722 ldb_dn_get_linearized(user_msg->dn)));
2723 TALLOC_FREE(frame);
2724 return NT_STATUS_WRONG_PASSWORD;
2727 if (new_password != NULL && new_password->length >= 500) {
2728 ldb_transaction_cancel(ldb);
2729 DEBUG(2, ("samdb_set_password_sid: "
2730 "utf16 password too long (%zu) "
2731 "sAMAccountName for SID[%s] DN[%s], "
2732 "returning WRONG_PASSWORD\n",
2733 new_password->length,
2734 dom_sid_string(frame, user_sid),
2735 ldb_dn_get_linearized(user_msg->dn)));
2736 TALLOC_FREE(frame);
2737 return NT_STATUS_WRONG_PASSWORD;
2740 account_name = ldb_msg_find_attr_as_string(user_msg,
2741 "sAMAccountName", NULL);
2742 if (account_name == NULL) {
2743 ldb_transaction_cancel(ldb);
2744 DEBUG(1, ("samdb_set_password_sid: missing "
2745 "sAMAccountName for SID[%s] DN[%s], "
2746 "returning NO_SUCH_USER\n",
2747 dom_sid_string(frame, user_sid),
2748 ldb_dn_get_linearized(user_msg->dn)));
2749 TALLOC_FREE(frame);
2750 return NT_STATUS_NO_SUCH_USER;
2753 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2754 SEC_CHAN_DOMAIN,
2755 account_name,
2756 tdo_attrs,
2757 frame, &tdo_msg);
2758 if (!NT_STATUS_IS_OK(nt_status)) {
2759 ldb_transaction_cancel(ldb);
2760 DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2761 "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2762 "returning INTERNAL_DB_CORRUPTION\n",
2763 nt_errstr(nt_status), account_name,
2764 dom_sid_string(frame, user_sid),
2765 ldb_dn_get_linearized(user_msg->dn)));
2766 TALLOC_FREE(frame);
2767 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2770 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2771 "trustDirection", 0);
2772 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2773 ldb_transaction_cancel(ldb);
2774 DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2775 "not inbound for sAMAccountName[%s] "
2776 "DN[%s] TDO[%s], "
2777 "returning INTERNAL_DB_CORRUPTION\n",
2778 (unsigned)trust_direction,
2779 account_name,
2780 ldb_dn_get_linearized(user_msg->dn),
2781 ldb_dn_get_linearized(tdo_msg->dn)));
2782 TALLOC_FREE(frame);
2783 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2786 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2787 if (old_val != NULL) {
2788 ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2789 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2790 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2791 ldb_transaction_cancel(ldb);
2792 DEBUG(1, ("samdb_set_password_sid: "
2793 "failed(%s) to parse "
2794 "trustAuthOutgoing sAMAccountName[%s] "
2795 "DN[%s] TDO[%s], "
2796 "returning INTERNAL_DB_CORRUPTION\n",
2797 ndr_map_error2string(ndr_err),
2798 account_name,
2799 ldb_dn_get_linearized(user_msg->dn),
2800 ldb_dn_get_linearized(tdo_msg->dn)));
2802 TALLOC_FREE(frame);
2803 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2807 for (i = old_blob.current.count; i > 0; i--) {
2808 struct AuthenticationInformation *a =
2809 &old_blob.current.array[i - 1];
2811 switch (a->AuthType) {
2812 case TRUST_AUTH_TYPE_NONE:
2813 if (i == old_blob.current.count) {
2815 * remove TRUST_AUTH_TYPE_NONE at the
2816 * end
2818 old_blob.current.count--;
2820 break;
2822 case TRUST_AUTH_TYPE_VERSION:
2823 old_version_a = a;
2824 old_version = a->AuthInfo.version.version;
2825 break;
2827 case TRUST_AUTH_TYPE_CLEAR:
2828 break;
2830 case TRUST_AUTH_TYPE_NT4OWF:
2831 break;
2835 if (new_version == NULL) {
2836 _new_version = 0;
2837 new_version = &_new_version;
2840 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2841 old_version_a->LastUpdateTime = now;
2842 old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2845 new_blob.count = MAX(old_blob.current.count, 2);
2846 new_blob.current.array = talloc_zero_array(frame,
2847 struct AuthenticationInformation,
2848 new_blob.count);
2849 if (new_blob.current.array == NULL) {
2850 ldb_transaction_cancel(ldb);
2851 TALLOC_FREE(frame);
2852 return NT_STATUS_NO_MEMORY;
2854 new_blob.previous.array = talloc_zero_array(frame,
2855 struct AuthenticationInformation,
2856 new_blob.count);
2857 if (new_blob.current.array == NULL) {
2858 ldb_transaction_cancel(ldb);
2859 TALLOC_FREE(frame);
2860 return NT_STATUS_NO_MEMORY;
2863 for (i = 0; i < old_blob.current.count; i++) {
2864 struct AuthenticationInformation *o =
2865 &old_blob.current.array[i];
2866 struct AuthenticationInformation *p =
2867 &new_blob.previous.array[i];
2869 *p = *o;
2870 new_blob.previous.count++;
2872 for (; i < new_blob.count; i++) {
2873 struct AuthenticationInformation *pi =
2874 &new_blob.previous.array[i];
2876 if (i == 0) {
2878 * new_blob.previous is still empty so
2879 * we'll do new_blob.previous = new_blob.current
2880 * below.
2882 break;
2885 pi->LastUpdateTime = now;
2886 pi->AuthType = TRUST_AUTH_TYPE_NONE;
2887 new_blob.previous.count++;
2890 for (i = 0; i < new_blob.count; i++) {
2891 struct AuthenticationInformation *ci =
2892 &new_blob.current.array[i];
2894 ci->LastUpdateTime = now;
2895 switch (i) {
2896 case 0:
2897 if (ntNewHash != NULL) {
2898 ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2899 ci->AuthInfo.nt4owf.password = *ntNewHash;
2900 break;
2903 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2904 ci->AuthInfo.clear.size = new_password->length;
2905 ci->AuthInfo.clear.password = new_password->data;
2906 break;
2907 case 1:
2908 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2909 ci->AuthInfo.version.version = *new_version;
2910 break;
2911 default:
2912 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2913 break;
2916 new_blob.current.count++;
2919 if (new_blob.previous.count == 0) {
2920 TALLOC_FREE(new_blob.previous.array);
2921 new_blob.previous = new_blob.current;
2924 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2925 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2926 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2927 ldb_transaction_cancel(ldb);
2928 DEBUG(1, ("samdb_set_password_sid: "
2929 "failed(%s) to generate "
2930 "trustAuthOutgoing sAMAccountName[%s] "
2931 "DN[%s] TDO[%s], "
2932 "returning UNSUCCESSFUL\n",
2933 ndr_map_error2string(ndr_err),
2934 account_name,
2935 ldb_dn_get_linearized(user_msg->dn),
2936 ldb_dn_get_linearized(tdo_msg->dn)));
2937 TALLOC_FREE(frame);
2938 return NT_STATUS_UNSUCCESSFUL;
2941 tdo_msg->num_elements = 0;
2942 TALLOC_FREE(tdo_msg->elements);
2944 ret = ldb_msg_append_value(tdo_msg, "trustAuthIncoming",
2945 &new_val, LDB_FLAG_MOD_REPLACE);
2946 if (ret != LDB_SUCCESS) {
2947 ldb_transaction_cancel(ldb);
2948 TALLOC_FREE(frame);
2949 return NT_STATUS_NO_MEMORY;
2952 ret = ldb_modify(ldb, tdo_msg);
2953 if (ret != LDB_SUCCESS) {
2954 nt_status = dsdb_ldb_err_to_ntstatus(ret);
2955 ldb_transaction_cancel(ldb);
2956 DEBUG(1, ("samdb_set_password_sid: "
2957 "failed to replace "
2958 "trustAuthOutgoing sAMAccountName[%s] "
2959 "DN[%s] TDO[%s], "
2960 "%s - %s\n",
2961 account_name,
2962 ldb_dn_get_linearized(user_msg->dn),
2963 ldb_dn_get_linearized(tdo_msg->dn),
2964 nt_errstr(nt_status), ldb_errstring(ldb)));
2965 TALLOC_FREE(frame);
2966 return nt_status;
2970 nt_status = samdb_set_password_internal(ldb, mem_ctx,
2971 user_msg->dn, NULL,
2972 new_password,
2973 ntNewHash,
2974 old_password_checked,
2975 reject_reason, _dominfo,
2976 true); /* permit trusts */
2977 if (!NT_STATUS_IS_OK(nt_status)) {
2978 ldb_transaction_cancel(ldb);
2979 TALLOC_FREE(frame);
2980 return nt_status;
2983 ret = ldb_transaction_commit(ldb);
2984 if (ret != LDB_SUCCESS) {
2985 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2986 ldb_dn_get_linearized(user_msg->dn),
2987 ldb_errstring(ldb)));
2988 TALLOC_FREE(frame);
2989 return NT_STATUS_TRANSACTION_ABORTED;
2992 TALLOC_FREE(frame);
2993 return NT_STATUS_OK;
2997 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2998 struct dom_sid *sid, struct ldb_dn **ret_dn)
3000 struct ldb_message *msg;
3001 struct ldb_dn *basedn = NULL;
3002 char *sidstr;
3003 int ret;
3005 sidstr = dom_sid_string(mem_ctx, sid);
3006 NT_STATUS_HAVE_NO_MEMORY(sidstr);
3008 /* We might have to create a ForeignSecurityPrincipal, even if this user
3009 * is in our own domain */
3011 msg = ldb_msg_new(sidstr);
3012 if (msg == NULL) {
3013 talloc_free(sidstr);
3014 return NT_STATUS_NO_MEMORY;
3017 ret = dsdb_wellknown_dn(sam_ctx, sidstr,
3018 ldb_get_default_basedn(sam_ctx),
3019 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
3020 &basedn);
3021 if (ret != LDB_SUCCESS) {
3022 DEBUG(0, ("Failed to find DN for "
3023 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
3024 talloc_free(sidstr);
3025 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3028 /* add core elements to the ldb_message for the alias */
3029 msg->dn = basedn;
3030 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
3031 talloc_free(sidstr);
3032 return NT_STATUS_NO_MEMORY;
3035 ret = ldb_msg_add_string(msg, "objectClass",
3036 "foreignSecurityPrincipal");
3037 if (ret != LDB_SUCCESS) {
3038 talloc_free(sidstr);
3039 return NT_STATUS_NO_MEMORY;
3042 /* create the alias */
3043 ret = ldb_add(sam_ctx, msg);
3044 if (ret != LDB_SUCCESS) {
3045 DEBUG(0,("Failed to create foreignSecurityPrincipal "
3046 "record %s: %s\n",
3047 ldb_dn_get_linearized(msg->dn),
3048 ldb_errstring(sam_ctx)));
3049 talloc_free(sidstr);
3050 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3053 *ret_dn = talloc_steal(mem_ctx, msg->dn);
3054 talloc_free(sidstr);
3056 return NT_STATUS_OK;
3061 Find the DN of a domain, assuming it to be a dotted.dns name
3064 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
3066 unsigned int i;
3067 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3068 const char *binary_encoded;
3069 const char * const *split_realm;
3070 struct ldb_dn *dn;
3072 if (!tmp_ctx) {
3073 return NULL;
3076 split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
3077 if (!split_realm) {
3078 talloc_free(tmp_ctx);
3079 return NULL;
3081 dn = ldb_dn_new(mem_ctx, ldb, NULL);
3082 for (i=0; split_realm[i]; i++) {
3083 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
3084 if (binary_encoded == NULL) {
3085 DEBUG(2, ("Failed to add dc= element to DN %s\n",
3086 ldb_dn_get_linearized(dn)));
3087 talloc_free(tmp_ctx);
3088 return NULL;
3090 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
3091 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
3092 binary_encoded, ldb_dn_get_linearized(dn)));
3093 talloc_free(tmp_ctx);
3094 return NULL;
3097 if (!ldb_dn_validate(dn)) {
3098 DEBUG(2, ("Failed to validated DN %s\n",
3099 ldb_dn_get_linearized(dn)));
3100 talloc_free(tmp_ctx);
3101 return NULL;
3103 talloc_free(tmp_ctx);
3104 return dn;
3109 Find the DNS equivalent of a DN, in dotted DNS form
3111 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
3113 int i, num_components = ldb_dn_get_comp_num(dn);
3114 char *dns_name = talloc_strdup(mem_ctx, "");
3115 if (dns_name == NULL) {
3116 return NULL;
3119 for (i=0; i<num_components; i++) {
3120 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
3121 char *s;
3122 if (v == NULL) {
3123 talloc_free(dns_name);
3124 return NULL;
3126 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
3127 (int)v->length, (int)v->length, (char *)v->data);
3128 if (s == NULL) {
3129 talloc_free(dns_name);
3130 return NULL;
3132 dns_name = s;
3135 /* remove the last '.' */
3136 if (dns_name[0] != 0) {
3137 dns_name[strlen(dns_name)-1] = 0;
3140 return dns_name;
3144 Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
3145 name is based on the forest DNS name
3147 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
3148 TALLOC_CTX *mem_ctx,
3149 const struct GUID *ntds_guid)
3151 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3152 const char *guid_str;
3153 struct ldb_dn *forest_dn;
3154 const char *dnsforest;
3155 char *ret;
3157 guid_str = GUID_string(tmp_ctx, ntds_guid);
3158 if (guid_str == NULL) {
3159 talloc_free(tmp_ctx);
3160 return NULL;
3162 forest_dn = ldb_get_root_basedn(samdb);
3163 if (forest_dn == NULL) {
3164 talloc_free(tmp_ctx);
3165 return NULL;
3167 dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
3168 if (dnsforest == NULL) {
3169 talloc_free(tmp_ctx);
3170 return NULL;
3172 ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
3173 talloc_free(tmp_ctx);
3174 return ret;
3179 Find the DN of a domain, be it the netbios or DNS name
3181 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
3182 const char *domain_name)
3184 const char * const domain_ref_attrs[] = {
3185 "ncName", NULL
3187 const char * const domain_ref2_attrs[] = {
3188 NULL
3190 struct ldb_result *res_domain_ref;
3191 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
3192 int ret_domain;
3194 if (escaped_domain == NULL) {
3195 return NULL;
3198 /* find the domain's DN */
3199 ret_domain = ldb_search(ldb, mem_ctx,
3200 &res_domain_ref,
3201 samdb_partitions_dn(ldb, mem_ctx),
3202 LDB_SCOPE_ONELEVEL,
3203 domain_ref_attrs,
3204 "(&(nETBIOSName=%s)(objectclass=crossRef))",
3205 escaped_domain);
3206 if (ret_domain != LDB_SUCCESS) {
3207 return NULL;
3210 if (res_domain_ref->count == 0) {
3211 ret_domain = ldb_search(ldb, mem_ctx,
3212 &res_domain_ref,
3213 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
3214 LDB_SCOPE_BASE,
3215 domain_ref2_attrs,
3216 "(objectclass=domain)");
3217 if (ret_domain != LDB_SUCCESS) {
3218 return NULL;
3221 if (res_domain_ref->count == 1) {
3222 return res_domain_ref->msgs[0]->dn;
3224 return NULL;
3227 if (res_domain_ref->count > 1) {
3228 DEBUG(0,("Found %d records matching domain [%s]\n",
3229 ret_domain, domain_name));
3230 return NULL;
3233 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3239 use a GUID to find a DN
3241 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
3242 TALLOC_CTX *mem_ctx,
3243 const struct GUID *guid,
3244 uint32_t dsdb_flags,
3245 struct ldb_dn **dn)
3247 int ret;
3248 struct ldb_result *res;
3249 const char *attrs[] = { NULL };
3250 struct GUID_txt_buf buf;
3251 char *guid_str = GUID_buf_string(guid, &buf);
3253 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3254 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3255 DSDB_SEARCH_SHOW_EXTENDED_DN |
3256 DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3257 "objectGUID=%s", guid_str);
3258 if (ret != LDB_SUCCESS) {
3259 return ret;
3262 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3263 talloc_free(res);
3265 return LDB_SUCCESS;
3269 use a DN to find a GUID with a given attribute name
3271 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3272 struct ldb_dn *dn, const char *attribute,
3273 struct GUID *guid)
3275 int ret;
3276 struct ldb_result *res = NULL;
3277 const char *attrs[2];
3278 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3280 attrs[0] = attribute;
3281 attrs[1] = NULL;
3283 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3284 DSDB_SEARCH_SHOW_DELETED |
3285 DSDB_SEARCH_SHOW_RECYCLED);
3286 if (ret != LDB_SUCCESS) {
3287 talloc_free(tmp_ctx);
3288 return ret;
3290 /* satisfy clang */
3291 if (res == NULL) {
3292 talloc_free(tmp_ctx);
3293 return LDB_ERR_OTHER;
3295 if (res->count < 1) {
3296 talloc_free(tmp_ctx);
3297 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3299 *guid = samdb_result_guid(res->msgs[0], attribute);
3300 talloc_free(tmp_ctx);
3301 return LDB_SUCCESS;
3305 use a DN to find a GUID
3307 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3308 struct ldb_dn *dn, struct GUID *guid)
3310 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3316 adds the given GUID to the given ldb_message. This value is added
3317 for the given attr_name (may be either "objectGUID" or "parentGUID").
3318 This function is used in processing 'add' requests.
3320 int dsdb_msg_add_guid(struct ldb_message *msg,
3321 struct GUID *guid,
3322 const char *attr_name)
3324 int ret;
3325 struct ldb_val v;
3326 NTSTATUS status;
3327 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
3329 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3330 if (!NT_STATUS_IS_OK(status)) {
3331 ret = LDB_ERR_OPERATIONS_ERROR;
3332 goto done;
3335 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3336 if (ret != LDB_SUCCESS) {
3337 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3338 attr_name));
3339 goto done;
3342 ret = LDB_SUCCESS;
3344 done:
3345 talloc_free(tmp_ctx);
3346 return ret;
3352 use a DN to find a SID
3354 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
3355 struct ldb_dn *dn, struct dom_sid *sid)
3357 int ret;
3358 struct ldb_result *res = NULL;
3359 const char *attrs[] = { "objectSid", NULL };
3360 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3361 struct dom_sid *s;
3363 ZERO_STRUCTP(sid);
3365 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3366 DSDB_SEARCH_SHOW_DELETED |
3367 DSDB_SEARCH_SHOW_RECYCLED);
3368 if (ret != LDB_SUCCESS) {
3369 talloc_free(tmp_ctx);
3370 return ret;
3372 if (res == NULL) {
3373 talloc_free(tmp_ctx);
3374 return LDB_ERR_OTHER;
3376 if (res->count < 1) {
3377 talloc_free(tmp_ctx);
3378 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3380 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3381 if (s == NULL) {
3382 talloc_free(tmp_ctx);
3383 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3385 *sid = *s;
3386 talloc_free(tmp_ctx);
3387 return LDB_SUCCESS;
3391 use a SID to find a DN
3393 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3394 TALLOC_CTX *mem_ctx,
3395 struct dom_sid *sid, struct ldb_dn **dn)
3397 int ret;
3398 struct ldb_result *res;
3399 const char *attrs[] = { NULL };
3400 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3402 if (!sid_str) {
3403 return ldb_operr(ldb);
3406 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3407 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3408 DSDB_SEARCH_SHOW_EXTENDED_DN |
3409 DSDB_SEARCH_ONE_ONLY,
3410 "objectSid=%s", sid_str);
3411 talloc_free(sid_str);
3412 if (ret != LDB_SUCCESS) {
3413 return ret;
3416 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3417 talloc_free(res);
3419 return LDB_SUCCESS;
3423 load a repsFromTo blob list for a given partition GUID
3424 attr must be "repsFrom" or "repsTo"
3426 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3427 const char *attr, struct repsFromToBlob **r, uint32_t *count)
3429 const char *attrs[] = { attr, NULL };
3430 struct ldb_result *res = NULL;
3431 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3432 unsigned int i;
3433 struct ldb_message_element *el;
3434 int ret;
3436 *r = NULL;
3437 *count = 0;
3439 ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3440 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3441 /* partition hasn't been replicated yet */
3442 return WERR_OK;
3444 if (ret != LDB_SUCCESS) {
3445 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3446 talloc_free(tmp_ctx);
3447 return WERR_DS_DRA_INTERNAL_ERROR;
3450 /* satisfy clang */
3451 if (res == NULL) {
3452 talloc_free(tmp_ctx);
3453 return WERR_DS_DRA_INTERNAL_ERROR;
3455 el = ldb_msg_find_element(res->msgs[0], attr);
3456 if (el == NULL) {
3457 /* it's OK to be empty */
3458 talloc_free(tmp_ctx);
3459 return WERR_OK;
3462 *count = el->num_values;
3463 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3464 if (*r == NULL) {
3465 talloc_free(tmp_ctx);
3466 return WERR_DS_DRA_INTERNAL_ERROR;
3469 for (i=0; i<(*count); i++) {
3470 enum ndr_err_code ndr_err;
3471 ndr_err = ndr_pull_struct_blob(&el->values[i],
3472 mem_ctx,
3473 &(*r)[i],
3474 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3475 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3476 talloc_free(tmp_ctx);
3477 return WERR_DS_DRA_INTERNAL_ERROR;
3481 talloc_free(tmp_ctx);
3483 return WERR_OK;
3487 save the repsFromTo blob list for a given partition GUID
3488 attr must be "repsFrom" or "repsTo"
3490 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3491 const char *attr, struct repsFromToBlob *r, uint32_t count)
3493 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3494 struct ldb_message *msg;
3495 struct ldb_message_element *el;
3496 unsigned int i;
3498 msg = ldb_msg_new(tmp_ctx);
3499 msg->dn = dn;
3500 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3501 goto failed;
3504 el->values = talloc_array(msg, struct ldb_val, count);
3505 if (!el->values) {
3506 goto failed;
3509 for (i=0; i<count; i++) {
3510 struct ldb_val v;
3511 enum ndr_err_code ndr_err;
3513 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
3514 &r[i],
3515 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3516 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3517 goto failed;
3520 el->num_values++;
3521 el->values[i] = v;
3524 if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3525 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3526 goto failed;
3529 talloc_free(tmp_ctx);
3531 return WERR_OK;
3533 failed:
3534 talloc_free(tmp_ctx);
3535 return WERR_DS_DRA_INTERNAL_ERROR;
3540 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3541 object for a partition
3543 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3544 uint64_t *uSN, uint64_t *urgent_uSN)
3546 struct ldb_request *req;
3547 int ret;
3548 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3549 struct dsdb_control_current_partition *p_ctrl;
3550 struct ldb_result *res;
3552 res = talloc_zero(tmp_ctx, struct ldb_result);
3553 if (!res) {
3554 talloc_free(tmp_ctx);
3555 return ldb_oom(ldb);
3558 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3559 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3560 LDB_SCOPE_BASE,
3561 NULL, NULL,
3562 NULL,
3563 res, ldb_search_default_callback,
3564 NULL);
3565 if (ret != LDB_SUCCESS) {
3566 talloc_free(tmp_ctx);
3567 return ret;
3570 p_ctrl = talloc(req, struct dsdb_control_current_partition);
3571 if (p_ctrl == NULL) {
3572 talloc_free(tmp_ctx);
3573 return ldb_oom(ldb);
3575 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3576 p_ctrl->dn = dn;
3578 ret = ldb_request_add_control(req,
3579 DSDB_CONTROL_CURRENT_PARTITION_OID,
3580 false, p_ctrl);
3581 if (ret != LDB_SUCCESS) {
3582 talloc_free(tmp_ctx);
3583 return ret;
3586 /* Run the new request */
3587 ret = ldb_request(ldb, req);
3589 if (ret == LDB_SUCCESS) {
3590 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3593 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3594 /* it hasn't been created yet, which means
3595 an implicit value of zero */
3596 *uSN = 0;
3597 talloc_free(tmp_ctx);
3598 return LDB_SUCCESS;
3601 if (ret != LDB_SUCCESS) {
3602 talloc_free(tmp_ctx);
3603 return ret;
3606 if (res->count < 1) {
3607 *uSN = 0;
3608 if (urgent_uSN) {
3609 *urgent_uSN = 0;
3611 } else {
3612 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3613 if (urgent_uSN) {
3614 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3618 talloc_free(tmp_ctx);
3620 return LDB_SUCCESS;
3623 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3624 const struct drsuapi_DsReplicaCursor2 *c2)
3626 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3629 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3630 const struct drsuapi_DsReplicaCursor *c2)
3632 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3636 * Return the NTDS object for a GUID, confirming it is in the
3637 * configuration partition and a nTDSDSA object
3639 int samdb_get_ntds_obj_by_guid(TALLOC_CTX *mem_ctx,
3640 struct ldb_context *sam_ctx,
3641 const struct GUID *objectGUID,
3642 const char **attrs,
3643 struct ldb_message **msg)
3645 int ret;
3646 struct ldb_result *res;
3647 struct GUID_txt_buf guid_buf;
3648 char *guid_str = GUID_buf_string(objectGUID, &guid_buf);
3649 struct ldb_dn *config_dn = NULL;
3651 config_dn = ldb_get_config_basedn(sam_ctx);
3652 if (config_dn == NULL) {
3653 return ldb_operr(sam_ctx);
3656 ret = dsdb_search(sam_ctx,
3657 mem_ctx,
3658 &res,
3659 config_dn,
3660 LDB_SCOPE_SUBTREE,
3661 attrs,
3662 DSDB_SEARCH_ONE_ONLY,
3663 "(&(objectGUID=%s)(objectClass=nTDSDSA))",
3664 guid_str);
3665 if (ret != LDB_SUCCESS) {
3666 return ret;
3668 if (msg) {
3669 *msg = talloc_steal(mem_ctx, res->msgs[0]);
3671 TALLOC_FREE(res);
3672 return ret;
3677 see if a computer identified by its objectGUID is a RODC
3679 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3681 /* 1) find the DN for this servers NTDSDSA object
3682 2) search for the msDS-isRODC attribute
3683 3) if not present then not a RODC
3684 4) if present and TRUE then is a RODC
3686 const char *attrs[] = { "msDS-isRODC", NULL };
3687 int ret;
3688 struct ldb_message *msg;
3689 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3691 ret = samdb_get_ntds_obj_by_guid(tmp_ctx,
3692 sam_ctx,
3693 objectGUID,
3694 attrs, &msg);
3696 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3697 *is_rodc = false;
3698 talloc_free(tmp_ctx);
3699 return LDB_SUCCESS;
3702 if (ret != LDB_SUCCESS) {
3703 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
3704 GUID_string(tmp_ctx, objectGUID)));
3705 *is_rodc = false;
3706 talloc_free(tmp_ctx);
3707 return ret;
3710 ret = ldb_msg_find_attr_as_bool(msg, "msDS-isRODC", 0);
3711 *is_rodc = (ret == 1);
3713 talloc_free(tmp_ctx);
3714 return LDB_SUCCESS;
3719 see if we are a RODC
3721 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3723 const struct GUID *objectGUID;
3724 int ret;
3725 bool *cached;
3727 /* see if we have a cached copy */
3728 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3729 if (cached) {
3730 *am_rodc = *cached;
3731 return LDB_SUCCESS;
3734 objectGUID = samdb_ntds_objectGUID(sam_ctx);
3735 if (!objectGUID) {
3736 return ldb_operr(sam_ctx);
3739 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3740 if (ret != LDB_SUCCESS) {
3741 return ret;
3744 cached = talloc(sam_ctx, bool);
3745 if (cached == NULL) {
3746 return ldb_oom(sam_ctx);
3748 *cached = *am_rodc;
3750 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3751 if (ret != LDB_SUCCESS) {
3752 talloc_free(cached);
3753 return ldb_operr(sam_ctx);
3756 return LDB_SUCCESS;
3759 int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
3761 const char *_host_name = NULL;
3762 const char *attrs[] = { "dnsHostName", NULL };
3763 TALLOC_CTX *tmp_ctx = NULL;
3764 int ret;
3765 struct ldb_result *res = NULL;
3767 _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
3768 if (_host_name != NULL) {
3769 *host_name = _host_name;
3770 return LDB_SUCCESS;
3773 tmp_ctx = talloc_new(sam_ctx);
3775 ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
3777 if (res == NULL || res->count != 1 || ret != LDB_SUCCESS) {
3778 DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s",
3779 ldb_errstring(sam_ctx)));
3780 TALLOC_FREE(tmp_ctx);
3781 return ret;
3784 _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
3785 "dnsHostName",
3786 NULL);
3787 if (_host_name == NULL) {
3788 DEBUG(0, ("Failed to get dnsHostName from rootDSE"));
3789 TALLOC_FREE(tmp_ctx);
3790 return LDB_ERR_OPERATIONS_ERROR;
3792 ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
3793 discard_const_p(char *, _host_name));
3794 if (ret != LDB_SUCCESS) {
3795 TALLOC_FREE(tmp_ctx);
3796 return ldb_operr(sam_ctx);
3799 *host_name = talloc_steal(sam_ctx, _host_name);
3801 TALLOC_FREE(tmp_ctx);
3802 return LDB_SUCCESS;
3805 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3807 TALLOC_CTX *tmp_ctx;
3808 bool *cached;
3810 tmp_ctx = talloc_new(ldb);
3811 if (tmp_ctx == NULL) {
3812 goto failed;
3815 cached = talloc(tmp_ctx, bool);
3816 if (!cached) {
3817 goto failed;
3820 *cached = am_rodc;
3821 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3822 goto failed;
3825 talloc_steal(ldb, cached);
3826 talloc_free(tmp_ctx);
3827 return true;
3829 failed:
3830 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3831 talloc_free(tmp_ctx);
3832 return false;
3837 * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3838 * flags are DS_NTDSSETTINGS_OPT_*
3840 int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3841 uint32_t *options)
3843 int rc;
3844 TALLOC_CTX *tmp_ctx;
3845 struct ldb_result *res;
3846 struct ldb_dn *site_dn;
3847 const char *attrs[] = { "options", NULL };
3849 tmp_ctx = talloc_new(ldb_ctx);
3850 if (tmp_ctx == NULL)
3851 goto failed;
3853 /* Retrieve the site dn for the ldb that we
3854 * have open. This is our local site.
3856 site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3857 if (site_dn == NULL)
3858 goto failed;
3860 /* Perform a one level (child) search from the local
3861 * site distinguided name. We're looking for the
3862 * "options" attribute within the nTDSSiteSettings
3863 * object
3865 rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
3866 LDB_SCOPE_ONELEVEL, attrs,
3867 "objectClass=nTDSSiteSettings");
3869 if (rc != LDB_SUCCESS || res->count != 1)
3870 goto failed;
3872 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3874 talloc_free(tmp_ctx);
3876 return LDB_SUCCESS;
3878 failed:
3879 DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
3880 talloc_free(tmp_ctx);
3881 return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
3885 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
3887 flags are DS_NTDS_OPTION_*
3889 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3891 TALLOC_CTX *tmp_ctx;
3892 const char *attrs[] = { "options", NULL };
3893 int ret;
3894 struct ldb_result *res;
3896 tmp_ctx = talloc_new(ldb);
3897 if (tmp_ctx == NULL) {
3898 goto failed;
3901 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3902 if (ret != LDB_SUCCESS) {
3903 goto failed;
3906 if (res->count != 1) {
3907 goto failed;
3910 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3912 talloc_free(tmp_ctx);
3914 return LDB_SUCCESS;
3916 failed:
3917 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3918 talloc_free(tmp_ctx);
3919 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3922 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3924 const char *attrs[] = { "objectCategory", NULL };
3925 int ret;
3926 struct ldb_result *res;
3928 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3929 if (ret != LDB_SUCCESS) {
3930 goto failed;
3933 if (res->count != 1) {
3934 goto failed;
3937 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3939 failed:
3940 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3941 return NULL;
3945 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3946 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3948 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3950 char **tokens, *ret;
3951 size_t i;
3953 tokens = str_list_make(mem_ctx, cn, " -_");
3954 if (tokens == NULL || tokens[0] == NULL) {
3955 return NULL;
3958 /* "tolower()" and "toupper()" should also work properly on 0x00 */
3959 tokens[0][0] = tolower(tokens[0][0]);
3960 for (i = 1; tokens[i] != NULL; i++)
3961 tokens[i][0] = toupper(tokens[i][0]);
3963 ret = talloc_strdup(mem_ctx, tokens[0]);
3964 for (i = 1; tokens[i] != NULL; i++)
3965 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3967 talloc_free(tokens);
3969 return ret;
3973 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3975 int dsdb_functional_level(struct ldb_context *ldb)
3977 int *domainFunctionality =
3978 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3979 if (!domainFunctionality) {
3980 /* this is expected during initial provision */
3981 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3982 return DS_DOMAIN_FUNCTION_2000;
3984 return *domainFunctionality;
3988 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3990 int dsdb_forest_functional_level(struct ldb_context *ldb)
3992 int *forestFunctionality =
3993 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3994 if (!forestFunctionality) {
3995 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3996 return DS_DOMAIN_FUNCTION_2000;
3998 return *forestFunctionality;
4002 * This detects and returns the DC functional level (DS_DOMAIN_FUNCTION_*)
4004 int dsdb_dc_functional_level(struct ldb_context *ldb)
4006 int *dcFunctionality =
4007 talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int);
4008 if (!dcFunctionality) {
4009 /* this is expected during initial provision */
4010 DEBUG(4,(__location__ ": WARNING: domainControllerFunctionality not setup\n"));
4011 return DS_DOMAIN_FUNCTION_2008_R2;
4013 return *dcFunctionality;
4016 const char *dsdb_dc_operatingSystemVersion(int dc_functional_level)
4018 const char *operatingSystemVersion = NULL;
4021 * While we are there also update
4022 * operatingSystem and operatingSystemVersion
4023 * as at least operatingSystemVersion is really
4024 * important for some clients/applications (like exchange).
4027 if (dc_functional_level >= DS_DOMAIN_FUNCTION_2016) {
4028 /* Pretend Windows 2016 */
4029 operatingSystemVersion = "10.0 (14393)";
4030 } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012_R2) {
4031 /* Pretend Windows 2012 R2 */
4032 operatingSystemVersion = "6.3 (9600)";
4033 } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012) {
4034 /* Pretend Windows 2012 */
4035 operatingSystemVersion = "6.2 (9200)";
4036 } else {
4037 /* Pretend Windows 2008 R2 */
4038 operatingSystemVersion = "6.1 (7600)";
4041 return operatingSystemVersion;
4044 int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_context *lp_ctx)
4046 TALLOC_CTX *frame = talloc_stackframe();
4047 int ret;
4049 int db_dc_functional_level;
4050 int db_domain_functional_level;
4051 int db_forest_functional_level;
4052 int lp_dc_functional_level = lpcfg_ad_dc_functional_level(lp_ctx);
4053 bool am_rodc;
4054 struct ldb_message *msg = NULL;
4055 struct ldb_dn *dc_ntds_settings_dn = NULL;
4056 struct ldb_dn *dc_computer_dn = NULL;
4057 const char *operatingSystem = NULL;
4058 const char *operatingSystemVersion = NULL;
4060 db_dc_functional_level = dsdb_dc_functional_level(ldb_ctx);
4061 db_domain_functional_level = dsdb_functional_level(ldb_ctx);
4062 db_forest_functional_level = dsdb_forest_functional_level(ldb_ctx);
4064 if (lp_dc_functional_level < db_domain_functional_level) {
4065 DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
4066 "which is less than the domain functional level of %d\n",
4067 lp_dc_functional_level, db_domain_functional_level);
4068 TALLOC_FREE(frame);
4069 return LDB_ERR_CONSTRAINT_VIOLATION;
4072 if (lp_dc_functional_level < db_forest_functional_level) {
4073 DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
4074 "which is less than the forest functional level of %d\n",
4075 lp_dc_functional_level, db_forest_functional_level);
4076 TALLOC_FREE(frame);
4077 return LDB_ERR_CONSTRAINT_VIOLATION;
4080 /* Check if we need to update the DB */
4081 if (db_dc_functional_level == lp_dc_functional_level) {
4083 * Note that this early return means
4084 * we're not updating operatingSystem and
4085 * operatingSystemVersion.
4087 * But at least for now that's
4088 * exactly what we want.
4090 TALLOC_FREE(frame);
4091 return LDB_SUCCESS;
4094 /* Confirm we are not an RODC before we try a modify */
4095 ret = samdb_rodc(ldb_ctx, &am_rodc);
4096 if (ret != LDB_SUCCESS) {
4097 DBG_ERR("Failed to determine if this server is an RODC\n");
4098 TALLOC_FREE(frame);
4099 return ret;
4102 if (am_rodc) {
4103 DBG_WARNING("Unable to update DC's msDS-Behavior-Version "
4104 "(from %d to %d) and operatingSystem[Version] "
4105 "as we are an RODC\n",
4106 db_dc_functional_level, lp_dc_functional_level);
4107 TALLOC_FREE(frame);
4108 return LDB_SUCCESS;
4111 dc_ntds_settings_dn = samdb_ntds_settings_dn(ldb_ctx, frame);
4113 if (dc_ntds_settings_dn == NULL) {
4114 DBG_ERR("Failed to find own NTDS Settings DN\n");
4115 TALLOC_FREE(frame);
4116 return LDB_ERR_NO_SUCH_OBJECT;
4119 /* Now update our msDS-Behavior-Version */
4121 msg = ldb_msg_new(frame);
4122 if (msg == NULL) {
4123 DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
4124 TALLOC_FREE(frame);
4125 return LDB_ERR_OPERATIONS_ERROR;
4128 msg->dn = dc_ntds_settings_dn;
4130 ret = samdb_msg_add_int(ldb_ctx, frame, msg, "msDS-Behavior-Version", lp_dc_functional_level);
4131 if (ret != LDB_SUCCESS) {
4132 DBG_ERR("Failed to set new msDS-Behavior-Version on message\n");
4133 TALLOC_FREE(frame);
4134 return LDB_ERR_OPERATIONS_ERROR;
4137 ret = dsdb_replace(ldb_ctx, msg, 0);
4138 if (ret != LDB_SUCCESS) {
4139 DBG_ERR("Failed to update DB with new msDS-Behavior-Version on %s: %s\n",
4140 ldb_dn_get_linearized(dc_ntds_settings_dn),
4141 ldb_errstring(ldb_ctx));
4142 TALLOC_FREE(frame);
4143 return ret;
4147 * We have to update the opaque because this particular ldb_context
4148 * will not re-read the DB
4151 int *val = talloc(ldb_ctx, int);
4152 if (!val) {
4153 TALLOC_FREE(frame);
4154 return LDB_ERR_OPERATIONS_ERROR;
4156 *val = lp_dc_functional_level;
4157 ret = ldb_set_opaque(ldb_ctx,
4158 "domainControllerFunctionality", val);
4159 if (ret != LDB_SUCCESS) {
4160 DBG_ERR("Failed to re-set domainControllerFunctionality opaque\n");
4161 TALLOC_FREE(val);
4162 TALLOC_FREE(frame);
4163 return ret;
4168 * While we are there also update
4169 * operatingSystem and operatingSystemVersion
4170 * as at least operatingSystemVersion is really
4171 * important for some clients/applications (like exchange).
4174 operatingSystem = talloc_asprintf(frame, "Samba-%s",
4175 samba_version_string());
4176 if (operatingSystem == NULL) {
4177 TALLOC_FREE(frame);
4178 return ldb_oom(ldb_ctx);
4181 operatingSystemVersion = dsdb_dc_operatingSystemVersion(db_dc_functional_level);
4183 ret = samdb_server_reference_dn(ldb_ctx, frame, &dc_computer_dn);
4184 if (ret != LDB_SUCCESS) {
4185 DBG_ERR("Failed get the dc_computer_dn: %s\n",
4186 ldb_errstring(ldb_ctx));
4187 TALLOC_FREE(frame);
4188 return ret;
4191 msg = ldb_msg_new(frame);
4192 if (msg == NULL) {
4193 DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
4194 TALLOC_FREE(frame);
4195 return LDB_ERR_OPERATIONS_ERROR;
4198 msg->dn = dc_computer_dn;
4200 ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
4201 "operatingSystem",
4202 operatingSystem);
4203 if (ret != LDB_SUCCESS) {
4204 DBG_ERR("Failed to set new operatingSystem on message\n");
4205 TALLOC_FREE(frame);
4206 return ldb_operr(ldb_ctx);
4209 ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
4210 "operatingSystemVersion",
4211 operatingSystemVersion);
4212 if (ret != LDB_SUCCESS) {
4213 DBG_ERR("Failed to set new operatingSystemVersion on message\n");
4214 TALLOC_FREE(frame);
4215 return ldb_operr(ldb_ctx);
4218 ret = dsdb_replace(ldb_ctx, msg, 0);
4219 if (ret != LDB_SUCCESS) {
4220 DBG_ERR("Failed to update DB with new operatingSystem[Version] on %s: %s\n",
4221 ldb_dn_get_linearized(dc_computer_dn),
4222 ldb_errstring(ldb_ctx));
4223 TALLOC_FREE(frame);
4224 return ret;
4227 TALLOC_FREE(frame);
4228 return LDB_SUCCESS;
4233 set a GUID in an extended DN structure
4235 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
4237 struct ldb_val v;
4238 NTSTATUS status;
4239 int ret;
4241 status = GUID_to_ndr_blob(guid, dn, &v);
4242 if (!NT_STATUS_IS_OK(status)) {
4243 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4246 ret = ldb_dn_set_extended_component(dn, component_name, &v);
4247 data_blob_free(&v);
4248 return ret;
4252 return a GUID from a extended DN structure
4254 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
4256 const struct ldb_val *v;
4258 v = ldb_dn_get_extended_component(dn, component_name);
4259 if (v == NULL) {
4260 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4263 return GUID_from_ndr_blob(v, guid);
4267 return a uint64_t from a extended DN structure
4269 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
4271 const struct ldb_val *v;
4272 int error = 0;
4274 v = ldb_dn_get_extended_component(dn, component_name);
4275 if (v == NULL) {
4276 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4279 /* Just check we don't allow the caller to fill our stack */
4280 if (v->length >= 64) {
4281 return NT_STATUS_INVALID_PARAMETER;
4282 } else {
4283 char s[v->length+1];
4284 memcpy(s, v->data, v->length);
4285 s[v->length] = 0;
4287 *val = smb_strtoull(s, NULL, 0, &error, SMB_STR_STANDARD);
4288 if (error != 0) {
4289 return NT_STATUS_INVALID_PARAMETER;
4292 return NT_STATUS_OK;
4296 return a NTTIME from a extended DN structure
4298 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
4300 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
4304 return a uint32_t from a extended DN structure
4306 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
4308 const struct ldb_val *v;
4309 int error = 0;
4311 v = ldb_dn_get_extended_component(dn, component_name);
4312 if (v == NULL) {
4313 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4316 /* Just check we don't allow the caller to fill our stack */
4317 if (v->length >= 32) {
4318 return NT_STATUS_INVALID_PARAMETER;
4319 } else {
4320 char s[v->length + 1];
4321 memcpy(s, v->data, v->length);
4322 s[v->length] = 0;
4323 *val = smb_strtoul(s, NULL, 0, &error, SMB_STR_STANDARD);
4324 if (error != 0) {
4325 return NT_STATUS_INVALID_PARAMETER;
4329 return NT_STATUS_OK;
4333 return a dom_sid from a extended DN structure
4335 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
4337 const struct ldb_val *sid_blob;
4338 enum ndr_err_code ndr_err;
4340 sid_blob = ldb_dn_get_extended_component(dn, component_name);
4341 if (!sid_blob) {
4342 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4345 ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
4346 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
4347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4348 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
4349 return status;
4352 return NT_STATUS_OK;
4357 return RMD_FLAGS directly from a ldb_dn
4358 returns 0 if not found
4360 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
4362 uint32_t rmd_flags = 0;
4363 NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
4364 "RMD_FLAGS");
4365 if (NT_STATUS_IS_OK(status)) {
4366 return rmd_flags;
4368 return 0;
4372 return RMD_FLAGS directly from a ldb_val for a DN
4373 returns 0 if RMD_FLAGS is not found
4375 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
4377 const char *p;
4378 uint32_t flags;
4379 char *end;
4380 int error = 0;
4382 if (val->length < 13) {
4383 return 0;
4385 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
4386 if (!p) {
4387 return 0;
4389 flags = smb_strtoul(p+11, &end, 10, &error, SMB_STR_STANDARD);
4390 if (!end || *end != '>' || error != 0) {
4391 /* it must end in a > */
4392 return 0;
4394 return flags;
4398 return true if a ldb_val containing a DN in storage form is deleted
4400 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
4402 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
4406 return true if a ldb_val containing a DN in storage form is
4407 in the upgraded w2k3 linked attribute format
4409 bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
4411 return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
4415 return a DN for a wellknown GUID
4417 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
4418 struct ldb_dn *nc_root, const char *wk_guid,
4419 struct ldb_dn **wkguid_dn)
4421 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4422 const char *attrs[] = { NULL };
4423 int ret;
4424 struct ldb_dn *dn;
4425 struct ldb_result *res = NULL;
4427 /* construct the magic WKGUID DN */
4428 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
4429 wk_guid, ldb_dn_get_linearized(nc_root));
4430 if (!wkguid_dn) {
4431 talloc_free(tmp_ctx);
4432 return ldb_operr(samdb);
4435 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
4436 DSDB_SEARCH_SHOW_DELETED |
4437 DSDB_SEARCH_SHOW_RECYCLED);
4438 if (ret != LDB_SUCCESS) {
4439 talloc_free(tmp_ctx);
4440 return ret;
4442 /* fix clang warning */
4443 if (res == NULL){
4444 talloc_free(tmp_ctx);
4445 return LDB_ERR_OTHER;
4448 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
4449 talloc_free(tmp_ctx);
4450 return LDB_SUCCESS;
4454 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
4456 return ldb_dn_compare(*dn1, *dn2);
4460 find a NC root given a DN within the NC by reading the rootDSE namingContexts
4462 static int dsdb_find_nc_root_string_based(struct ldb_context *samdb,
4463 TALLOC_CTX *mem_ctx,
4464 struct ldb_dn *dn,
4465 struct ldb_dn **nc_root)
4467 const char *root_attrs[] = { "namingContexts", NULL };
4468 TALLOC_CTX *tmp_ctx;
4469 int ret;
4470 struct ldb_message_element *el;
4471 struct ldb_result *root_res;
4472 unsigned int i;
4473 struct ldb_dn **nc_dns;
4475 tmp_ctx = talloc_new(samdb);
4476 if (tmp_ctx == NULL) {
4477 return ldb_oom(samdb);
4480 ret = ldb_search(samdb, tmp_ctx, &root_res,
4481 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
4482 if (ret != LDB_SUCCESS || root_res->count == 0) {
4483 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
4484 talloc_free(tmp_ctx);
4485 return ret;
4488 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
4489 if ((el == NULL) || (el->num_values < 3)) {
4490 struct ldb_message *tmp_msg;
4492 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
4494 /* This generates a temporary list of NCs in order to let the
4495 * provisioning work. */
4496 tmp_msg = ldb_msg_new(tmp_ctx);
4497 if (tmp_msg == NULL) {
4498 talloc_free(tmp_ctx);
4499 return ldb_oom(samdb);
4501 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4502 ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
4503 if (ret != LDB_SUCCESS) {
4504 talloc_free(tmp_ctx);
4505 return ret;
4507 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4508 ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
4509 if (ret != LDB_SUCCESS) {
4510 talloc_free(tmp_ctx);
4511 return ret;
4513 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4514 ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
4515 if (ret != LDB_SUCCESS) {
4516 talloc_free(tmp_ctx);
4517 return ret;
4519 el = &tmp_msg->elements[0];
4522 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
4523 if (!nc_dns) {
4524 talloc_free(tmp_ctx);
4525 return ldb_oom(samdb);
4528 for (i=0; i<el->num_values; i++) {
4529 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
4530 if (nc_dns[i] == NULL) {
4531 talloc_free(tmp_ctx);
4532 return ldb_operr(samdb);
4536 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
4538 for (i=0; i<el->num_values; i++) {
4539 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
4540 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
4541 talloc_free(tmp_ctx);
4542 return LDB_SUCCESS;
4546 talloc_free(tmp_ctx);
4547 return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4550 struct dsdb_get_partition_and_dn {
4551 TALLOC_CTX *mem_ctx;
4552 unsigned int count;
4553 struct ldb_dn *dn;
4554 struct ldb_dn *partition_dn;
4555 bool want_partition_dn;
4558 static int dsdb_get_partition_and_dn(struct ldb_request *req,
4559 struct ldb_reply *ares)
4561 int ret;
4562 struct dsdb_get_partition_and_dn *context = req->context;
4563 struct ldb_control *partition_ctrl = NULL;
4564 struct dsdb_control_current_partition *partition = NULL;
4566 if (!ares) {
4567 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
4569 if (ares->error != LDB_SUCCESS
4570 && ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4571 return ldb_request_done(req, ares->error);
4574 switch (ares->type) {
4575 case LDB_REPLY_ENTRY:
4576 if (context->count != 0) {
4577 return ldb_request_done(req,
4578 LDB_ERR_CONSTRAINT_VIOLATION);
4580 context->count++;
4582 context->dn = talloc_steal(context->mem_ctx,
4583 ares->message->dn);
4584 break;
4586 case LDB_REPLY_REFERRAL:
4587 talloc_free(ares);
4588 return ldb_request_done(req, LDB_SUCCESS);
4590 case LDB_REPLY_DONE:
4591 partition_ctrl
4592 = ldb_reply_get_control(ares,
4593 DSDB_CONTROL_CURRENT_PARTITION_OID);
4594 if (!context->want_partition_dn ||
4595 partition_ctrl == NULL) {
4596 ret = ares->error;
4597 talloc_free(ares);
4599 return ldb_request_done(req, ret);
4602 partition
4603 = talloc_get_type_abort(partition_ctrl->data,
4604 struct dsdb_control_current_partition);
4605 context->partition_dn
4606 = ldb_dn_copy(context->mem_ctx, partition->dn);
4607 if (context->partition_dn == NULL) {
4608 return ldb_request_done(req,
4609 LDB_ERR_OPERATIONS_ERROR);
4612 ret = ares->error;
4613 talloc_free(ares);
4615 return ldb_request_done(req, ret);
4618 talloc_free(ares);
4619 return LDB_SUCCESS;
4623 find a NC root given a DN within the NC
4625 int dsdb_normalise_dn_and_find_nc_root(struct ldb_context *samdb,
4626 TALLOC_CTX *mem_ctx,
4627 struct ldb_dn *dn,
4628 struct ldb_dn **normalised_dn,
4629 struct ldb_dn **nc_root)
4631 TALLOC_CTX *tmp_ctx;
4632 int ret;
4633 struct ldb_request *req;
4634 struct ldb_result *res;
4635 struct ldb_dn *search_dn = dn;
4636 static const char * attrs[] = { NULL };
4637 bool has_extended = ldb_dn_has_extended(dn);
4638 bool has_normal_components = ldb_dn_get_comp_num(dn) >= 1;
4639 struct dsdb_get_partition_and_dn context = {
4640 .mem_ctx = mem_ctx,
4641 .want_partition_dn = nc_root != NULL
4644 if (!has_extended && !has_normal_components) {
4645 return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT,
4646 "Request for NC root for rootDSE (\"\") denied.");
4649 tmp_ctx = talloc_new(samdb);
4650 if (tmp_ctx == NULL) {
4651 return ldb_oom(samdb);
4654 res = talloc_zero(tmp_ctx, struct ldb_result);
4655 if (res == NULL) {
4656 talloc_free(tmp_ctx);
4657 return ldb_oom(samdb);
4660 if (has_extended && has_normal_components) {
4661 bool minimise_ok;
4662 search_dn = ldb_dn_copy(tmp_ctx, dn);
4663 if (search_dn == NULL) {
4664 talloc_free(tmp_ctx);
4665 return ldb_oom(samdb);
4667 minimise_ok = ldb_dn_minimise(search_dn);
4668 if (!minimise_ok) {
4669 talloc_free(tmp_ctx);
4670 return ldb_operr(samdb);
4674 ret = ldb_build_search_req(&req, samdb, tmp_ctx,
4675 search_dn,
4676 LDB_SCOPE_BASE,
4677 NULL,
4678 attrs,
4679 NULL,
4680 &context,
4681 dsdb_get_partition_and_dn,
4682 NULL);
4683 if (ret != LDB_SUCCESS) {
4684 talloc_free(tmp_ctx);
4685 return ret;
4688 ret = ldb_request_add_control(req,
4689 DSDB_CONTROL_CURRENT_PARTITION_OID,
4690 false, NULL);
4691 if (ret != LDB_SUCCESS) {
4692 talloc_free(tmp_ctx);
4693 return ret;
4696 ret = dsdb_request_add_controls(req,
4697 DSDB_SEARCH_SHOW_RECYCLED|
4698 DSDB_SEARCH_SHOW_DELETED|
4699 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
4700 if (ret != LDB_SUCCESS) {
4701 talloc_free(tmp_ctx);
4702 return ret;
4705 ret = ldb_request(samdb, req);
4706 if (ret == LDB_SUCCESS) {
4707 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4711 * This could be a new DN, not in the DB, which is OK. If we
4712 * don't need the normalised DN, we can continue.
4714 * We may be told the partition it would be in in the search
4715 * reply control, or if not we can do a string-based match.
4718 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4719 if (normalised_dn != NULL) {
4720 talloc_free(tmp_ctx);
4721 return ret;
4723 ret = LDB_SUCCESS;
4724 ldb_reset_err_string(samdb);
4725 } else if (ret != LDB_SUCCESS) {
4726 talloc_free(tmp_ctx);
4727 return ret;
4730 if (normalised_dn != NULL) {
4731 if (context.count != 1) {
4732 /* No results */
4733 ldb_asprintf_errstring(samdb,
4734 "Request for NC root for %s failed to return any results.",
4735 ldb_dn_get_linearized(dn));
4736 return LDB_ERR_NO_SUCH_OBJECT;
4738 *normalised_dn = context.dn;
4742 * If the user did not need to find the nc_root,
4743 * we are done
4745 if (nc_root == NULL) {
4746 talloc_free(tmp_ctx);
4747 return ret;
4751 * When we are working locally, both for the case were
4752 * we find the DN, and the case where we fail, we get
4753 * back via controls the partition it was in or should
4754 * have been in, to return to the client
4756 if (context.partition_dn != NULL) {
4757 (*nc_root) = context.partition_dn;
4759 talloc_free(tmp_ctx);
4760 return ret;
4764 * This is a remote operation, which is a little harder as we
4765 * have a work out the nc_root from the list of NCs. If we did
4766 * at least resolve the DN to a string, get that now, it makes
4767 * the string-based match below possible for a GUID-based
4768 * input over remote LDAP.
4770 if (context.dn) {
4771 dn = context.dn;
4772 } else if (has_extended && !has_normal_components) {
4773 ldb_asprintf_errstring(samdb,
4774 "Cannot determine NC root "
4775 "for a not-found bare extended DN %s.",
4776 ldb_dn_get_extended_linearized(tmp_ctx, dn, 1));
4777 talloc_free(tmp_ctx);
4778 return LDB_ERR_NO_SUCH_OBJECT;
4782 * Either we are working aginast a remote LDAP
4783 * server or the object doesn't exist locally.
4785 * This means any GUID that was present in the DN
4786 * therefore could not be evaluated, so do a
4787 * string-based match instead.
4789 talloc_free(tmp_ctx);
4790 return dsdb_find_nc_root_string_based(samdb,
4791 mem_ctx,
4793 nc_root);
4797 find a NC root given a DN within the NC
4799 int dsdb_find_nc_root(struct ldb_context *samdb,
4800 TALLOC_CTX *mem_ctx,
4801 struct ldb_dn *dn,
4802 struct ldb_dn **nc_root)
4804 return dsdb_normalise_dn_and_find_nc_root(samdb,
4805 mem_ctx,
4807 NULL,
4808 nc_root);
4812 find the deleted objects DN for any object, by looking for the NC
4813 root, then looking up the wellknown GUID
4815 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
4816 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
4817 struct ldb_dn **do_dn)
4819 struct ldb_dn *nc_root;
4820 int ret;
4822 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
4823 if (ret != LDB_SUCCESS) {
4824 return ret;
4827 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
4828 talloc_free(nc_root);
4829 return ret;
4833 return the tombstoneLifetime, in days
4835 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
4837 struct ldb_dn *dn;
4838 dn = ldb_get_config_basedn(ldb);
4839 if (!dn) {
4840 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4842 dn = ldb_dn_copy(ldb, dn);
4843 if (!dn) {
4844 return ldb_operr(ldb);
4846 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
4847 be a wellknown GUID for this */
4848 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
4849 talloc_free(dn);
4850 return ldb_operr(ldb);
4853 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
4854 talloc_free(dn);
4855 return LDB_SUCCESS;
4859 compare a ldb_val to a string case insensitively
4861 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
4863 size_t len = strlen(s);
4864 int ret;
4865 if (len > v->length) return 1;
4866 ret = strncasecmp(s, (const char *)v->data, v->length);
4867 if (ret != 0) return ret;
4868 if (v->length > len && v->data[len] != 0) {
4869 return -1;
4871 return 0;
4876 load the UDV for a partition in v2 format
4877 The list is returned sorted, and with our local cursor added
4879 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4880 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
4882 static const char *attrs[] = { "replUpToDateVector", NULL };
4883 struct ldb_result *r = NULL;
4884 const struct ldb_val *ouv_value;
4885 unsigned int i;
4886 int ret;
4887 uint64_t highest_usn = 0;
4888 const struct GUID *our_invocation_id;
4889 static const struct timeval tv1970;
4890 NTTIME nt1970 = timeval_to_nttime(&tv1970);
4892 ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
4893 if (ret != LDB_SUCCESS) {
4894 return ret;
4896 /* fix clang warning */
4897 if (r == NULL) {
4898 return LDB_ERR_OTHER;
4900 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
4901 if (ouv_value) {
4902 enum ndr_err_code ndr_err;
4903 struct replUpToDateVectorBlob ouv;
4905 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
4906 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4907 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4908 talloc_free(r);
4909 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4911 if (ouv.version != 2) {
4912 /* we always store as version 2, and
4913 * replUpToDateVector is not replicated
4915 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4918 *count = ouv.ctr.ctr2.count;
4919 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
4920 } else {
4921 *count = 0;
4922 *cursors = NULL;
4925 talloc_free(r);
4927 our_invocation_id = samdb_ntds_invocation_id(samdb);
4928 if (!our_invocation_id) {
4929 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
4930 talloc_free(*cursors);
4931 return ldb_operr(samdb);
4934 ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
4935 if (ret != LDB_SUCCESS) {
4936 /* nothing to add - this can happen after a vampire */
4937 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4938 return LDB_SUCCESS;
4941 for (i=0; i<*count; i++) {
4942 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
4943 (*cursors)[i].highest_usn = highest_usn;
4944 (*cursors)[i].last_sync_success = nt1970;
4945 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4946 return LDB_SUCCESS;
4950 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
4951 if (! *cursors) {
4952 return ldb_oom(samdb);
4955 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
4956 (*cursors)[*count].highest_usn = highest_usn;
4957 (*cursors)[*count].last_sync_success = nt1970;
4958 (*count)++;
4960 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4962 return LDB_SUCCESS;
4966 load the UDV for a partition in version 1 format
4967 The list is returned sorted, and with our local cursor added
4969 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4970 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
4972 struct drsuapi_DsReplicaCursor2 *v2 = NULL;
4973 uint32_t i;
4974 int ret;
4976 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
4977 if (ret != LDB_SUCCESS) {
4978 return ret;
4981 if (*count == 0) {
4982 talloc_free(v2);
4983 *cursors = NULL;
4984 return LDB_SUCCESS;
4987 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
4988 if (*cursors == NULL) {
4989 talloc_free(v2);
4990 return ldb_oom(samdb);
4993 for (i=0; i<*count; i++) {
4994 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
4995 (*cursors)[i].highest_usn = v2[i].highest_usn;
4997 talloc_free(v2);
4998 return LDB_SUCCESS;
5002 add a set of controls to a ldb_request structure based on a set of
5003 flags. See util.h for a list of available flags
5005 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
5007 int ret;
5008 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
5009 struct ldb_search_options_control *options;
5010 /* Using the phantom root control allows us to search all partitions */
5011 options = talloc(req, struct ldb_search_options_control);
5012 if (options == NULL) {
5013 return LDB_ERR_OPERATIONS_ERROR;
5015 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
5017 ret = ldb_request_add_control(req,
5018 LDB_CONTROL_SEARCH_OPTIONS_OID,
5019 true, options);
5020 if (ret != LDB_SUCCESS) {
5021 return ret;
5025 if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
5026 ret = ldb_request_add_control(req,
5027 DSDB_CONTROL_NO_GLOBAL_CATALOG,
5028 false, NULL);
5029 if (ret != LDB_SUCCESS) {
5030 return ret;
5034 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
5035 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
5036 if (ret != LDB_SUCCESS) {
5037 return ret;
5041 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
5042 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
5043 if (ret != LDB_SUCCESS) {
5044 return ret;
5048 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
5049 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
5050 if (ret != LDB_SUCCESS) {
5051 return ret;
5055 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
5056 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
5057 if (!extended_ctrl) {
5058 return LDB_ERR_OPERATIONS_ERROR;
5060 extended_ctrl->type = 1;
5062 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
5063 if (ret != LDB_SUCCESS) {
5064 return ret;
5068 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
5069 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
5070 if (ret != LDB_SUCCESS) {
5071 return ret;
5075 if (dsdb_flags & DSDB_MODIFY_RELAX) {
5076 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
5077 if (ret != LDB_SUCCESS) {
5078 return ret;
5082 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
5083 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
5084 if (ret != LDB_SUCCESS) {
5085 return ret;
5089 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
5090 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
5091 if (ret != LDB_SUCCESS) {
5092 return ret;
5096 if (dsdb_flags & DSDB_TREE_DELETE) {
5097 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
5098 if (ret != LDB_SUCCESS) {
5099 return ret;
5103 if (dsdb_flags & DSDB_PROVISION) {
5104 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
5105 if (ret != LDB_SUCCESS) {
5106 return ret;
5110 /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
5111 if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
5112 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
5113 if (ret != LDB_SUCCESS) {
5114 return ret;
5118 if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
5120 * This must not be critical, as it will only be
5121 * handled (and need to be handled) if the other
5122 * attributes in the request bring password_hash into
5123 * action
5125 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
5126 if (ret != LDB_SUCCESS) {
5127 return ret;
5131 if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
5132 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
5133 if (ret != LDB_SUCCESS) {
5134 return ret;
5138 if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
5139 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
5140 if (ret != LDB_SUCCESS) {
5141 return ret;
5145 if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
5146 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
5147 if (ret != LDB_SUCCESS) {
5148 return ret;
5152 if (dsdb_flags & DSDB_FLAG_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE) {
5153 ret = ldb_request_add_control(req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID, true, NULL);
5154 if (ret != LDB_SUCCESS) {
5155 return ret;
5159 if (dsdb_flags & DSDB_MARK_REQ_UNTRUSTED) {
5160 ldb_req_mark_untrusted(req);
5163 return LDB_SUCCESS;
5167 returns true if a control with the specified "oid" exists
5169 bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
5171 return (ldb_request_get_control(req, oid) != NULL);
5175 an add with a set of controls
5177 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
5178 uint32_t dsdb_flags)
5180 struct ldb_request *req;
5181 int ret;
5183 ret = ldb_build_add_req(&req, ldb, ldb,
5184 message,
5185 NULL,
5186 NULL,
5187 ldb_op_default_callback,
5188 NULL);
5190 if (ret != LDB_SUCCESS) return ret;
5192 ret = dsdb_request_add_controls(req, dsdb_flags);
5193 if (ret != LDB_SUCCESS) {
5194 talloc_free(req);
5195 return ret;
5198 ret = dsdb_autotransaction_request(ldb, req);
5200 talloc_free(req);
5201 return ret;
5205 a modify with a set of controls
5207 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
5208 uint32_t dsdb_flags)
5210 struct ldb_request *req;
5211 int ret;
5213 ret = ldb_build_mod_req(&req, ldb, ldb,
5214 message,
5215 NULL,
5216 NULL,
5217 ldb_op_default_callback,
5218 NULL);
5220 if (ret != LDB_SUCCESS) return ret;
5222 ret = dsdb_request_add_controls(req, dsdb_flags);
5223 if (ret != LDB_SUCCESS) {
5224 talloc_free(req);
5225 return ret;
5228 ret = dsdb_autotransaction_request(ldb, req);
5230 talloc_free(req);
5231 return ret;
5235 a delete with a set of flags
5237 int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
5238 uint32_t dsdb_flags)
5240 struct ldb_request *req;
5241 int ret;
5243 ret = ldb_build_del_req(&req, ldb, ldb,
5245 NULL,
5246 NULL,
5247 ldb_op_default_callback,
5248 NULL);
5250 if (ret != LDB_SUCCESS) return ret;
5252 ret = dsdb_request_add_controls(req, dsdb_flags);
5253 if (ret != LDB_SUCCESS) {
5254 talloc_free(req);
5255 return ret;
5258 ret = dsdb_autotransaction_request(ldb, req);
5260 talloc_free(req);
5261 return ret;
5265 like dsdb_modify() but set all the element flags to
5266 LDB_FLAG_MOD_REPLACE
5268 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
5270 unsigned int i;
5272 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5273 for (i=0;i<msg->num_elements;i++) {
5274 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5277 return dsdb_modify(ldb, msg, dsdb_flags);
5280 const char *dsdb_search_scope_as_string(enum ldb_scope scope)
5282 const char *scope_str;
5284 switch (scope) {
5285 case LDB_SCOPE_BASE:
5286 scope_str = "BASE";
5287 break;
5288 case LDB_SCOPE_ONELEVEL:
5289 scope_str = "ONE";
5290 break;
5291 case LDB_SCOPE_SUBTREE:
5292 scope_str = "SUB";
5293 break;
5294 default:
5295 scope_str = "<Invalid scope>";
5296 break;
5298 return scope_str;
5303 search for attrs on one DN, allowing for dsdb_flags controls
5305 int dsdb_search_dn(struct ldb_context *ldb,
5306 TALLOC_CTX *mem_ctx,
5307 struct ldb_result **_result,
5308 struct ldb_dn *basedn,
5309 const char * const *attrs,
5310 uint32_t dsdb_flags)
5312 int ret;
5313 struct ldb_request *req;
5314 struct ldb_result *res;
5315 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5317 res = talloc_zero(tmp_ctx, struct ldb_result);
5318 if (!res) {
5319 talloc_free(tmp_ctx);
5320 return ldb_oom(ldb);
5323 ret = ldb_build_search_req(&req, ldb, res,
5324 basedn,
5325 LDB_SCOPE_BASE,
5326 NULL,
5327 attrs,
5328 NULL,
5329 res,
5330 ldb_search_default_callback,
5331 NULL);
5332 if (ret != LDB_SUCCESS) {
5333 talloc_free(tmp_ctx);
5334 return ret;
5337 ret = dsdb_request_add_controls(req, dsdb_flags);
5338 if (ret != LDB_SUCCESS) {
5339 talloc_free(tmp_ctx);
5340 return ret;
5343 ret = ldb_request(ldb, req);
5344 if (ret == LDB_SUCCESS) {
5345 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
5348 talloc_free(req);
5349 if (ret != LDB_SUCCESS) {
5350 DBG_INFO("flags=0x%08x %s -> %s (%s)\n",
5351 dsdb_flags,
5352 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5353 basedn,
5354 1):"NULL",
5355 ldb_errstring(ldb), ldb_strerror(ret));
5356 talloc_free(tmp_ctx);
5357 return ret;
5360 DBG_DEBUG("flags=0x%08x %s -> %d\n",
5361 dsdb_flags,
5362 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5363 basedn,
5364 1):"NULL",
5365 res->count);
5367 *_result = talloc_steal(mem_ctx, res);
5369 talloc_free(tmp_ctx);
5370 return LDB_SUCCESS;
5374 search for attrs on one DN, by the GUID of the DN, allowing for
5375 dsdb_flags controls
5377 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
5378 TALLOC_CTX *mem_ctx,
5379 struct ldb_result **_result,
5380 const struct GUID *guid,
5381 const char * const *attrs,
5382 uint32_t dsdb_flags)
5384 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5385 struct ldb_dn *dn;
5386 int ret;
5388 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
5389 if (dn == NULL) {
5390 talloc_free(tmp_ctx);
5391 return ldb_oom(ldb);
5394 ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
5395 talloc_free(tmp_ctx);
5396 return ret;
5400 general search with dsdb_flags for controls
5402 int dsdb_search(struct ldb_context *ldb,
5403 TALLOC_CTX *mem_ctx,
5404 struct ldb_result **_result,
5405 struct ldb_dn *basedn,
5406 enum ldb_scope scope,
5407 const char * const *attrs,
5408 uint32_t dsdb_flags,
5409 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
5411 int ret;
5412 struct ldb_request *req;
5413 struct ldb_result *res;
5414 va_list ap;
5415 char *expression = NULL;
5416 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5418 /* cross-partitions searches with a basedn break multi-domain support */
5419 SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
5421 res = talloc_zero(tmp_ctx, struct ldb_result);
5422 if (!res) {
5423 talloc_free(tmp_ctx);
5424 return ldb_oom(ldb);
5427 if (exp_fmt) {
5428 va_start(ap, exp_fmt);
5429 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
5430 va_end(ap);
5432 if (!expression) {
5433 talloc_free(tmp_ctx);
5434 return ldb_oom(ldb);
5438 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
5439 basedn,
5440 scope,
5441 expression,
5442 attrs,
5443 NULL,
5444 res,
5445 ldb_search_default_callback,
5446 NULL);
5447 if (ret != LDB_SUCCESS) {
5448 talloc_free(tmp_ctx);
5449 return ret;
5452 ret = dsdb_request_add_controls(req, dsdb_flags);
5453 if (ret != LDB_SUCCESS) {
5454 talloc_free(tmp_ctx);
5455 ldb_reset_err_string(ldb);
5456 return ret;
5459 ret = ldb_request(ldb, req);
5460 if (ret == LDB_SUCCESS) {
5461 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
5464 if (ret != LDB_SUCCESS) {
5465 DBG_INFO("%s flags=0x%08x %s %s -> %s (%s)\n",
5466 dsdb_search_scope_as_string(scope),
5467 dsdb_flags,
5468 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5469 basedn,
5470 1):"NULL",
5471 expression?expression:"NULL",
5472 ldb_errstring(ldb), ldb_strerror(ret));
5473 talloc_free(tmp_ctx);
5474 return ret;
5477 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
5478 if (res->count == 0) {
5479 DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u results\n",
5480 dsdb_search_scope_as_string(scope),
5481 dsdb_flags,
5482 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5483 basedn,
5484 1):"NULL",
5485 expression?expression:"NULL", res->count);
5486 talloc_free(tmp_ctx);
5487 ldb_reset_err_string(ldb);
5488 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
5490 if (res->count != 1) {
5491 DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u (expected 1) results\n",
5492 dsdb_search_scope_as_string(scope),
5493 dsdb_flags,
5494 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5495 basedn,
5496 1):"NULL",
5497 expression?expression:"NULL", res->count);
5498 talloc_free(tmp_ctx);
5499 ldb_reset_err_string(ldb);
5500 return LDB_ERR_CONSTRAINT_VIOLATION;
5504 *_result = talloc_steal(mem_ctx, res);
5506 DBG_DEBUG("%s flags=0x%08x %s %s -> %d\n",
5507 dsdb_search_scope_as_string(scope),
5508 dsdb_flags,
5509 basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5510 basedn,
5511 1):"NULL",
5512 expression?expression:"NULL",
5513 res->count);
5514 talloc_free(tmp_ctx);
5515 return LDB_SUCCESS;
5520 general search with dsdb_flags for controls
5521 returns exactly 1 record or an error
5523 int dsdb_search_one(struct ldb_context *ldb,
5524 TALLOC_CTX *mem_ctx,
5525 struct ldb_message **msg,
5526 struct ldb_dn *basedn,
5527 enum ldb_scope scope,
5528 const char * const *attrs,
5529 uint32_t dsdb_flags,
5530 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
5532 int ret;
5533 struct ldb_result *res;
5534 va_list ap;
5535 char *expression = NULL;
5536 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5538 dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
5540 res = talloc_zero(tmp_ctx, struct ldb_result);
5541 if (!res) {
5542 talloc_free(tmp_ctx);
5543 return ldb_oom(ldb);
5546 if (exp_fmt) {
5547 va_start(ap, exp_fmt);
5548 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
5549 va_end(ap);
5551 if (!expression) {
5552 talloc_free(tmp_ctx);
5553 return ldb_oom(ldb);
5555 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
5556 dsdb_flags, "%s", expression);
5557 } else {
5558 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
5559 dsdb_flags, NULL);
5562 if (ret != LDB_SUCCESS) {
5563 talloc_free(tmp_ctx);
5564 return ret;
5567 *msg = talloc_steal(mem_ctx, res->msgs[0]);
5568 talloc_free(tmp_ctx);
5570 return LDB_SUCCESS;
5573 /* returns back the forest DNS name */
5574 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
5576 const char *forest_name = ldb_dn_canonical_string(mem_ctx,
5577 ldb_get_root_basedn(ldb));
5578 char *p;
5580 if (forest_name == NULL) {
5581 return NULL;
5584 p = strchr(forest_name, '/');
5585 if (p) {
5586 *p = '\0';
5589 return forest_name;
5592 /* returns back the default domain DNS name */
5593 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
5595 const char *domain_name = ldb_dn_canonical_string(mem_ctx,
5596 ldb_get_default_basedn(ldb));
5597 char *p;
5599 if (domain_name == NULL) {
5600 return NULL;
5603 p = strchr(domain_name, '/');
5604 if (p) {
5605 *p = '\0';
5608 return domain_name;
5612 validate that an DSA GUID belongs to the specified user sid.
5613 The user SID must be a domain controller account (either RODC or
5614 RWDC)
5616 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
5617 const struct GUID *dsa_guid,
5618 const struct dom_sid *sid)
5620 /* strategy:
5621 - find DN of record with the DSA GUID in the
5622 configuration partition (objectGUID)
5623 - remove "NTDS Settings" component from DN
5624 - do a base search on that DN for serverReference with
5625 extended-dn enabled
5626 - extract objectSid from resulting serverReference
5627 attribute
5628 - check this sid matches the sid argument
5630 struct ldb_dn *config_dn;
5631 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5632 struct ldb_message *msg;
5633 const char *attrs1[] = { NULL };
5634 const char *attrs2[] = { "serverReference", NULL };
5635 int ret;
5636 struct ldb_dn *dn, *account_dn;
5637 struct dom_sid sid2;
5638 NTSTATUS status;
5640 config_dn = ldb_get_config_basedn(ldb);
5642 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
5643 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
5644 if (ret != LDB_SUCCESS) {
5645 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
5646 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5647 talloc_free(tmp_ctx);
5648 return ldb_operr(ldb);
5650 dn = msg->dn;
5652 if (!ldb_dn_remove_child_components(dn, 1)) {
5653 talloc_free(tmp_ctx);
5654 return ldb_operr(ldb);
5657 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
5658 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
5659 "(objectClass=server)");
5660 if (ret != LDB_SUCCESS) {
5661 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
5662 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5663 talloc_free(tmp_ctx);
5664 return ldb_operr(ldb);
5667 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
5668 if (account_dn == NULL) {
5669 DEBUG(1,(__location__ ": Failed to find account dn "
5670 "(serverReference) for %s, parent of DSA with "
5671 "objectGUID %s, sid %s\n",
5672 ldb_dn_get_linearized(msg->dn),
5673 GUID_string(tmp_ctx, dsa_guid),
5674 dom_sid_string(tmp_ctx, sid)));
5675 talloc_free(tmp_ctx);
5676 return ldb_operr(ldb);
5679 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
5680 if (!NT_STATUS_IS_OK(status)) {
5681 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
5682 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5683 talloc_free(tmp_ctx);
5684 return ldb_operr(ldb);
5687 if (!dom_sid_equal(sid, &sid2)) {
5688 /* someone is trying to spoof another account */
5689 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
5690 GUID_string(tmp_ctx, dsa_guid),
5691 dom_sid_string(tmp_ctx, sid),
5692 dom_sid_string(tmp_ctx, &sid2)));
5693 talloc_free(tmp_ctx);
5694 return ldb_operr(ldb);
5697 talloc_free(tmp_ctx);
5698 return LDB_SUCCESS;
5701 static const char * const secret_attributes[] = {
5702 DSDB_SECRET_ATTRIBUTES,
5703 NULL
5707 check if the attribute belongs to the RODC filtered attribute set
5708 Note that attributes that are in the filtered attribute set are the
5709 ones that _are_ always sent to a RODC
5711 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
5713 /* they never get secret attributes */
5714 if (ldb_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
5715 return false;
5718 /* they do get non-secret critical attributes */
5719 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
5720 return true;
5723 /* they do get non-secret attributes marked as being in the FAS */
5724 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
5725 return true;
5728 /* other attributes are denied */
5729 return false;
5732 /* return fsmo role dn and role owner dn for a particular role*/
5733 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
5734 struct ldb_context *ldb,
5735 uint32_t role,
5736 struct ldb_dn **fsmo_role_dn,
5737 struct ldb_dn **role_owner_dn)
5739 int ret;
5740 switch (role) {
5741 case DREPL_NAMING_MASTER:
5742 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
5743 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5744 if (ret != LDB_SUCCESS) {
5745 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
5746 ldb_errstring(ldb)));
5747 talloc_free(tmp_ctx);
5748 return WERR_DS_DRA_INTERNAL_ERROR;
5750 break;
5751 case DREPL_INFRASTRUCTURE_MASTER:
5752 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
5753 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5754 if (ret != LDB_SUCCESS) {
5755 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
5756 ldb_errstring(ldb)));
5757 talloc_free(tmp_ctx);
5758 return WERR_DS_DRA_INTERNAL_ERROR;
5760 break;
5761 case DREPL_RID_MASTER:
5762 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
5763 if (ret != LDB_SUCCESS) {
5764 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
5765 talloc_free(tmp_ctx);
5766 return WERR_DS_DRA_INTERNAL_ERROR;
5769 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5770 if (ret != LDB_SUCCESS) {
5771 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
5772 ldb_errstring(ldb)));
5773 talloc_free(tmp_ctx);
5774 return WERR_DS_DRA_INTERNAL_ERROR;
5776 break;
5777 case DREPL_SCHEMA_MASTER:
5778 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
5779 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5780 if (ret != LDB_SUCCESS) {
5781 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
5782 ldb_errstring(ldb)));
5783 talloc_free(tmp_ctx);
5784 return WERR_DS_DRA_INTERNAL_ERROR;
5786 break;
5787 case DREPL_PDC_MASTER:
5788 *fsmo_role_dn = ldb_get_default_basedn(ldb);
5789 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
5790 if (ret != LDB_SUCCESS) {
5791 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
5792 ldb_errstring(ldb)));
5793 talloc_free(tmp_ctx);
5794 return WERR_DS_DRA_INTERNAL_ERROR;
5796 break;
5797 default:
5798 return WERR_DS_DRA_INTERNAL_ERROR;
5800 return WERR_OK;
5803 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
5804 TALLOC_CTX *mem_ctx,
5805 struct ldb_dn *server_dn)
5807 int ldb_ret;
5808 struct ldb_result *res = NULL;
5809 const char * const attrs[] = { "dNSHostName", NULL};
5811 ldb_ret = ldb_search(ldb, mem_ctx, &res,
5812 server_dn,
5813 LDB_SCOPE_BASE,
5814 attrs, NULL);
5815 if (ldb_ret != LDB_SUCCESS) {
5816 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
5817 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
5818 return NULL;
5821 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
5825 returns true if an attribute is in the filter,
5826 false otherwise, provided that attribute value is provided with the expression
5828 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
5829 const char *attr)
5831 unsigned int i;
5832 switch (tree->operation) {
5833 case LDB_OP_AND:
5834 case LDB_OP_OR:
5835 for (i=0;i<tree->u.list.num_elements;i++) {
5836 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
5837 attr))
5838 return true;
5840 return false;
5841 case LDB_OP_NOT:
5842 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
5843 case LDB_OP_EQUALITY:
5844 case LDB_OP_GREATER:
5845 case LDB_OP_LESS:
5846 case LDB_OP_APPROX:
5847 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
5848 return true;
5850 return false;
5851 case LDB_OP_SUBSTRING:
5852 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
5853 return true;
5855 return false;
5856 case LDB_OP_PRESENT:
5857 /* (attrname=*) is not filtered out */
5858 return false;
5859 case LDB_OP_EXTENDED:
5860 if (tree->u.extended.attr &&
5861 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
5862 return true;
5864 return false;
5866 return false;
5869 int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
5870 const char *location, const char *func,
5871 const char *reason)
5873 if (reason == NULL) {
5874 reason = win_errstr(werr);
5876 ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
5877 W_ERROR_V(werr), reason, location, func);
5878 return ldb_ecode;
5882 map an ldb error code to an approximate NTSTATUS code
5884 NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
5886 switch (err) {
5887 case LDB_SUCCESS:
5888 return NT_STATUS_OK;
5890 case LDB_ERR_PROTOCOL_ERROR:
5891 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
5893 case LDB_ERR_TIME_LIMIT_EXCEEDED:
5894 return NT_STATUS_IO_TIMEOUT;
5896 case LDB_ERR_SIZE_LIMIT_EXCEEDED:
5897 return NT_STATUS_BUFFER_TOO_SMALL;
5899 case LDB_ERR_COMPARE_FALSE:
5900 case LDB_ERR_COMPARE_TRUE:
5901 return NT_STATUS_REVISION_MISMATCH;
5903 case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
5904 return NT_STATUS_NOT_SUPPORTED;
5906 case LDB_ERR_STRONG_AUTH_REQUIRED:
5907 case LDB_ERR_CONFIDENTIALITY_REQUIRED:
5908 case LDB_ERR_SASL_BIND_IN_PROGRESS:
5909 case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
5910 case LDB_ERR_INVALID_CREDENTIALS:
5911 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
5912 case LDB_ERR_UNWILLING_TO_PERFORM:
5913 return NT_STATUS_ACCESS_DENIED;
5915 case LDB_ERR_NO_SUCH_OBJECT:
5916 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5918 case LDB_ERR_REFERRAL:
5919 case LDB_ERR_NO_SUCH_ATTRIBUTE:
5920 return NT_STATUS_NOT_FOUND;
5922 case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
5923 return NT_STATUS_NOT_SUPPORTED;
5925 case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
5926 return NT_STATUS_BUFFER_TOO_SMALL;
5928 case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
5929 case LDB_ERR_INAPPROPRIATE_MATCHING:
5930 case LDB_ERR_CONSTRAINT_VIOLATION:
5931 case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
5932 case LDB_ERR_INVALID_DN_SYNTAX:
5933 case LDB_ERR_NAMING_VIOLATION:
5934 case LDB_ERR_OBJECT_CLASS_VIOLATION:
5935 case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
5936 case LDB_ERR_NOT_ALLOWED_ON_RDN:
5937 return NT_STATUS_INVALID_PARAMETER;
5939 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
5940 case LDB_ERR_ENTRY_ALREADY_EXISTS:
5941 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
5943 case LDB_ERR_BUSY:
5944 return NT_STATUS_NETWORK_BUSY;
5946 case LDB_ERR_ALIAS_PROBLEM:
5947 case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
5948 case LDB_ERR_UNAVAILABLE:
5949 case LDB_ERR_LOOP_DETECT:
5950 case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
5951 case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
5952 case LDB_ERR_OTHER:
5953 case LDB_ERR_OPERATIONS_ERROR:
5954 break;
5956 return NT_STATUS_UNSUCCESSFUL;
5961 create a new naming context that will hold a partial replica
5963 int dsdb_create_partial_replica_NC(struct ldb_context *ldb, struct ldb_dn *dn)
5965 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5966 struct ldb_message *msg;
5967 int ret;
5969 msg = ldb_msg_new(tmp_ctx);
5970 if (msg == NULL) {
5971 talloc_free(tmp_ctx);
5972 return ldb_oom(ldb);
5975 msg->dn = dn;
5976 ret = ldb_msg_add_string(msg, "objectClass", "top");
5977 if (ret != LDB_SUCCESS) {
5978 talloc_free(tmp_ctx);
5979 return ldb_oom(ldb);
5982 /* [MS-DRSR] implies that we should only add the 'top'
5983 * objectclass, but that would cause lots of problems with our
5984 * objectclass code as top is not structural, so we add
5985 * 'domainDNS' as well to keep things sane. We're expecting
5986 * this new NC to be of objectclass domainDNS after
5987 * replication anyway
5989 ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
5990 if (ret != LDB_SUCCESS) {
5991 talloc_free(tmp_ctx);
5992 return ldb_oom(ldb);
5995 ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
5996 INSTANCE_TYPE_IS_NC_HEAD|
5997 INSTANCE_TYPE_NC_ABOVE|
5998 INSTANCE_TYPE_UNINSTANT);
5999 if (ret != LDB_SUCCESS) {
6000 talloc_free(tmp_ctx);
6001 return ldb_oom(ldb);
6004 ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
6005 if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
6006 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
6007 ldb_dn_get_linearized(dn),
6008 ldb_errstring(ldb), ldb_strerror(ret)));
6009 talloc_free(tmp_ctx);
6010 return ret;
6013 DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
6015 talloc_free(tmp_ctx);
6016 return LDB_SUCCESS;
6020 * Return the effective badPwdCount
6022 * This requires that the user_msg have (if present):
6023 * - badPasswordTime
6024 * - badPwdCount
6026 * This also requires that the domain_msg have (if present):
6027 * - lockOutObservationWindow
6029 int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
6030 int64_t lockOutObservationWindow,
6031 NTTIME now)
6033 int64_t badPasswordTime;
6034 badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
6036 if (badPasswordTime - lockOutObservationWindow >= now) {
6037 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
6038 } else {
6039 return 0;
6044 * Returns a user's PSO, or NULL if none was found
6046 static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
6047 TALLOC_CTX *mem_ctx,
6048 const struct ldb_message *user_msg,
6049 const char * const *attrs)
6051 struct ldb_result *res = NULL;
6052 struct ldb_dn *pso_dn = NULL;
6053 int ret;
6055 /* if the user has a PSO that applies, then use the PSO's setting */
6056 pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
6057 "msDS-ResultantPSO");
6059 if (pso_dn != NULL) {
6061 ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
6062 if (ret != LDB_SUCCESS) {
6065 * log the error. The caller should fallback to using
6066 * the default domain password settings
6068 DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s",
6069 ldb_dn_get_linearized(pso_dn),
6070 ldb_dn_get_linearized(user_msg->dn));
6072 talloc_free(pso_dn);
6074 return res;
6078 * Return the msDS-LockoutObservationWindow for a user message
6080 * This requires that the user_msg have (if present):
6081 * - msDS-ResultantPSO
6083 int64_t samdb_result_msds_LockoutObservationWindow(
6084 struct ldb_context *sam_ldb,
6085 TALLOC_CTX *mem_ctx,
6086 struct ldb_dn *domain_dn,
6087 const struct ldb_message *user_msg)
6089 int64_t lockOutObservationWindow;
6090 struct ldb_result *res = NULL;
6091 const char *attrs[] = { "msDS-LockoutObservationWindow",
6092 NULL };
6093 if (domain_dn == NULL) {
6094 smb_panic("domain dn is NULL");
6096 res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
6098 if (res != NULL) {
6099 lockOutObservationWindow =
6100 ldb_msg_find_attr_as_int64(res->msgs[0],
6101 "msDS-LockoutObservationWindow",
6102 DEFAULT_OBSERVATION_WINDOW);
6103 talloc_free(res);
6104 } else {
6106 /* no PSO was found, lookup the default domain setting */
6107 lockOutObservationWindow =
6108 samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
6109 "lockOutObservationWindow", NULL);
6111 return lockOutObservationWindow;
6115 * Return the effective badPwdCount
6117 * This requires that the user_msg have (if present):
6118 * - badPasswordTime
6119 * - badPwdCount
6120 * - msDS-ResultantPSO
6122 int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
6123 TALLOC_CTX *mem_ctx,
6124 struct ldb_dn *domain_dn,
6125 const struct ldb_message *user_msg)
6127 struct timeval tv_now = timeval_current();
6128 NTTIME now = timeval_to_nttime(&tv_now);
6129 int64_t lockOutObservationWindow =
6130 samdb_result_msds_LockoutObservationWindow(
6131 sam_ldb, mem_ctx, domain_dn, user_msg);
6132 return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
6136 * Returns the lockoutThreshold that applies. If a PSO is specified, then that
6137 * setting is used over the domain defaults
6139 static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
6140 struct ldb_message *pso_msg)
6142 if (pso_msg != NULL) {
6143 return ldb_msg_find_attr_as_int(pso_msg,
6144 "msDS-LockoutThreshold", 0);
6145 } else {
6146 return ldb_msg_find_attr_as_int(domain_msg,
6147 "lockoutThreshold", 0);
6152 * Returns the lockOutObservationWindow that applies. If a PSO is specified,
6153 * then that setting is used over the domain defaults
6155 static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
6156 struct ldb_message *pso_msg)
6158 if (pso_msg != NULL) {
6159 return ldb_msg_find_attr_as_int64(pso_msg,
6160 "msDS-LockoutObservationWindow",
6161 DEFAULT_OBSERVATION_WINDOW);
6162 } else {
6163 return ldb_msg_find_attr_as_int64(domain_msg,
6164 "lockOutObservationWindow",
6165 DEFAULT_OBSERVATION_WINDOW);
6170 * Prepare an update to the badPwdCount and associated attributes.
6172 * This requires that the user_msg have (if present):
6173 * - objectSid
6174 * - badPasswordTime
6175 * - badPwdCount
6177 * This also requires that the domain_msg have (if present):
6178 * - pwdProperties
6179 * - lockoutThreshold
6180 * - lockOutObservationWindow
6182 * This also requires that the pso_msg have (if present):
6183 * - msDS-LockoutThreshold
6184 * - msDS-LockoutObservationWindow
6186 NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
6187 struct ldb_context *sam_ctx,
6188 struct ldb_message *user_msg,
6189 struct ldb_message *domain_msg,
6190 struct ldb_message *pso_msg,
6191 struct ldb_message **_mod_msg)
6193 int ret, badPwdCount;
6194 unsigned int i;
6195 int64_t lockoutThreshold, lockOutObservationWindow;
6196 struct dom_sid *sid;
6197 struct timeval tv_now = timeval_current();
6198 NTTIME now = timeval_to_nttime(&tv_now);
6199 NTSTATUS status;
6200 uint32_t pwdProperties, rid = 0;
6201 struct ldb_message *mod_msg;
6203 sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
6205 pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
6206 "pwdProperties", -1);
6207 if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
6208 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
6209 if (!NT_STATUS_IS_OK(status)) {
6211 * This can't happen anyway, but always try
6212 * and update the badPwdCount on failure
6214 rid = 0;
6217 TALLOC_FREE(sid);
6220 * Work out if we are doing password lockout on the domain.
6221 * Also, the built in administrator account is exempt:
6222 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
6224 lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
6225 if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
6226 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
6227 ldb_dn_get_linearized(user_msg->dn)));
6228 return NT_STATUS_OK;
6231 mod_msg = ldb_msg_new(mem_ctx);
6232 if (mod_msg == NULL) {
6233 return NT_STATUS_NO_MEMORY;
6235 mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
6236 if (mod_msg->dn == NULL) {
6237 TALLOC_FREE(mod_msg);
6238 return NT_STATUS_NO_MEMORY;
6241 lockOutObservationWindow = get_lockout_observation_window(domain_msg,
6242 pso_msg);
6244 badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
6246 badPwdCount++;
6248 ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
6249 if (ret != LDB_SUCCESS) {
6250 TALLOC_FREE(mod_msg);
6251 return NT_STATUS_NO_MEMORY;
6253 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
6254 if (ret != LDB_SUCCESS) {
6255 TALLOC_FREE(mod_msg);
6256 return NT_STATUS_NO_MEMORY;
6259 if (badPwdCount >= lockoutThreshold) {
6260 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
6261 if (ret != LDB_SUCCESS) {
6262 TALLOC_FREE(mod_msg);
6263 return NT_STATUS_NO_MEMORY;
6265 DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
6266 ldb_dn_get_linearized(user_msg->dn), badPwdCount));
6267 } else {
6268 DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
6269 ldb_dn_get_linearized(user_msg->dn), badPwdCount));
6272 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
6273 for (i=0; i< mod_msg->num_elements; i++) {
6274 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6277 *_mod_msg = mod_msg;
6278 return NT_STATUS_OK;
6282 * Sets defaults for a User object
6283 * List of default attributes set:
6284 * accountExpires, badPasswordTime, badPwdCount,
6285 * codePage, countryCode, lastLogoff, lastLogon
6286 * logonCount, pwdLastSet
6288 int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
6289 struct ldb_message *usr_obj,
6290 struct ldb_request *req)
6292 size_t i;
6293 int ret;
6294 const struct attribute_values {
6295 const char *name;
6296 const char *value;
6297 const char *add_value;
6298 const char *mod_value;
6299 const char *control;
6300 unsigned add_flags;
6301 unsigned mod_flags;
6302 } map[] = {
6304 .name = "accountExpires",
6305 .add_value = "9223372036854775807",
6306 .mod_value = "0",
6309 .name = "badPasswordTime",
6310 .value = "0"
6313 .name = "badPwdCount",
6314 .value = "0"
6317 .name = "codePage",
6318 .value = "0"
6321 .name = "countryCode",
6322 .value = "0"
6325 .name = "lastLogoff",
6326 .value = "0"
6329 .name = "lastLogon",
6330 .value = "0"
6333 .name = "logonCount",
6334 .value = "0"
6337 .name = "logonHours",
6338 .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
6341 .name = "pwdLastSet",
6342 .value = "0",
6343 .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
6346 .name = "adminCount",
6347 .mod_value = "0",
6350 .name = "operatorCount",
6351 .mod_value = "0",
6355 for (i = 0; i < ARRAY_SIZE(map); i++) {
6356 bool added = false;
6357 const char *value = NULL;
6358 unsigned flags = 0;
6360 if (req != NULL && req->operation == LDB_ADD) {
6361 value = map[i].add_value;
6362 flags = map[i].add_flags;
6363 } else {
6364 value = map[i].mod_value;
6365 flags = map[i].mod_flags;
6368 if (value == NULL) {
6369 value = map[i].value;
6372 if (value != NULL) {
6373 flags |= LDB_FLAG_MOD_ADD;
6376 if (flags == 0) {
6377 continue;
6380 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
6381 map[i].name,
6382 value, flags,
6383 &added);
6384 if (ret != LDB_SUCCESS) {
6385 return ret;
6388 if (req != NULL && added && map[i].control != NULL) {
6389 ret = ldb_request_add_control(req,
6390 map[i].control,
6391 false, NULL);
6392 if (ret != LDB_SUCCESS) {
6393 return ret;
6398 return LDB_SUCCESS;
6402 * Sets 'sAMAccountType on user object based on userAccountControl.
6403 * This function is used in processing both 'add' and 'modify' requests.
6404 * @param ldb Current ldb_context
6405 * @param usr_obj ldb_message representing User object
6406 * @param user_account_control Value for userAccountControl flags
6407 * @param account_type_p Optional pointer to account_type to return
6408 * @return LDB_SUCCESS or LDB_ERR* code on failure
6410 int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
6411 uint32_t user_account_control, uint32_t *account_type_p)
6413 int ret;
6414 uint32_t account_type;
6416 account_type = ds_uf2atype(user_account_control);
6417 if (account_type == 0) {
6418 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
6419 return LDB_ERR_UNWILLING_TO_PERFORM;
6421 ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
6422 "sAMAccountType",
6423 account_type,
6424 LDB_FLAG_MOD_REPLACE);
6425 if (ret != LDB_SUCCESS) {
6426 return ret;
6429 if (account_type_p) {
6430 *account_type_p = account_type;
6433 return LDB_SUCCESS;
6437 * Determine and set primaryGroupID based on userAccountControl value.
6438 * This function is used in processing both 'add' and 'modify' requests.
6439 * @param ldb Current ldb_context
6440 * @param usr_obj ldb_message representing User object
6441 * @param user_account_control Value for userAccountControl flags
6442 * @param group_rid_p Optional pointer to group RID to return
6443 * @return LDB_SUCCESS or LDB_ERR* code on failure
6445 int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
6446 uint32_t user_account_control, uint32_t *group_rid_p)
6448 int ret;
6449 uint32_t rid;
6451 rid = ds_uf2prim_group_rid(user_account_control);
6453 ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
6454 "primaryGroupID", rid,
6455 LDB_FLAG_MOD_REPLACE);
6456 if (ret != LDB_SUCCESS) {
6457 return ret;
6460 if (group_rid_p) {
6461 *group_rid_p = rid;
6464 return LDB_SUCCESS;
6468 * Returns True if the source and target DNs both have the same naming context,
6469 * i.e. they're both in the same partition.
6471 bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
6472 TALLOC_CTX *mem_ctx,
6473 struct ldb_dn *source_dn,
6474 struct ldb_dn *target_dn)
6476 TALLOC_CTX *tmp_ctx;
6477 struct ldb_dn *source_nc = NULL;
6478 struct ldb_dn *target_nc = NULL;
6479 int ret;
6480 bool same_nc = true;
6482 tmp_ctx = talloc_new(mem_ctx);
6484 ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
6485 /* fix clang warning */
6486 if (source_nc == NULL) {
6487 ret = LDB_ERR_OTHER;
6489 if (ret != LDB_SUCCESS) {
6490 DBG_ERR("Failed to find base DN for source %s: %s\n",
6491 ldb_dn_get_linearized(source_dn), ldb_errstring(ldb));
6492 talloc_free(tmp_ctx);
6493 return true;
6496 ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
6497 /* fix clang warning */
6498 if (target_nc == NULL) {
6499 ret = LDB_ERR_OTHER;
6501 if (ret != LDB_SUCCESS) {
6502 DBG_ERR("Failed to find base DN for target %s: %s\n",
6503 ldb_dn_get_linearized(target_dn), ldb_errstring(ldb));
6504 talloc_free(tmp_ctx);
6505 return true;
6508 same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
6510 talloc_free(tmp_ctx);
6512 return same_nc;
6515 * Context for dsdb_count_domain_callback
6517 struct dsdb_count_domain_context {
6519 * Number of matching records
6521 size_t count;
6523 * sid of the domain that the records must belong to.
6524 * if NULL records can belong to any domain.
6526 struct dom_sid *dom_sid;
6530 * @brief ldb async callback for dsdb_domain_count.
6532 * count the number of records in the database matching an LDAP query,
6533 * optionally filtering for domain membership.
6535 * @param [in,out] req the ldb request being processed
6536 * req->context contains:
6537 * count The number of matching records
6538 * dom_sid The domain sid, if present records must belong
6539 * to the domain to be counted.
6540 *@param [in,out] ares The query result.
6542 * @return an LDB error code
6545 static int dsdb_count_domain_callback(
6546 struct ldb_request *req,
6547 struct ldb_reply *ares)
6550 if (ares == NULL) {
6551 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
6553 if (ares->error != LDB_SUCCESS) {
6554 int error = ares->error;
6555 TALLOC_FREE(ares);
6556 return ldb_request_done(req, error);
6559 switch (ares->type) {
6560 case LDB_REPLY_ENTRY:
6562 struct dsdb_count_domain_context *context = NULL;
6563 ssize_t ret;
6564 bool in_domain;
6565 struct dom_sid sid;
6566 const struct ldb_val *v;
6568 context = req->context;
6569 if (context->dom_sid == NULL) {
6570 context->count++;
6571 break;
6574 v = ldb_msg_find_ldb_val(ares->message, "objectSid");
6575 if (v == NULL) {
6576 break;
6579 ret = sid_parse(v->data, v->length, &sid);
6580 if (ret == -1) {
6581 break;
6584 in_domain = dom_sid_in_domain(context->dom_sid, &sid);
6585 if (!in_domain) {
6586 break;
6589 context->count++;
6590 break;
6592 case LDB_REPLY_REFERRAL:
6593 break;
6595 case LDB_REPLY_DONE:
6596 TALLOC_FREE(ares);
6597 return ldb_request_done(req, LDB_SUCCESS);
6600 TALLOC_FREE(ares);
6602 return LDB_SUCCESS;
6606 * @brief Count the number of records matching a query.
6608 * Count the number of entries in the database matching the supplied query,
6609 * optionally filtering only those entries belonging to the supplied domain.
6611 * @param ldb [in] Current ldb context
6612 * @param count [out] Pointer to the count
6613 * @param base [in] The base dn for the quey
6614 * @param dom_sid [in] The domain sid, if non NULL records that are not a member
6615 * of the domain are ignored.
6616 * @param scope [in] Search scope.
6617 * @param exp_fmt [in] format string for the query.
6619 * @return LDB_STATUS code.
6621 int PRINTF_ATTRIBUTE(6, 7) dsdb_domain_count(
6622 struct ldb_context *ldb,
6623 size_t *count,
6624 struct ldb_dn *base,
6625 struct dom_sid *dom_sid,
6626 enum ldb_scope scope,
6627 const char *exp_fmt, ...)
6629 TALLOC_CTX *tmp_ctx = NULL;
6630 struct ldb_request *req = NULL;
6631 struct dsdb_count_domain_context *context = NULL;
6632 char *expression = NULL;
6633 const char *object_sid[] = {"objectSid", NULL};
6634 const char *none[] = {NULL};
6635 va_list ap;
6636 int ret;
6638 *count = 0;
6639 tmp_ctx = talloc_new(ldb);
6641 context = talloc_zero(tmp_ctx, struct dsdb_count_domain_context);
6642 if (context == NULL) {
6643 return LDB_ERR_OPERATIONS_ERROR;
6645 context->dom_sid = dom_sid;
6647 if (exp_fmt) {
6648 va_start(ap, exp_fmt);
6649 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
6650 va_end(ap);
6652 if (expression == NULL) {
6653 TALLOC_FREE(context);
6654 TALLOC_FREE(tmp_ctx);
6655 return LDB_ERR_OPERATIONS_ERROR;
6659 ret = ldb_build_search_req(
6660 &req,
6661 ldb,
6662 tmp_ctx,
6663 base,
6664 scope,
6665 expression,
6666 (dom_sid == NULL) ? none : object_sid,
6667 NULL,
6668 context,
6669 dsdb_count_domain_callback,
6670 NULL);
6671 ldb_req_set_location(req, "dsdb_domain_count");
6673 if (ret != LDB_SUCCESS) goto done;
6675 ret = ldb_request(ldb, req);
6677 if (ret == LDB_SUCCESS) {
6678 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
6679 if (ret == LDB_SUCCESS) {
6680 *count = context->count;
6685 done:
6686 TALLOC_FREE(expression);
6687 TALLOC_FREE(req);
6688 TALLOC_FREE(context);
6689 TALLOC_FREE(tmp_ctx);
6691 return ret;
6695 * Returns 1 if 'sids' contains the Protected Users group SID for the domain, 0
6696 * if not. Returns a negative value on error.
6698 int dsdb_is_protected_user(struct ldb_context *ldb,
6699 const struct auth_SidAttr *sids,
6700 uint32_t num_sids)
6702 const struct dom_sid *domain_sid = NULL;
6703 struct dom_sid protected_users_sid;
6704 uint32_t i;
6706 domain_sid = samdb_domain_sid(ldb);
6707 if (domain_sid == NULL) {
6708 return -1;
6711 protected_users_sid = *domain_sid;
6712 if (!sid_append_rid(&protected_users_sid, DOMAIN_RID_PROTECTED_USERS)) {
6713 return -1;
6716 for (i = 0; i < num_sids; ++i) {
6717 if (dom_sid_equal(&protected_users_sid, &sids[i].sid)) {
6718 return 1;
6722 return 0;