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/>.
25 #include "events/events.h"
27 #include "ldb_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "../libds/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39 #include "librpc/gen_ndr/ndr_drsblobs.h"
42 search the sam for the specified attributes in a specific domain, filter on
43 objectSid being in domain_sid.
45 int samdb_search_domain(struct ldb_context
*sam_ldb
,
47 struct ldb_dn
*basedn
,
48 struct ldb_message
***res
,
49 const char * const *attrs
,
50 const struct dom_sid
*domain_sid
,
51 const char *format
, ...) _PRINTF_ATTRIBUTE(7,8)
57 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
,
58 res
, attrs
, format
, ap
);
64 struct dom_sid
*entry_sid
;
66 entry_sid
= samdb_result_dom_sid(mem_ctx
, (*res
)[i
], "objectSid");
68 if ((entry_sid
== NULL
) ||
69 (!dom_sid_in_domain(domain_sid
, entry_sid
))) {
70 /* Delete that entry from the result set */
71 (*res
)[i
] = (*res
)[count
-1];
73 talloc_free(entry_sid
);
76 talloc_free(entry_sid
);
84 search the sam for a single string attribute in exactly 1 record
86 const char *samdb_search_string_v(struct ldb_context
*sam_ldb
,
88 struct ldb_dn
*basedn
,
89 const char *attr_name
,
90 const char *format
, va_list ap
) _PRINTF_ATTRIBUTE(5,0)
93 const char *attrs
[2] = { NULL
, NULL
};
94 struct ldb_message
**res
= NULL
;
98 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
100 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
101 attr_name
, format
, count
));
108 return samdb_result_string(res
[0], attr_name
, NULL
);
112 search the sam for a single string attribute in exactly 1 record
114 const char *samdb_search_string(struct ldb_context
*sam_ldb
,
116 struct ldb_dn
*basedn
,
117 const char *attr_name
,
118 const char *format
, ...) _PRINTF_ATTRIBUTE(5,6)
123 va_start(ap
, format
);
124 str
= samdb_search_string_v(sam_ldb
, mem_ctx
, basedn
, attr_name
, format
, ap
);
130 struct ldb_dn
*samdb_search_dn(struct ldb_context
*sam_ldb
,
132 struct ldb_dn
*basedn
,
133 const char *format
, ...) _PRINTF_ATTRIBUTE(4,5)
137 struct ldb_message
**res
= NULL
;
140 va_start(ap
, format
);
141 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, NULL
, format
, ap
);
144 if (count
!= 1) return NULL
;
146 ret
= talloc_steal(mem_ctx
, res
[0]->dn
);
153 search the sam for a dom_sid attribute in exactly 1 record
155 struct dom_sid
*samdb_search_dom_sid(struct ldb_context
*sam_ldb
,
157 struct ldb_dn
*basedn
,
158 const char *attr_name
,
159 const char *format
, ...) _PRINTF_ATTRIBUTE(5,6)
163 struct ldb_message
**res
;
164 const char *attrs
[2] = { NULL
, NULL
};
167 attrs
[0] = attr_name
;
169 va_start(ap
, format
);
170 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174 attr_name
, format
, count
));
180 sid
= samdb_result_dom_sid(mem_ctx
, res
[0], attr_name
);
186 return the count of the number of records in the sam matching the query
188 int samdb_search_count(struct ldb_context
*sam_ldb
,
190 struct ldb_dn
*basedn
,
191 const char *format
, ...) _PRINTF_ATTRIBUTE(4,5)
194 struct ldb_message
**res
;
195 const char * const attrs
[] = { NULL
};
198 va_start(ap
, format
);
199 ret
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
207 search the sam for a single integer attribute in exactly 1 record
209 uint_t
samdb_search_uint(struct ldb_context
*sam_ldb
,
211 uint_t default_value
,
212 struct ldb_dn
*basedn
,
213 const char *attr_name
,
214 const char *format
, ...) _PRINTF_ATTRIBUTE(6,7)
218 struct ldb_message
**res
;
219 const char *attrs
[2] = { NULL
, NULL
};
221 attrs
[0] = attr_name
;
223 va_start(ap
, format
);
224 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
228 return default_value
;
231 return samdb_result_uint(res
[0], attr_name
, default_value
);
235 search the sam for a single signed 64 bit integer attribute in exactly 1 record
237 int64_t samdb_search_int64(struct ldb_context
*sam_ldb
,
239 int64_t default_value
,
240 struct ldb_dn
*basedn
,
241 const char *attr_name
,
242 const char *format
, ...) _PRINTF_ATTRIBUTE(6,7)
246 struct ldb_message
**res
;
247 const char *attrs
[2] = { NULL
, NULL
};
249 attrs
[0] = attr_name
;
251 va_start(ap
, format
);
252 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
256 return default_value
;
259 return samdb_result_int64(res
[0], attr_name
, default_value
);
263 search the sam for multipe records each giving a single string attribute
264 return the number of matches, or -1 on error
266 int samdb_search_string_multiple(struct ldb_context
*sam_ldb
,
268 struct ldb_dn
*basedn
,
270 const char *attr_name
,
271 const char *format
, ...) _PRINTF_ATTRIBUTE(6,7)
275 const char *attrs
[2] = { NULL
, NULL
};
276 struct ldb_message
**res
= NULL
;
278 attrs
[0] = attr_name
;
280 va_start(ap
, format
);
281 count
= gendb_search_v(sam_ldb
, mem_ctx
, basedn
, &res
, attrs
, format
, ap
);
288 /* make sure its single valued */
289 for (i
=0;i
<count
;i
++) {
290 if (res
[i
]->num_elements
!= 1) {
291 DEBUG(1,("samdb: search for %s %s not single valued\n",
298 *strs
= talloc_array(mem_ctx
, const char *, count
+1);
304 for (i
=0;i
<count
;i
++) {
305 (*strs
)[i
] = samdb_result_string(res
[i
], attr_name
, NULL
);
307 (*strs
)[count
] = NULL
;
313 pull a uint from a result set.
315 uint_t
samdb_result_uint(const struct ldb_message
*msg
, const char *attr
, uint_t default_value
)
317 return ldb_msg_find_attr_as_uint(msg
, attr
, default_value
);
321 pull a (signed) int64 from a result set.
323 int64_t samdb_result_int64(const struct ldb_message
*msg
, const char *attr
, int64_t default_value
)
325 return ldb_msg_find_attr_as_int64(msg
, attr
, default_value
);
329 pull a string from a result set.
331 const char *samdb_result_string(const struct ldb_message
*msg
, const char *attr
,
332 const char *default_value
)
334 return ldb_msg_find_attr_as_string(msg
, attr
, default_value
);
337 struct ldb_dn
*samdb_result_dn(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
338 const char *attr
, struct ldb_dn
*default_value
)
340 struct ldb_dn
*ret_dn
= ldb_msg_find_attr_as_dn(ldb
, mem_ctx
, msg
, attr
);
342 return default_value
;
348 pull a rid from a objectSid in a result set.
350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
351 const char *attr
, uint32_t default_value
)
356 sid
= samdb_result_dom_sid(mem_ctx
, msg
, attr
);
358 return default_value
;
360 rid
= sid
->sub_auths
[sid
->num_auths
-1];
366 pull a dom_sid structure from a objectSid in a result set.
368 struct dom_sid
*samdb_result_dom_sid(TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
371 const struct ldb_val
*v
;
373 enum ndr_err_code ndr_err
;
374 v
= ldb_msg_find_ldb_val(msg
, attr
);
378 sid
= talloc(mem_ctx
, struct dom_sid
);
382 ndr_err
= ndr_pull_struct_blob(v
, sid
, NULL
, sid
,
383 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
392 pull a guid structure from a objectGUID in a result set.
394 struct GUID
samdb_result_guid(const struct ldb_message
*msg
, const char *attr
)
396 const struct ldb_val
*v
;
397 enum ndr_err_code ndr_err
;
403 v
= ldb_msg_find_ldb_val(msg
, attr
);
406 mem_ctx
= talloc_named_const(NULL
, 0, "samdb_result_guid");
407 if (!mem_ctx
) return guid
;
408 ndr_err
= ndr_pull_struct_blob(v
, mem_ctx
, NULL
, &guid
,
409 (ndr_pull_flags_fn_t
)ndr_pull_GUID
);
410 talloc_free(mem_ctx
);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
419 pull a sid prefix from a objectSid in a result set.
420 this is used to find the domain sid for a user
422 struct dom_sid
*samdb_result_sid_prefix(TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
425 struct dom_sid
*sid
= samdb_result_dom_sid(mem_ctx
, msg
, attr
);
426 if (!sid
|| sid
->num_auths
< 1) return NULL
;
432 pull a NTTIME in a result set.
434 NTTIME
samdb_result_nttime(struct ldb_message
*msg
, const char *attr
, NTTIME default_value
)
436 return ldb_msg_find_attr_as_uint64(msg
, attr
, default_value
);
440 * Windows stores 0 for lastLogoff.
441 * But when a MS DC return the lastLogoff (as Logoff Time)
442 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
443 * cause windows 2008 and newer version to fail for SMB requests
445 NTTIME
samdb_result_last_logoff(struct ldb_message
*msg
)
447 NTTIME ret
= ldb_msg_find_attr_as_uint64(msg
, "lastLogoff",0);
450 ret
= 0x7FFFFFFFFFFFFFFFULL
;
456 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
457 * indicate an account doesn't expire.
459 * When Windows initially creates an account, it sets
460 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
461 * when changing from an account having a specific expiration date to
462 * that account never expiring, it sets accountExpires = 0.
464 * Consolidate that logic here to allow clearer logic for account expiry in
465 * the rest of the code.
467 NTTIME
samdb_result_account_expires(struct ldb_message
*msg
)
469 NTTIME ret
= ldb_msg_find_attr_as_uint64(msg
, "accountExpires",
473 ret
= 0x7FFFFFFFFFFFFFFFULL
;
479 pull a uint64_t from a result set.
481 uint64_t samdb_result_uint64(struct ldb_message
*msg
, const char *attr
, uint64_t default_value
)
483 return ldb_msg_find_attr_as_uint64(msg
, attr
, default_value
);
488 construct the allow_password_change field from the PwdLastSet attribute and the
489 domain password settings
491 NTTIME
samdb_result_allow_password_change(struct ldb_context
*sam_ldb
,
493 struct ldb_dn
*domain_dn
,
494 struct ldb_message
*msg
,
497 uint64_t attr_time
= samdb_result_uint64(msg
, attr
, 0);
500 if (attr_time
== 0) {
504 minPwdAge
= samdb_search_int64(sam_ldb
, mem_ctx
, 0, domain_dn
, "minPwdAge", NULL
);
506 /* yes, this is a -= not a += as minPwdAge is stored as the negative
507 of the number of 100-nano-seconds */
508 attr_time
-= minPwdAge
;
514 construct the force_password_change field from the PwdLastSet
515 attribute, the userAccountControl and the domain password settings
517 NTTIME
samdb_result_force_password_change(struct ldb_context
*sam_ldb
,
519 struct ldb_dn
*domain_dn
,
520 struct ldb_message
*msg
)
522 uint64_t attr_time
= samdb_result_uint64(msg
, "pwdLastSet", 0);
523 uint32_t userAccountControl
= samdb_result_uint64(msg
, "userAccountControl", 0);
526 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
527 if (!(userAccountControl
& UF_NORMAL_ACCOUNT
)
528 || (userAccountControl
& UF_DONT_EXPIRE_PASSWD
)) {
529 return 0x7FFFFFFFFFFFFFFFULL
;
532 if (attr_time
== 0) {
536 maxPwdAge
= samdb_search_int64(sam_ldb
, mem_ctx
, 0, domain_dn
, "maxPwdAge", NULL
);
537 if (maxPwdAge
== 0) {
538 return 0x7FFFFFFFFFFFFFFFULL
;
540 attr_time
-= maxPwdAge
;
547 pull a samr_Password structutre from a result set.
549 struct samr_Password
*samdb_result_hash(TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
, const char *attr
)
551 struct samr_Password
*hash
= NULL
;
552 const struct ldb_val
*val
= ldb_msg_find_ldb_val(msg
, attr
);
553 if (val
&& (val
->length
>= sizeof(hash
->hash
))) {
554 hash
= talloc(mem_ctx
, struct samr_Password
);
555 memcpy(hash
->hash
, val
->data
, MIN(val
->length
, sizeof(hash
->hash
)));
561 pull an array of samr_Password structutres from a result set.
563 uint_t
samdb_result_hashes(TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
564 const char *attr
, struct samr_Password
**hashes
)
567 const struct ldb_val
*val
= ldb_msg_find_ldb_val(msg
, attr
);
574 count
= val
->length
/ 16;
579 *hashes
= talloc_array(mem_ctx
, struct samr_Password
, count
);
584 for (i
=0;i
<count
;i
++) {
585 memcpy((*hashes
)[i
].hash
, (i
*16)+(char *)val
->data
, 16);
591 NTSTATUS
samdb_result_passwords(TALLOC_CTX
*mem_ctx
, struct loadparm_context
*lp_ctx
, struct ldb_message
*msg
,
592 struct samr_Password
**lm_pwd
, struct samr_Password
**nt_pwd
)
594 struct samr_Password
*lmPwdHash
, *ntPwdHash
;
597 num_nt
= samdb_result_hashes(mem_ctx
, msg
, "unicodePwd", &ntPwdHash
);
600 } else if (num_nt
> 1) {
601 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
603 *nt_pwd
= &ntPwdHash
[0];
607 /* Ensure that if we have turned off LM
608 * authentication, that we never use the LM hash, even
610 if (lp_lanman_auth(lp_ctx
)) {
612 num_lm
= samdb_result_hashes(mem_ctx
, msg
, "dBCSPwd", &lmPwdHash
);
615 } else if (num_lm
> 1) {
616 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
618 *lm_pwd
= &lmPwdHash
[0];
628 pull a samr_LogonHours structutre from a result set.
630 struct samr_LogonHours
samdb_result_logon_hours(TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
, const char *attr
)
632 struct samr_LogonHours hours
;
633 const int units_per_week
= 168;
634 const struct ldb_val
*val
= ldb_msg_find_ldb_val(msg
, attr
);
636 hours
.bits
= talloc_array(mem_ctx
, uint8_t, units_per_week
);
640 hours
.units_per_week
= units_per_week
;
641 memset(hours
.bits
, 0xFF, units_per_week
);
643 memcpy(hours
.bits
, val
->data
, MIN(val
->length
, units_per_week
));
649 pull a set of account_flags from a result set.
651 This requires that the attributes:
656 uint32_t samdb_result_acct_flags(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
657 struct ldb_message
*msg
, struct ldb_dn
*domain_dn
)
659 uint32_t userAccountControl
= ldb_msg_find_attr_as_uint(msg
, "userAccountControl", 0);
660 uint32_t acct_flags
= ds_uf2acb(userAccountControl
);
661 NTTIME must_change_time
;
664 must_change_time
= samdb_result_force_password_change(sam_ctx
, mem_ctx
,
667 /* Test account expire time */
668 unix_to_nt_time(&now
, time(NULL
));
669 /* check for expired password */
670 if (must_change_time
< now
) {
671 acct_flags
|= ACB_PW_EXPIRED
;
676 struct lsa_BinaryString
samdb_result_parameters(TALLOC_CTX
*mem_ctx
,
677 struct ldb_message
*msg
,
680 struct lsa_BinaryString s
;
681 const struct ldb_val
*val
= ldb_msg_find_ldb_val(msg
, attr
);
689 s
.array
= talloc_array(mem_ctx
, uint16_t, val
->length
/2);
693 s
.length
= s
.size
= val
->length
/2;
694 memcpy(s
.array
, val
->data
, val
->length
);
699 /* Find an attribute, with a particular value */
701 /* The current callers of this function expect a very specific
702 * behaviour: In particular, objectClass subclass equivilance is not
703 * wanted. This means that we should not lookup the schema for the
704 * comparison function */
705 struct ldb_message_element
*samdb_find_attribute(struct ldb_context
*ldb
,
706 const struct ldb_message
*msg
,
707 const char *name
, const char *value
)
710 struct ldb_message_element
*el
= ldb_msg_find_element(msg
, name
);
716 for (i
=0;i
<el
->num_values
;i
++) {
717 if (ldb_attr_cmp(value
, (char *)el
->values
[i
].data
) == 0) {
725 int samdb_find_or_add_value(struct ldb_context
*ldb
, struct ldb_message
*msg
, const char *name
, const char *set_value
)
727 if (samdb_find_attribute(ldb
, msg
, name
, set_value
) == NULL
) {
728 return samdb_msg_add_string(ldb
, msg
, msg
, name
, set_value
);
733 int samdb_find_or_add_attribute(struct ldb_context
*ldb
, struct ldb_message
*msg
, const char *name
, const char *set_value
)
735 struct ldb_message_element
*el
;
737 el
= ldb_msg_find_element(msg
, name
);
742 return samdb_msg_add_string(ldb
, msg
, msg
, name
, set_value
);
748 add a string element to a message
750 int samdb_msg_add_string(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
751 const char *attr_name
, const char *str
)
753 char *s
= talloc_strdup(mem_ctx
, str
);
754 char *a
= talloc_strdup(mem_ctx
, attr_name
);
755 if (s
== NULL
|| a
== NULL
) {
756 return LDB_ERR_OPERATIONS_ERROR
;
758 return ldb_msg_add_string(msg
, a
, s
);
762 add a dom_sid element to a message
764 int samdb_msg_add_dom_sid(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
765 const char *attr_name
, struct dom_sid
*sid
)
768 enum ndr_err_code ndr_err
;
770 ndr_err
= ndr_push_struct_blob(&v
, mem_ctx
,
771 lp_iconv_convenience(ldb_get_opaque(sam_ldb
, "loadparm")),
773 (ndr_push_flags_fn_t
)ndr_push_dom_sid
);
774 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
777 return ldb_msg_add_value(msg
, attr_name
, &v
, NULL
);
782 add a delete element operation to a message
784 int samdb_msg_add_delete(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
785 const char *attr_name
)
787 /* we use an empty replace rather than a delete, as it allows for
788 samdb_replace() to be used everywhere */
789 return ldb_msg_add_empty(msg
, attr_name
, LDB_FLAG_MOD_REPLACE
, NULL
);
793 add a add attribute value to a message
795 int samdb_msg_add_addval(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
796 const char *attr_name
, const char *value
)
798 struct ldb_message_element
*el
;
801 a
= talloc_strdup(mem_ctx
, attr_name
);
804 v
= talloc_strdup(mem_ctx
, value
);
807 ret
= ldb_msg_add_string(msg
, a
, v
);
810 el
= ldb_msg_find_element(msg
, a
);
813 el
->flags
= LDB_FLAG_MOD_ADD
;
818 add a delete attribute value to a message
820 int samdb_msg_add_delval(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
821 const char *attr_name
, const char *value
)
823 struct ldb_message_element
*el
;
826 a
= talloc_strdup(mem_ctx
, attr_name
);
829 v
= talloc_strdup(mem_ctx
, value
);
832 ret
= ldb_msg_add_string(msg
, a
, v
);
835 el
= ldb_msg_find_element(msg
, a
);
838 el
->flags
= LDB_FLAG_MOD_DELETE
;
843 add a int element to a message
845 int samdb_msg_add_int(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
846 const char *attr_name
, int v
)
848 const char *s
= talloc_asprintf(mem_ctx
, "%d", v
);
849 return samdb_msg_add_string(sam_ldb
, mem_ctx
, msg
, attr_name
, s
);
853 add a uint_t element to a message
855 int samdb_msg_add_uint(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
856 const char *attr_name
, uint_t v
)
858 const char *s
= talloc_asprintf(mem_ctx
, "%u", v
);
859 return samdb_msg_add_string(sam_ldb
, mem_ctx
, msg
, attr_name
, s
);
863 add a (signed) int64_t element to a message
865 int samdb_msg_add_int64(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
866 const char *attr_name
, int64_t v
)
868 const char *s
= talloc_asprintf(mem_ctx
, "%lld", (long long)v
);
869 return samdb_msg_add_string(sam_ldb
, mem_ctx
, msg
, attr_name
, s
);
873 add a uint64_t element to a message
875 int samdb_msg_add_uint64(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
876 const char *attr_name
, uint64_t v
)
878 const char *s
= talloc_asprintf(mem_ctx
, "%llu", (unsigned long long)v
);
879 return samdb_msg_add_string(sam_ldb
, mem_ctx
, msg
, attr_name
, s
);
883 add a samr_Password element to a message
885 int samdb_msg_add_hash(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
886 const char *attr_name
, struct samr_Password
*hash
)
889 val
.data
= talloc_memdup(mem_ctx
, hash
->hash
, 16);
894 return ldb_msg_add_value(msg
, attr_name
, &val
, NULL
);
898 add a samr_Password array to a message
900 int samdb_msg_add_hashes(TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
901 const char *attr_name
, struct samr_Password
*hashes
, uint_t count
)
905 val
.data
= talloc_array_size(mem_ctx
, 16, count
);
906 val
.length
= count
*16;
910 for (i
=0;i
<count
;i
++) {
911 memcpy(i
*16 + (char *)val
.data
, hashes
[i
].hash
, 16);
913 return ldb_msg_add_value(msg
, attr_name
, &val
, NULL
);
917 add a acct_flags element to a message
919 int samdb_msg_add_acct_flags(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
920 const char *attr_name
, uint32_t v
)
922 return samdb_msg_add_uint(sam_ldb
, mem_ctx
, msg
, attr_name
, ds_acb2uf(v
));
926 add a logon_hours element to a message
928 int samdb_msg_add_logon_hours(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
929 const char *attr_name
, struct samr_LogonHours
*hours
)
932 val
.length
= hours
->units_per_week
/ 8;
933 val
.data
= hours
->bits
;
934 return ldb_msg_add_value(msg
, attr_name
, &val
, NULL
);
938 add a parameters element to a message
940 int samdb_msg_add_parameters(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
941 const char *attr_name
, struct lsa_BinaryString
*parameters
)
944 val
.length
= parameters
->length
* 2;
945 val
.data
= (uint8_t *)parameters
->array
;
946 return ldb_msg_add_value(msg
, attr_name
, &val
, NULL
);
949 add a general value element to a message
951 int samdb_msg_add_value(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
952 const char *attr_name
, const struct ldb_val
*val
)
954 return ldb_msg_add_value(msg
, attr_name
, val
, NULL
);
958 sets a general value element to a message
960 int samdb_msg_set_value(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
961 const char *attr_name
, const struct ldb_val
*val
)
963 struct ldb_message_element
*el
;
965 el
= ldb_msg_find_element(msg
, attr_name
);
969 return ldb_msg_add_value(msg
, attr_name
, val
, NULL
);
973 set a string element in a message
975 int samdb_msg_set_string(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
,
976 const char *attr_name
, const char *str
)
978 struct ldb_message_element
*el
;
980 el
= ldb_msg_find_element(msg
, attr_name
);
984 return samdb_msg_add_string(sam_ldb
, mem_ctx
, msg
, attr_name
, str
);
988 replace elements in a record
990 int samdb_replace(struct ldb_context
*sam_ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_message
*msg
)
994 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
995 for (i
=0;i
<msg
->num_elements
;i
++) {
996 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
999 /* modify the samdb record */
1000 return ldb_modify(sam_ldb
, msg
);
1004 return a default security descriptor
1006 struct security_descriptor
*samdb_default_security_descriptor(TALLOC_CTX
*mem_ctx
)
1008 struct security_descriptor
*sd
;
1010 sd
= security_descriptor_initialise(mem_ctx
);
1015 struct ldb_dn
*samdb_base_dn(struct ldb_context
*sam_ctx
)
1017 return ldb_get_default_basedn(sam_ctx
);
1020 struct ldb_dn
*samdb_config_dn(struct ldb_context
*sam_ctx
)
1022 return ldb_get_config_basedn(sam_ctx
);
1025 struct ldb_dn
*samdb_schema_dn(struct ldb_context
*sam_ctx
)
1027 return ldb_get_schema_basedn(sam_ctx
);
1030 struct ldb_dn
*samdb_root_dn(struct ldb_context
*sam_ctx
)
1032 return ldb_get_root_basedn(sam_ctx
);
1035 struct ldb_dn
*samdb_partitions_dn(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
)
1037 struct ldb_dn
*new_dn
;
1039 new_dn
= ldb_dn_copy(mem_ctx
, samdb_config_dn(sam_ctx
));
1040 if ( ! ldb_dn_add_child_fmt(new_dn
, "CN=Partitions")) {
1041 talloc_free(new_dn
);
1047 struct ldb_dn
*samdb_sites_dn(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
)
1049 struct ldb_dn
*new_dn
;
1051 new_dn
= ldb_dn_copy(mem_ctx
, samdb_config_dn(sam_ctx
));
1052 if ( ! ldb_dn_add_child_fmt(new_dn
, "CN=Sites")) {
1053 talloc_free(new_dn
);
1060 work out the domain sid for the current open ldb
1062 const struct dom_sid
*samdb_domain_sid(struct ldb_context
*ldb
)
1064 TALLOC_CTX
*tmp_ctx
;
1065 const struct dom_sid
*domain_sid
;
1066 const char *attrs
[] = {
1070 struct ldb_result
*res
;
1073 /* see if we have a cached copy */
1074 domain_sid
= (struct dom_sid
*)ldb_get_opaque(ldb
, "cache.domain_sid");
1079 tmp_ctx
= talloc_new(ldb
);
1080 if (tmp_ctx
== NULL
) {
1084 ret
= ldb_search(ldb
, tmp_ctx
, &res
, ldb_get_default_basedn(ldb
), LDB_SCOPE_BASE
, attrs
, "objectSid=*");
1086 if (ret
!= LDB_SUCCESS
) {
1090 if (res
->count
!= 1) {
1094 domain_sid
= samdb_result_dom_sid(tmp_ctx
, res
->msgs
[0], "objectSid");
1095 if (domain_sid
== NULL
) {
1099 /* cache the domain_sid in the ldb */
1100 if (ldb_set_opaque(ldb
, "cache.domain_sid", discard_const_p(struct dom_sid
, domain_sid
)) != LDB_SUCCESS
) {
1104 talloc_steal(ldb
, domain_sid
);
1105 talloc_free(tmp_ctx
);
1110 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1111 talloc_free(tmp_ctx
);
1115 bool samdb_set_domain_sid(struct ldb_context
*ldb
, const struct dom_sid
*dom_sid_in
)
1117 TALLOC_CTX
*tmp_ctx
;
1118 struct dom_sid
*dom_sid_new
;
1119 struct dom_sid
*dom_sid_old
;
1121 /* see if we have a cached copy */
1122 dom_sid_old
= talloc_get_type(ldb_get_opaque(ldb
,
1123 "cache.domain_sid"), struct dom_sid
);
1125 tmp_ctx
= talloc_new(ldb
);
1126 if (tmp_ctx
== NULL
) {
1130 dom_sid_new
= dom_sid_dup(tmp_ctx
, dom_sid_in
);
1135 /* cache the domain_sid in the ldb */
1136 if (ldb_set_opaque(ldb
, "cache.domain_sid", dom_sid_new
) != LDB_SUCCESS
) {
1140 talloc_steal(ldb
, dom_sid_new
);
1141 talloc_free(tmp_ctx
);
1142 talloc_free(dom_sid_old
);
1147 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1148 talloc_free(tmp_ctx
);
1152 /* Obtain the short name of the flexible single master operator
1153 * (FSMO), such as the PDC Emulator */
1154 const char *samdb_result_fsmo_name(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
, const struct ldb_message
*msg
,
1157 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1158 struct ldb_dn
*fsmo_dn
= ldb_msg_find_attr_as_dn(ldb
, mem_ctx
, msg
, attr
);
1159 const struct ldb_val
*val
= ldb_dn_get_component_val(fsmo_dn
, 1);
1160 const char *name
= ldb_dn_get_component_name(fsmo_dn
, 1);
1162 if (!name
|| (ldb_attr_cmp(name
, "cn") != 0)) {
1163 /* Ensure this matches the format. This gives us a
1164 * bit more confidence that a 'cn' value will be a
1169 return (char *)val
->data
;
1175 work out the ntds settings dn for the current open ldb
1177 struct ldb_dn
*samdb_ntds_settings_dn(struct ldb_context
*ldb
)
1179 TALLOC_CTX
*tmp_ctx
;
1180 const char *root_attrs
[] = { "dsServiceName", NULL
};
1182 struct ldb_result
*root_res
;
1183 struct ldb_dn
*settings_dn
;
1185 /* see if we have a cached copy */
1186 settings_dn
= (struct ldb_dn
*)ldb_get_opaque(ldb
, "cache.settings_dn");
1191 tmp_ctx
= talloc_new(ldb
);
1192 if (tmp_ctx
== NULL
) {
1196 ret
= ldb_search(ldb
, tmp_ctx
, &root_res
, ldb_dn_new(tmp_ctx
, ldb
, ""), LDB_SCOPE_BASE
, root_attrs
, NULL
);
1198 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1199 ldb_errstring(ldb
)));
1203 if (root_res
->count
!= 1) {
1207 settings_dn
= ldb_msg_find_attr_as_dn(ldb
, tmp_ctx
, root_res
->msgs
[0], "dsServiceName");
1209 /* cache the domain_sid in the ldb */
1210 if (ldb_set_opaque(ldb
, "cache.settings_dn", settings_dn
) != LDB_SUCCESS
) {
1214 talloc_steal(ldb
, settings_dn
);
1215 talloc_free(tmp_ctx
);
1220 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1221 talloc_free(tmp_ctx
);
1226 work out the ntds settings invocationId for the current open ldb
1228 const struct GUID
*samdb_ntds_invocation_id(struct ldb_context
*ldb
)
1230 TALLOC_CTX
*tmp_ctx
;
1231 const char *attrs
[] = { "invocationId", NULL
};
1233 struct ldb_result
*res
;
1234 struct GUID
*invocation_id
;
1236 /* see if we have a cached copy */
1237 invocation_id
= (struct GUID
*)ldb_get_opaque(ldb
, "cache.invocation_id");
1238 if (invocation_id
) {
1239 return invocation_id
;
1242 tmp_ctx
= talloc_new(ldb
);
1243 if (tmp_ctx
== NULL
) {
1247 ret
= ldb_search(ldb
, tmp_ctx
, &res
, samdb_ntds_settings_dn(ldb
), LDB_SCOPE_BASE
, attrs
, NULL
);
1252 if (res
->count
!= 1) {
1256 invocation_id
= talloc(tmp_ctx
, struct GUID
);
1257 if (!invocation_id
) {
1261 *invocation_id
= samdb_result_guid(res
->msgs
[0], "invocationId");
1263 /* cache the domain_sid in the ldb */
1264 if (ldb_set_opaque(ldb
, "cache.invocation_id", invocation_id
) != LDB_SUCCESS
) {
1268 talloc_steal(ldb
, invocation_id
);
1269 talloc_free(tmp_ctx
);
1271 return invocation_id
;
1274 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1275 talloc_free(tmp_ctx
);
1279 bool samdb_set_ntds_invocation_id(struct ldb_context
*ldb
, const struct GUID
*invocation_id_in
)
1281 TALLOC_CTX
*tmp_ctx
;
1282 struct GUID
*invocation_id_new
;
1283 struct GUID
*invocation_id_old
;
1285 /* see if we have a cached copy */
1286 invocation_id_old
= (struct GUID
*)ldb_get_opaque(ldb
,
1287 "cache.invocation_id");
1289 tmp_ctx
= talloc_new(ldb
);
1290 if (tmp_ctx
== NULL
) {
1294 invocation_id_new
= talloc(tmp_ctx
, struct GUID
);
1295 if (!invocation_id_new
) {
1299 *invocation_id_new
= *invocation_id_in
;
1301 /* cache the domain_sid in the ldb */
1302 if (ldb_set_opaque(ldb
, "cache.invocation_id", invocation_id_new
) != LDB_SUCCESS
) {
1306 talloc_steal(ldb
, invocation_id_new
);
1307 talloc_free(tmp_ctx
);
1308 talloc_free(invocation_id_old
);
1313 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314 talloc_free(tmp_ctx
);
1319 work out the ntds settings objectGUID for the current open ldb
1321 const struct GUID
*samdb_ntds_objectGUID(struct ldb_context
*ldb
)
1323 TALLOC_CTX
*tmp_ctx
;
1324 const char *attrs
[] = { "objectGUID", NULL
};
1326 struct ldb_result
*res
;
1327 struct GUID
*ntds_guid
;
1329 /* see if we have a cached copy */
1330 ntds_guid
= (struct GUID
*)ldb_get_opaque(ldb
, "cache.ntds_guid");
1335 tmp_ctx
= talloc_new(ldb
);
1336 if (tmp_ctx
== NULL
) {
1340 ret
= ldb_search(ldb
, tmp_ctx
, &res
, samdb_ntds_settings_dn(ldb
), LDB_SCOPE_BASE
, attrs
, NULL
);
1345 if (res
->count
!= 1) {
1349 ntds_guid
= talloc(tmp_ctx
, struct GUID
);
1354 *ntds_guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
1356 /* cache the domain_sid in the ldb */
1357 if (ldb_set_opaque(ldb
, "cache.ntds_guid", ntds_guid
) != LDB_SUCCESS
) {
1361 talloc_steal(ldb
, ntds_guid
);
1362 talloc_free(tmp_ctx
);
1367 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1368 talloc_free(tmp_ctx
);
1372 bool samdb_set_ntds_objectGUID(struct ldb_context
*ldb
, const struct GUID
*ntds_guid_in
)
1374 TALLOC_CTX
*tmp_ctx
;
1375 struct GUID
*ntds_guid_new
;
1376 struct GUID
*ntds_guid_old
;
1378 /* see if we have a cached copy */
1379 ntds_guid_old
= (struct GUID
*)ldb_get_opaque(ldb
, "cache.ntds_guid");
1381 tmp_ctx
= talloc_new(ldb
);
1382 if (tmp_ctx
== NULL
) {
1386 ntds_guid_new
= talloc(tmp_ctx
, struct GUID
);
1387 if (!ntds_guid_new
) {
1391 *ntds_guid_new
= *ntds_guid_in
;
1393 /* cache the domain_sid in the ldb */
1394 if (ldb_set_opaque(ldb
, "cache.ntds_guid", ntds_guid_new
) != LDB_SUCCESS
) {
1398 talloc_steal(ldb
, ntds_guid_new
);
1399 talloc_free(tmp_ctx
);
1400 talloc_free(ntds_guid_old
);
1405 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1406 talloc_free(tmp_ctx
);
1411 work out the server dn for the current open ldb
1413 struct ldb_dn
*samdb_server_dn(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
)
1415 return ldb_dn_get_parent(mem_ctx
, samdb_ntds_settings_dn(ldb
));
1419 work out the server dn for the current open ldb
1421 struct ldb_dn
*samdb_server_site_dn(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
)
1423 struct ldb_dn
*server_dn
;
1424 struct ldb_dn
*server_site_dn
;
1426 server_dn
= samdb_server_dn(ldb
, mem_ctx
);
1427 if (!server_dn
) return NULL
;
1429 server_site_dn
= ldb_dn_get_parent(mem_ctx
, server_dn
);
1431 talloc_free(server_dn
);
1432 return server_site_dn
;
1435 const char *samdb_server_site_name(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
)
1437 const struct ldb_val
*val
= ldb_dn_get_rdn_val(samdb_server_site_dn(ldb
, mem_ctx
));
1440 return (const char *) val
->data
;
1446 work out if we are the PDC for the domain of the current open ldb
1448 bool samdb_is_pdc(struct ldb_context
*ldb
)
1450 const char *dom_attrs
[] = { "fSMORoleOwner", NULL
};
1452 struct ldb_result
*dom_res
;
1453 TALLOC_CTX
*tmp_ctx
;
1457 tmp_ctx
= talloc_new(ldb
);
1458 if (tmp_ctx
== NULL
) {
1459 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1463 ret
= ldb_search(ldb
, tmp_ctx
, &dom_res
, ldb_get_default_basedn(ldb
), LDB_SCOPE_BASE
, dom_attrs
, NULL
);
1465 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1466 ldb_dn_get_linearized(ldb_get_default_basedn(ldb
)),
1467 ldb_errstring(ldb
)));
1470 if (dom_res
->count
!= 1) {
1474 pdc
= ldb_msg_find_attr_as_dn(ldb
, tmp_ctx
, dom_res
->msgs
[0], "fSMORoleOwner");
1476 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb
), pdc
) == 0) {
1482 talloc_free(tmp_ctx
);
1487 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1488 talloc_free(tmp_ctx
);
1493 work out if we are a Global Catalog server for the domain of the current open ldb
1495 bool samdb_is_gc(struct ldb_context
*ldb
)
1497 const char *attrs
[] = { "options", NULL
};
1499 struct ldb_result
*res
;
1500 TALLOC_CTX
*tmp_ctx
;
1502 tmp_ctx
= talloc_new(ldb
);
1503 if (tmp_ctx
== NULL
) {
1504 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1508 /* Query cn=ntds settings,.... */
1509 ret
= ldb_search(ldb
, tmp_ctx
, &res
, samdb_ntds_settings_dn(ldb
), LDB_SCOPE_BASE
, attrs
, NULL
);
1511 talloc_free(tmp_ctx
);
1514 if (res
->count
!= 1) {
1515 talloc_free(tmp_ctx
);
1519 options
= ldb_msg_find_attr_as_int(res
->msgs
[0], "options", 0);
1520 talloc_free(tmp_ctx
);
1522 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1523 if (options
& 0x000000001) {
1529 /* Find a domain object in the parents of a particular DN. */
1530 int samdb_search_for_parent_domain(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
, struct ldb_dn
*dn
,
1531 struct ldb_dn
**parent_dn
, const char **errstring
)
1533 TALLOC_CTX
*local_ctx
;
1534 struct ldb_dn
*sdn
= dn
;
1535 struct ldb_result
*res
= NULL
;
1537 const char *attrs
[] = { NULL
};
1539 local_ctx
= talloc_new(mem_ctx
);
1540 if (local_ctx
== NULL
) return LDB_ERR_OPERATIONS_ERROR
;
1542 while ((sdn
= ldb_dn_get_parent(local_ctx
, sdn
))) {
1543 ret
= ldb_search(ldb
, local_ctx
, &res
, sdn
, LDB_SCOPE_BASE
, attrs
,
1544 "(|(objectClass=domain)(objectClass=builtinDomain))");
1545 if (ret
== LDB_SUCCESS
) {
1546 if (res
->count
== 1) {
1554 if (ret
!= LDB_SUCCESS
) {
1555 *errstring
= talloc_asprintf(mem_ctx
, "Error searching for parent domain of %s, failed searching for %s: %s",
1556 ldb_dn_get_linearized(dn
),
1557 ldb_dn_get_linearized(sdn
),
1558 ldb_errstring(ldb
));
1559 talloc_free(local_ctx
);
1562 if (res
->count
!= 1) {
1563 *errstring
= talloc_asprintf(mem_ctx
, "Invalid dn (%s), not child of a domain object",
1564 ldb_dn_get_linearized(dn
));
1565 DEBUG(0,(__location__
": %s\n", *errstring
));
1566 talloc_free(local_ctx
);
1567 return LDB_ERR_CONSTRAINT_VIOLATION
;
1570 *parent_dn
= talloc_steal(mem_ctx
, res
->msgs
[0]->dn
);
1571 talloc_free(local_ctx
);
1577 * Performs checks on a user password (plaintext UNIX format - attribute
1578 * "password"). The remaining parameters have to be extracted from the domain
1581 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1583 enum samr_ValidationStatus
samdb_check_password(const DATA_BLOB
*password
,
1584 const uint32_t pwdProperties
,
1585 const uint32_t minPwdLength
)
1587 /* checks if the "minPwdLength" property is satisfied */
1588 if (minPwdLength
> password
->length
)
1589 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT
;
1591 /* checks the password complexity */
1592 if (((pwdProperties
& DOMAIN_PASSWORD_COMPLEX
) != 0)
1593 && (password
->data
!= NULL
)
1594 && (!check_password_quality((const char *) password
->data
)))
1595 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH
;
1597 return SAMR_VALIDATION_STATUS_SUCCESS
;
1601 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1602 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1603 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1604 * gives some more informations if the changed failed.
1606 * The caller should have a LDB transaction wrapping this.
1608 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1609 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1610 * NT_STATUS_PASSWORD_RESTRICTION
1612 NTSTATUS
samdb_set_password(struct ldb_context
*ctx
, TALLOC_CTX
*mem_ctx
,
1613 struct ldb_dn
*user_dn
, struct ldb_dn
*domain_dn
,
1614 struct ldb_message
*mod
,
1615 const DATA_BLOB
*new_password
,
1616 struct samr_Password
*param_lmNewHash
,
1617 struct samr_Password
*param_ntNewHash
,
1619 enum samPwdChangeReason
*reject_reason
,
1620 struct samr_DomInfo1
**_dominfo
)
1622 const char * const user_attrs
[] = { "userAccountControl",
1625 "dBCSPwd", "unicodePwd",
1627 "pwdLastSet", NULL
};
1628 const char * const domain_attrs
[] = { "minPwdLength", "pwdProperties",
1630 "maxPwdAge", "minPwdAge", NULL
};
1632 uint32_t minPwdLength
, pwdProperties
, pwdHistoryLength
;
1633 int64_t maxPwdAge
, minPwdAge
;
1634 uint32_t userAccountControl
;
1635 struct samr_Password
*sambaLMPwdHistory
, *sambaNTPwdHistory
,
1636 *lmPwdHash
, *ntPwdHash
, *lmNewHash
, *ntNewHash
;
1637 struct samr_Password local_lmNewHash
, local_ntNewHash
;
1638 int sambaLMPwdHistory_len
, sambaNTPwdHistory_len
;
1639 struct dom_sid
*domain_sid
;
1640 struct ldb_message
**res
;
1643 time_t now
= time(NULL
);
1647 /* we need to know the time to compute password age */
1648 unix_to_nt_time(&now_nt
, now
);
1650 /* pull all the user parameters */
1651 count
= gendb_search_dn(ctx
, mem_ctx
, user_dn
, &res
, user_attrs
);
1653 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1655 userAccountControl
= samdb_result_uint(res
[0], "userAccountControl", 0);
1656 sambaLMPwdHistory_len
= samdb_result_hashes(mem_ctx
, res
[0],
1657 "lmPwdHistory", &sambaLMPwdHistory
);
1658 sambaNTPwdHistory_len
= samdb_result_hashes(mem_ctx
, res
[0],
1659 "ntPwdHistory", &sambaNTPwdHistory
);
1660 lmPwdHash
= samdb_result_hash(mem_ctx
, res
[0], "dBCSPwd");
1661 ntPwdHash
= samdb_result_hash(mem_ctx
, res
[0], "unicodePwd");
1662 pwdLastSet
= samdb_result_uint64(res
[0], "pwdLastSet", 0);
1664 /* Copy parameters */
1665 lmNewHash
= param_lmNewHash
;
1666 ntNewHash
= param_ntNewHash
;
1668 /* Only non-trust accounts have restrictions (possibly this
1669 * test is the wrong way around, but I like to be restrictive
1671 restrictions
= !(userAccountControl
& (UF_INTERDOMAIN_TRUST_ACCOUNT
1672 |UF_WORKSTATION_TRUST_ACCOUNT
1673 |UF_SERVER_TRUST_ACCOUNT
));
1675 if (domain_dn
!= NULL
) {
1676 /* pull the domain parameters */
1677 count
= gendb_search_dn(ctx
, mem_ctx
, domain_dn
, &res
,
1680 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1681 ldb_dn_get_linearized(domain_dn
),
1682 ldb_dn_get_linearized(user_dn
)));
1683 return NT_STATUS_NO_SUCH_DOMAIN
;
1686 /* work out the domain sid, and pull the domain from there */
1687 domain_sid
= samdb_result_sid_prefix(mem_ctx
, res
[0],
1689 if (domain_sid
== NULL
) {
1690 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1693 count
= gendb_search(ctx
, mem_ctx
, NULL
, &res
, domain_attrs
,
1695 ldap_encode_ndr_dom_sid(mem_ctx
, domain_sid
));
1697 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1698 dom_sid_string(mem_ctx
, domain_sid
),
1699 ldb_dn_get_linearized(user_dn
)));
1700 return NT_STATUS_NO_SUCH_DOMAIN
;
1704 minPwdLength
= samdb_result_uint(res
[0], "minPwdLength", 0);
1705 pwdProperties
= samdb_result_uint(res
[0], "pwdProperties", 0);
1706 pwdHistoryLength
= samdb_result_uint(res
[0], "pwdHistoryLength", 0);
1707 maxPwdAge
= samdb_result_int64(res
[0], "maxPwdAge", 0);
1708 minPwdAge
= samdb_result_int64(res
[0], "minPwdAge", 0);
1710 if ((userAccountControl
& UF_PASSWD_NOTREQD
) != 0) {
1711 /* see [MS-ADTS] 2.2.15 */
1715 if (_dominfo
!= NULL
) {
1716 struct samr_DomInfo1
*dominfo
;
1717 /* on failure we need to fill in the reject reasons */
1718 dominfo
= talloc(mem_ctx
, struct samr_DomInfo1
);
1719 if (dominfo
== NULL
) {
1720 return NT_STATUS_NO_MEMORY
;
1722 dominfo
->min_password_length
= minPwdLength
;
1723 dominfo
->password_properties
= pwdProperties
;
1724 dominfo
->password_history_length
= pwdHistoryLength
;
1725 dominfo
->max_password_age
= maxPwdAge
;
1726 dominfo
->min_password_age
= minPwdAge
;
1727 *_dominfo
= dominfo
;
1730 if ((restrictions
!= 0) && (new_password
!= 0)) {
1733 /* checks if the "minPwdLength" property is satisfied */
1734 if ((restrictions
!= 0)
1735 && (minPwdLength
> utf16_len_n(
1736 new_password
->data
, new_password
->length
)/2)) {
1737 if (reject_reason
) {
1738 *reject_reason
= SAM_PWD_CHANGE_PASSWORD_TOO_SHORT
;
1740 return NT_STATUS_PASSWORD_RESTRICTION
;
1743 /* Create the NT hash */
1744 mdfour(local_ntNewHash
.hash
, new_password
->data
,
1745 new_password
->length
);
1747 ntNewHash
= &local_ntNewHash
;
1749 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1750 if (convert_string_talloc_convenience(mem_ctx
,
1751 lp_iconv_convenience(ldb_get_opaque(ctx
, "loadparm")),
1753 new_password
->data
, new_password
->length
,
1754 (void **)&new_pass
, NULL
, false)) {
1756 /* checks the password complexity */
1757 if ((restrictions
!= 0)
1759 & DOMAIN_PASSWORD_COMPLEX
) != 0)
1760 && (!check_password_quality(new_pass
))) {
1761 if (reject_reason
) {
1762 *reject_reason
= SAM_PWD_CHANGE_NOT_COMPLEX
;
1764 return NT_STATUS_PASSWORD_RESTRICTION
;
1767 /* compute the new lm hashes (for checking history - case insenitivly!) */
1768 if (E_deshash(new_pass
, local_lmNewHash
.hash
)) {
1769 lmNewHash
= &local_lmNewHash
;
1774 if ((restrictions
!= 0) && user_change
) {
1775 /* are all password changes disallowed? */
1776 if ((pwdProperties
& DOMAIN_REFUSE_PASSWORD_CHANGE
) != 0) {
1777 if (reject_reason
) {
1778 *reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1780 return NT_STATUS_PASSWORD_RESTRICTION
;
1783 /* can this user change the password? */
1784 if ((userAccountControl
& UF_PASSWD_CANT_CHANGE
) != 0) {
1785 if (reject_reason
) {
1786 *reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1788 return NT_STATUS_PASSWORD_RESTRICTION
;
1791 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1792 if (pwdLastSet
- minPwdAge
> now_nt
) {
1793 if (reject_reason
) {
1794 *reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1796 return NT_STATUS_PASSWORD_RESTRICTION
;
1799 /* check the immediately past password */
1800 if (pwdHistoryLength
> 0) {
1801 if (lmNewHash
&& lmPwdHash
&& memcmp(lmNewHash
->hash
,
1802 lmPwdHash
->hash
, 16) == 0) {
1803 if (reject_reason
) {
1804 *reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1806 return NT_STATUS_PASSWORD_RESTRICTION
;
1808 if (ntNewHash
&& ntPwdHash
&& memcmp(ntNewHash
->hash
,
1809 ntPwdHash
->hash
, 16) == 0) {
1810 if (reject_reason
) {
1811 *reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1813 return NT_STATUS_PASSWORD_RESTRICTION
;
1817 /* check the password history */
1818 sambaLMPwdHistory_len
= MIN(sambaLMPwdHistory_len
,
1820 sambaNTPwdHistory_len
= MIN(sambaNTPwdHistory_len
,
1823 for (i
=0; lmNewHash
&& i
<sambaLMPwdHistory_len
;i
++) {
1824 if (memcmp(lmNewHash
->hash
, sambaLMPwdHistory
[i
].hash
,
1826 if (reject_reason
) {
1827 *reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1829 return NT_STATUS_PASSWORD_RESTRICTION
;
1832 for (i
=0; ntNewHash
&& i
<sambaNTPwdHistory_len
;i
++) {
1833 if (memcmp(ntNewHash
->hash
, sambaNTPwdHistory
[i
].hash
,
1835 if (reject_reason
) {
1836 *reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1838 return NT_STATUS_PASSWORD_RESTRICTION
;
1843 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1845 /* the password is acceptable. Start forming the new fields */
1846 if (new_password
!= NULL
) {
1847 /* if we know the cleartext UTF16 password, then set it.
1848 * Modules in ldb will set all the appropriate
1850 CHECK_RET(ldb_msg_add_value(mod
, "clearTextPassword", new_password
, NULL
));
1852 /* We don't have the cleartext, so delete the old one
1853 * and set what we have of the hashes */
1854 CHECK_RET(samdb_msg_add_delete(ctx
, mem_ctx
, mod
, "clearTextPassword"));
1857 CHECK_RET(samdb_msg_add_hash(ctx
, mem_ctx
, mod
, "dBCSPwd", lmNewHash
));
1859 CHECK_RET(samdb_msg_add_delete(ctx
, mem_ctx
, mod
, "dBCSPwd"));
1863 CHECK_RET(samdb_msg_add_hash(ctx
, mem_ctx
, mod
, "unicodePwd", ntNewHash
));
1865 CHECK_RET(samdb_msg_add_delete(ctx
, mem_ctx
, mod
, "unicodePwd"));
1869 if (reject_reason
) {
1870 *reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1872 return NT_STATUS_OK
;
1877 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1878 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1879 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1880 * gives some more informations if the changed failed.
1882 * This wrapper function for "samdb_set_password" takes a SID as input rather
1885 * This call encapsulates a new LDB transaction for changing the password;
1886 * therefore the user hasn't to start a new one.
1888 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1889 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1890 * NT_STATUS_PASSWORD_RESTRICTION
1892 NTSTATUS
samdb_set_password_sid(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
,
1893 const struct dom_sid
*user_sid
,
1894 const DATA_BLOB
*new_password
,
1895 struct samr_Password
*lmNewHash
,
1896 struct samr_Password
*ntNewHash
,
1898 enum samPwdChangeReason
*reject_reason
,
1899 struct samr_DomInfo1
**_dominfo
)
1902 struct ldb_dn
*user_dn
;
1903 struct ldb_message
*msg
;
1906 ret
= ldb_transaction_start(ldb
);
1907 if (ret
!= LDB_SUCCESS
) {
1908 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb
)));
1909 return NT_STATUS_TRANSACTION_ABORTED
;
1912 user_dn
= samdb_search_dn(ldb
, mem_ctx
, NULL
,
1913 "(&(objectSid=%s)(objectClass=user))",
1914 ldap_encode_ndr_dom_sid(mem_ctx
, user_sid
));
1916 ldb_transaction_cancel(ldb
);
1917 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1918 dom_sid_string(mem_ctx
, user_sid
)));
1919 return NT_STATUS_NO_SUCH_USER
;
1922 msg
= ldb_msg_new(mem_ctx
);
1924 ldb_transaction_cancel(ldb
);
1925 return NT_STATUS_NO_MEMORY
;
1928 msg
->dn
= ldb_dn_copy(msg
, user_dn
);
1930 ldb_transaction_cancel(ldb
);
1931 return NT_STATUS_NO_MEMORY
;
1934 nt_status
= samdb_set_password(ldb
, mem_ctx
,
1937 lmNewHash
, ntNewHash
,
1938 user_change
, /* This is a password set, not change */
1939 reject_reason
, _dominfo
);
1940 if (!NT_STATUS_IS_OK(nt_status
)) {
1941 ldb_transaction_cancel(ldb
);
1945 /* modify the samdb record */
1946 ret
= samdb_replace(ldb
, mem_ctx
, msg
);
1947 if (ret
!= LDB_SUCCESS
) {
1948 ldb_transaction_cancel(ldb
);
1949 return NT_STATUS_ACCESS_DENIED
;
1952 ret
= ldb_transaction_commit(ldb
);
1953 if (ret
!= LDB_SUCCESS
) {
1954 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1955 ldb_dn_get_linearized(msg
->dn
),
1956 ldb_errstring(ldb
)));
1957 return NT_STATUS_TRANSACTION_ABORTED
;
1959 return NT_STATUS_OK
;
1963 NTSTATUS
samdb_create_foreign_security_principal(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
,
1964 struct dom_sid
*sid
, struct ldb_dn
**ret_dn
)
1966 struct ldb_message
*msg
;
1967 struct ldb_dn
*basedn
;
1971 sidstr
= dom_sid_string(mem_ctx
, sid
);
1972 NT_STATUS_HAVE_NO_MEMORY(sidstr
);
1974 /* We might have to create a ForeignSecurityPrincipal, even if this user
1975 * is in our own domain */
1977 msg
= ldb_msg_new(mem_ctx
);
1979 return NT_STATUS_NO_MEMORY
;
1982 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1983 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1984 * not work, this is wrong for the Builtin domain, there's no
1985 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1988 basedn
= samdb_search_dn(sam_ctx
, mem_ctx
, NULL
,
1989 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1991 if (basedn
== NULL
) {
1992 DEBUG(0, ("Failed to find DN for "
1993 "ForeignSecurityPrincipal container\n"));
1994 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1997 /* add core elements to the ldb_message for the alias */
1998 msg
->dn
= ldb_dn_copy(mem_ctx
, basedn
);
1999 if ( ! ldb_dn_add_child_fmt(msg
->dn
, "CN=%s", sidstr
))
2000 return NT_STATUS_NO_MEMORY
;
2002 samdb_msg_add_string(sam_ctx
, mem_ctx
, msg
,
2004 "foreignSecurityPrincipal");
2006 /* create the alias */
2007 ret
= ldb_add(sam_ctx
, msg
);
2009 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2011 ldb_dn_get_linearized(msg
->dn
),
2012 ldb_errstring(sam_ctx
)));
2013 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2016 return NT_STATUS_OK
;
2021 Find the DN of a domain, assuming it to be a dotted.dns name
2024 struct ldb_dn
*samdb_dns_domain_to_dn(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
, const char *dns_domain
)
2027 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
2028 const char *binary_encoded
;
2029 const char **split_realm
;
2036 split_realm
= (const char **)str_list_make(tmp_ctx
, dns_domain
, ".");
2038 talloc_free(tmp_ctx
);
2041 dn
= ldb_dn_new(mem_ctx
, ldb
, NULL
);
2042 for (i
=0; split_realm
[i
]; i
++) {
2043 binary_encoded
= ldb_binary_encode_string(tmp_ctx
, split_realm
[i
]);
2044 if (!ldb_dn_add_base_fmt(dn
, "dc=%s", binary_encoded
)) {
2045 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2046 binary_encoded
, ldb_dn_get_linearized(dn
)));
2047 talloc_free(tmp_ctx
);
2051 if (!ldb_dn_validate(dn
)) {
2052 DEBUG(2, ("Failed to validated DN %s\n",
2053 ldb_dn_get_linearized(dn
)));
2059 Find the DN of a domain, be it the netbios or DNS name
2062 struct ldb_dn
*samdb_domain_to_dn(struct ldb_context
*ldb
, TALLOC_CTX
*mem_ctx
,
2063 const char *domain_name
)
2065 const char * const domain_ref_attrs
[] = {
2068 const char * const domain_ref2_attrs
[] = {
2071 struct ldb_result
*res_domain_ref
;
2072 char *escaped_domain
= ldb_binary_encode_string(mem_ctx
, domain_name
);
2073 /* find the domain's DN */
2074 int ret_domain
= ldb_search(ldb
, mem_ctx
,
2076 samdb_partitions_dn(ldb
, mem_ctx
),
2079 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2081 if (ret_domain
!= 0) {
2085 if (res_domain_ref
->count
== 0) {
2086 ret_domain
= ldb_search(ldb
, mem_ctx
,
2088 samdb_dns_domain_to_dn(ldb
, mem_ctx
, domain_name
),
2091 "(objectclass=domain)");
2092 if (ret_domain
!= 0) {
2096 if (res_domain_ref
->count
== 1) {
2097 return res_domain_ref
->msgs
[0]->dn
;
2102 if (res_domain_ref
->count
> 1) {
2103 DEBUG(0,("Found %d records matching domain [%s]\n",
2104 ret_domain
, domain_name
));
2108 return samdb_result_dn(ldb
, mem_ctx
, res_domain_ref
->msgs
[0], "nCName", NULL
);
2114 use a GUID to find a DN
2116 int dsdb_find_dn_by_guid(struct ldb_context
*ldb
,
2117 TALLOC_CTX
*mem_ctx
,
2118 const char *guid_str
, struct ldb_dn
**dn
)
2121 struct ldb_result
*res
;
2122 const char *attrs
[] = { NULL
};
2123 struct ldb_request
*search_req
;
2125 struct ldb_search_options_control
*options
;
2127 expression
= talloc_asprintf(mem_ctx
, "objectGUID=%s", guid_str
);
2129 DEBUG(0, (__location__
": out of memory\n"));
2130 return LDB_ERR_OPERATIONS_ERROR
;
2133 res
= talloc_zero(mem_ctx
, struct ldb_result
);
2135 DEBUG(0, (__location__
": out of memory\n"));
2136 return LDB_ERR_OPERATIONS_ERROR
;
2139 ret
= ldb_build_search_req(&search_req
, ldb
, mem_ctx
,
2140 ldb_get_default_basedn(ldb
),
2144 res
, ldb_search_default_callback
,
2146 if (ret
!= LDB_SUCCESS
) {
2150 /* we need to cope with cross-partition links, so search for
2151 the GUID over all partitions */
2152 options
= talloc(search_req
, struct ldb_search_options_control
);
2153 if (options
== NULL
) {
2154 DEBUG(0, (__location__
": out of memory\n"));
2155 return LDB_ERR_OPERATIONS_ERROR
;
2157 options
->search_options
= LDB_SEARCH_OPTION_PHANTOM_ROOT
;
2159 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_EXTENDED_DN_OID
, true, NULL
);
2160 if (ret
!= LDB_SUCCESS
) {
2164 ret
= ldb_request_add_control(search_req
,
2165 LDB_CONTROL_SEARCH_OPTIONS_OID
,
2167 if (ret
!= LDB_SUCCESS
) {
2171 ret
= ldb_request(ldb
, search_req
);
2172 if (ret
!= LDB_SUCCESS
) {
2176 ret
= ldb_wait(search_req
->handle
, LDB_WAIT_ALL
);
2177 if (ret
!= LDB_SUCCESS
) {
2181 /* this really should be exactly 1, but there is a bug in the
2182 partitions module that can return two here with the
2183 search_options control set */
2184 if (res
->count
< 1) {
2185 return LDB_ERR_NO_SUCH_OBJECT
;
2188 *dn
= res
->msgs
[0]->dn
;
2194 search for attrs on one DN, allowing for deleted objects
2196 int dsdb_search_dn_with_deleted(struct ldb_context
*ldb
,
2197 TALLOC_CTX
*mem_ctx
,
2198 struct ldb_result
**_res
,
2199 struct ldb_dn
*basedn
,
2200 const char * const *attrs
)
2203 struct ldb_request
*req
;
2204 TALLOC_CTX
*tmp_ctx
;
2205 struct ldb_result
*res
;
2207 tmp_ctx
= talloc_new(mem_ctx
);
2209 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
2211 return LDB_ERR_OPERATIONS_ERROR
;
2214 ret
= ldb_build_search_req(&req
, ldb
, tmp_ctx
,
2221 ldb_search_default_callback
,
2223 if (ret
!= LDB_SUCCESS
) {
2224 talloc_free(tmp_ctx
);
2228 ret
= ldb_request_add_control(req
, LDB_CONTROL_SHOW_DELETED_OID
, true, NULL
);
2229 if (ret
!= LDB_SUCCESS
) {
2233 ret
= ldb_request(ldb
, req
);
2234 if (ret
== LDB_SUCCESS
) {
2235 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
2239 *_res
= talloc_steal(mem_ctx
, res
);
2245 use a DN to find a GUID
2247 int dsdb_find_guid_by_dn(struct ldb_context
*ldb
,
2248 struct ldb_dn
*dn
, struct GUID
*guid
)
2251 struct ldb_result
*res
;
2252 const char *attrs
[] = { "objectGUID", NULL
};
2253 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
2255 ret
= dsdb_search_dn_with_deleted(ldb
, tmp_ctx
, &res
, dn
, attrs
);
2256 if (ret
!= LDB_SUCCESS
) {
2257 talloc_free(tmp_ctx
);
2260 if (res
->count
< 1) {
2261 talloc_free(tmp_ctx
);
2262 return LDB_ERR_NO_SUCH_OBJECT
;
2264 *guid
= samdb_result_guid(res
->msgs
[0], "objectGUID");
2265 talloc_free(tmp_ctx
);
2270 use a DN to find a SID
2272 int dsdb_find_sid_by_dn(struct ldb_context
*ldb
,
2273 struct ldb_dn
*dn
, struct dom_sid
*sid
)
2276 struct ldb_result
*res
;
2277 const char *attrs
[] = { "objectSID", NULL
};
2278 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
2283 ret
= dsdb_search_dn_with_deleted(ldb
, tmp_ctx
, &res
, dn
, attrs
);
2284 if (ret
!= LDB_SUCCESS
) {
2285 talloc_free(tmp_ctx
);
2288 if (res
->count
< 1) {
2289 talloc_free(tmp_ctx
);
2290 return LDB_ERR_NO_SUCH_OBJECT
;
2292 s
= samdb_result_dom_sid(tmp_ctx
, res
->msgs
[0], "objectSID");
2294 talloc_free(tmp_ctx
);
2295 return LDB_ERR_NO_SUCH_OBJECT
;
2298 talloc_free(tmp_ctx
);
2305 load a repsFromTo blob list for a given partition GUID
2306 attr must be "repsFrom" or "repsTo"
2308 WERROR
dsdb_loadreps(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
, struct ldb_dn
*dn
,
2309 const char *attr
, struct repsFromToBlob
**r
, uint32_t *count
)
2311 const char *attrs
[] = { attr
, NULL
};
2312 struct ldb_result
*res
= NULL
;
2313 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
2315 struct ldb_message_element
*el
;
2320 if (ldb_search(sam_ctx
, tmp_ctx
, &res
, dn
, LDB_SCOPE_BASE
, attrs
, NULL
) != LDB_SUCCESS
||
2322 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2323 talloc_free(tmp_ctx
);
2324 return WERR_DS_DRA_INTERNAL_ERROR
;
2327 el
= ldb_msg_find_element(res
->msgs
[0], attr
);
2329 /* it's OK to be empty */
2330 talloc_free(tmp_ctx
);
2334 *count
= el
->num_values
;
2335 *r
= talloc_array(mem_ctx
, struct repsFromToBlob
, *count
);
2337 talloc_free(tmp_ctx
);
2338 return WERR_DS_DRA_INTERNAL_ERROR
;
2341 for (i
=0; i
<(*count
); i
++) {
2342 enum ndr_err_code ndr_err
;
2343 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
],
2344 mem_ctx
, lp_iconv_convenience(ldb_get_opaque(sam_ctx
, "loadparm")),
2346 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
2347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2348 talloc_free(tmp_ctx
);
2349 return WERR_DS_DRA_INTERNAL_ERROR
;
2353 talloc_free(tmp_ctx
);
2359 save the repsFromTo blob list for a given partition GUID
2360 attr must be "repsFrom" or "repsTo"
2362 WERROR
dsdb_savereps(struct ldb_context
*sam_ctx
, TALLOC_CTX
*mem_ctx
, struct ldb_dn
*dn
,
2363 const char *attr
, struct repsFromToBlob
*r
, uint32_t count
)
2365 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
2366 struct ldb_message
*msg
;
2367 struct ldb_message_element
*el
;
2370 msg
= ldb_msg_new(tmp_ctx
);
2372 if (ldb_msg_add_empty(msg
, attr
, LDB_FLAG_MOD_REPLACE
, &el
) != LDB_SUCCESS
) {
2376 el
->values
= talloc_array(msg
, struct ldb_val
, count
);
2381 for (i
=0; i
<count
; i
++) {
2383 enum ndr_err_code ndr_err
;
2385 ndr_err
= ndr_push_struct_blob(&v
, tmp_ctx
, lp_iconv_convenience(ldb_get_opaque(sam_ctx
, "loadparm")),
2387 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
2388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2396 if (ldb_modify(sam_ctx
, msg
) != LDB_SUCCESS
) {
2397 DEBUG(0,("Failed to store %s - %s\n", attr
, ldb_errstring(sam_ctx
)));
2401 talloc_free(tmp_ctx
);
2406 talloc_free(tmp_ctx
);
2407 return WERR_DS_DRA_INTERNAL_ERROR
;
2412 load the uSNHighest attribute from the @REPLCHANGED object for a
2415 int dsdb_load_partition_usn(struct ldb_context
*ldb
, struct ldb_dn
*dn
, uint64_t *uSN
)
2417 struct ldb_request
*req
;
2419 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
2420 struct dsdb_control_current_partition
*p_ctrl
;
2421 struct ldb_result
*res
;
2423 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
2425 talloc_free(tmp_ctx
);
2426 return LDB_ERR_OPERATIONS_ERROR
;
2429 ret
= ldb_build_search_req(&req
, ldb
, tmp_ctx
,
2430 ldb_dn_new(tmp_ctx
, ldb
, "@REPLCHANGED"),
2434 res
, ldb_search_default_callback
,
2436 if (ret
!= LDB_SUCCESS
) {
2437 talloc_free(tmp_ctx
);
2441 p_ctrl
= talloc(req
, struct dsdb_control_current_partition
);
2442 if (p_ctrl
== NULL
) {
2444 return LDB_ERR_OPERATIONS_ERROR
;
2446 p_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
2450 ret
= ldb_request_add_control(req
,
2451 DSDB_CONTROL_CURRENT_PARTITION_OID
,
2453 if (ret
!= LDB_SUCCESS
) {
2454 talloc_free(tmp_ctx
);
2458 /* Run the new request */
2459 ret
= ldb_request(ldb
, req
);
2461 if (ret
== LDB_SUCCESS
) {
2462 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
2465 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
2466 /* it hasn't been created yet, which means
2467 an implicit value of zero */
2469 talloc_free(tmp_ctx
);
2473 if (ret
!= LDB_SUCCESS
) {
2474 talloc_free(tmp_ctx
);
2478 if (res
->count
< 1) {
2481 *uSN
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "uSNHighest", 0);
2484 talloc_free(tmp_ctx
);
2490 save the uSNHighest attribute in the @REPLCHANGED object for a
2493 int dsdb_save_partition_usn(struct ldb_context
*ldb
, struct ldb_dn
*dn
, uint64_t uSN
)
2495 struct ldb_request
*req
;
2496 struct ldb_message
*msg
;
2497 struct dsdb_control_current_partition
*p_ctrl
;
2500 msg
= ldb_msg_new(ldb
);
2502 return LDB_ERR_OPERATIONS_ERROR
;
2505 msg
->dn
= ldb_dn_new(msg
, ldb
, "@REPLCHANGED");
2506 if (msg
->dn
== NULL
) {
2508 return LDB_ERR_OPERATIONS_ERROR
;
2511 ret
= ldb_msg_add_fmt(msg
, "uSNHighest", "%llu", (unsigned long long)uSN
);
2512 if (ret
!= LDB_SUCCESS
) {
2516 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
2519 p_ctrl
= talloc(msg
, struct dsdb_control_current_partition
);
2520 if (p_ctrl
== NULL
) {
2522 return LDB_ERR_OPERATIONS_ERROR
;
2524 p_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
2527 ret
= ldb_build_mod_req(&req
, ldb
, msg
,
2530 NULL
, ldb_op_default_callback
,
2533 if (ret
!= LDB_SUCCESS
) {
2538 ret
= ldb_request_add_control(req
,
2539 DSDB_CONTROL_CURRENT_PARTITION_OID
,
2541 if (ret
!= LDB_SUCCESS
) {
2546 /* Run the new request */
2547 ret
= ldb_request(ldb
, req
);
2549 if (ret
== LDB_SUCCESS
) {
2550 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
2552 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
2553 ret
= ldb_build_add_req(&req
, ldb
, msg
,
2556 NULL
, ldb_op_default_callback
,
2566 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2
*c1
,
2567 const struct drsuapi_DsReplicaCursor2
*c2
)
2569 return GUID_compare(&c1
->source_dsa_invocation_id
, &c2
->source_dsa_invocation_id
);
2573 see if we are a RODC
2575 TODO: This should take a sam_ctx, and lookup the right object (with
2578 bool samdb_rodc(struct loadparm_context
*lp_ctx
)
2580 return lp_parm_bool(lp_ctx
, NULL
, "repl", "RODC", false);
2585 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2587 flags are DS_NTDS_OPTION_*
2589 int samdb_ntds_options(struct ldb_context
*ldb
, uint32_t *options
)
2591 TALLOC_CTX
*tmp_ctx
;
2592 const char *attrs
[] = { "options", NULL
};
2594 struct ldb_result
*res
;
2596 tmp_ctx
= talloc_new(ldb
);
2597 if (tmp_ctx
== NULL
) {
2601 ret
= ldb_search(ldb
, tmp_ctx
, &res
, samdb_ntds_settings_dn(ldb
), LDB_SCOPE_BASE
, attrs
, NULL
);
2606 if (res
->count
!= 1) {
2610 *options
= samdb_result_uint(res
->msgs
[0], "options", 0);
2612 talloc_free(tmp_ctx
);
2617 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2618 talloc_free(tmp_ctx
);
2619 return LDB_ERR_NO_SUCH_OBJECT
;