s4:samdb_check_password - allow the password string to be NULL
[Samba/fernandojvsilva.git] / source4 / dsdb / common / util.c
blob393e1d45f515a55b80fe50357a97a21231b1715d
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_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,
46 TALLOC_CTX *mem_ctx,
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)
53 va_list ap;
54 int i, count;
56 va_start(ap, format);
57 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
58 res, attrs, format, ap);
59 va_end(ap);
61 i=0;
63 while (i<count) {
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];
72 count -= 1;
73 talloc_free(entry_sid);
74 continue;
76 talloc_free(entry_sid);
77 i += 1;
80 return count;
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,
87 TALLOC_CTX *mem_ctx,
88 struct ldb_dn *basedn,
89 const char *attr_name,
90 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
92 int count;
93 const char *attrs[2] = { NULL, NULL };
94 struct ldb_message **res = NULL;
96 attrs[0] = attr_name;
98 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
99 if (count > 1) {
100 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
101 attr_name, format, count));
103 if (count != 1) {
104 talloc_free(res);
105 return NULL;
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,
115 TALLOC_CTX *mem_ctx,
116 struct ldb_dn *basedn,
117 const char *attr_name,
118 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
120 va_list ap;
121 const char *str;
123 va_start(ap, format);
124 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
125 va_end(ap);
127 return str;
130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
131 TALLOC_CTX *mem_ctx,
132 struct ldb_dn *basedn,
133 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
135 va_list ap;
136 struct ldb_dn *ret;
137 struct ldb_message **res = NULL;
138 int count;
140 va_start(ap, format);
141 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
142 va_end(ap);
144 if (count != 1) return NULL;
146 ret = talloc_steal(mem_ctx, res[0]->dn);
147 talloc_free(res);
149 return ret;
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,
156 TALLOC_CTX *mem_ctx,
157 struct ldb_dn *basedn,
158 const char *attr_name,
159 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
161 va_list ap;
162 int count;
163 struct ldb_message **res;
164 const char *attrs[2] = { NULL, NULL };
165 struct dom_sid *sid;
167 attrs[0] = attr_name;
169 va_start(ap, format);
170 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
171 va_end(ap);
172 if (count > 1) {
173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174 attr_name, format, count));
176 if (count != 1) {
177 talloc_free(res);
178 return NULL;
180 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
181 talloc_free(res);
182 return sid;
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,
189 TALLOC_CTX *mem_ctx,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
193 va_list ap;
194 struct ldb_message **res;
195 const char * const attrs[] = { NULL };
196 int ret;
198 va_start(ap, format);
199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
200 va_end(ap);
202 return ret;
207 search the sam for a single integer attribute in exactly 1 record
209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
210 TALLOC_CTX *mem_ctx,
211 uint_t default_value,
212 struct ldb_dn *basedn,
213 const char *attr_name,
214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
216 va_list ap;
217 int count;
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);
225 va_end(ap);
227 if (count != 1) {
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,
238 TALLOC_CTX *mem_ctx,
239 int64_t default_value,
240 struct ldb_dn *basedn,
241 const char *attr_name,
242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
244 va_list ap;
245 int count;
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);
253 va_end(ap);
255 if (count != 1) {
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,
267 TALLOC_CTX *mem_ctx,
268 struct ldb_dn *basedn,
269 const char ***strs,
270 const char *attr_name,
271 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
273 va_list ap;
274 int count, i;
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);
282 va_end(ap);
284 if (count <= 0) {
285 return count;
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",
292 attr_name, format));
293 talloc_free(res);
294 return -1;
298 *strs = talloc_array(mem_ctx, const char *, count+1);
299 if (! *strs) {
300 talloc_free(res);
301 return -1;
304 for (i=0;i<count;i++) {
305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
307 (*strs)[count] = NULL;
309 return count;
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);
341 if (!ret_dn) {
342 return default_value;
344 return ret_dn;
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)
353 struct dom_sid *sid;
354 uint32_t rid;
356 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
357 if (sid == NULL) {
358 return default_value;
360 rid = sid->sub_auths[sid->num_auths-1];
361 talloc_free(sid);
362 return rid;
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,
369 const char *attr)
371 const struct ldb_val *v;
372 struct dom_sid *sid;
373 enum ndr_err_code ndr_err;
374 v = ldb_msg_find_ldb_val(msg, attr);
375 if (v == NULL) {
376 return NULL;
378 sid = talloc(mem_ctx, struct dom_sid);
379 if (sid == NULL) {
380 return NULL;
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)) {
385 talloc_free(sid);
386 return NULL;
388 return sid;
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;
398 struct GUID guid;
399 TALLOC_CTX *mem_ctx;
401 ZERO_STRUCT(guid);
403 v = ldb_msg_find_ldb_val(msg, attr);
404 if (!v) return guid;
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)) {
412 return guid;
415 return guid;
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,
423 const char *attr)
425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426 if (!sid || sid->num_auths < 1) return NULL;
427 sid->num_auths--;
428 return sid;
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);
449 if (ret == 0)
450 ret = 0x7FFFFFFFFFFFFFFFULL;
452 return ret;
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",
472 if (ret == 0)
473 ret = 0x7FFFFFFFFFFFFFFFULL;
475 return ret;
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,
492 TALLOC_CTX *mem_ctx,
493 struct ldb_dn *domain_dn,
494 struct ldb_message *msg,
495 const char *attr)
497 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
498 int64_t minPwdAge;
500 if (attr_time == 0) {
501 return 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;
510 return attr_time;
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,
518 TALLOC_CTX *mem_ctx,
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);
524 int64_t maxPwdAge;
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) {
533 return 0;
536 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
537 if (maxPwdAge == 0) {
538 return 0x7FFFFFFFFFFFFFFFULL;
539 } else {
540 attr_time -= maxPwdAge;
543 return attr_time;
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)));
557 return 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)
566 uint_t count = 0;
567 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
568 int i;
570 *hashes = NULL;
571 if (!val) {
572 return 0;
574 count = val->length / 16;
575 if (count == 0) {
576 return 0;
579 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
580 if (! *hashes) {
581 return 0;
584 for (i=0;i<count;i++) {
585 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
588 return count;
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;
595 if (nt_pwd) {
596 int num_nt;
597 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
598 if (num_nt == 0) {
599 *nt_pwd = NULL;
600 } else if (num_nt > 1) {
601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
602 } else {
603 *nt_pwd = &ntPwdHash[0];
606 if (lm_pwd) {
607 /* Ensure that if we have turned off LM
608 * authentication, that we never use the LM hash, even
609 * if we store it */
610 if (lp_lanman_auth(lp_ctx)) {
611 int num_lm;
612 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
613 if (num_lm == 0) {
614 *lm_pwd = NULL;
615 } else if (num_lm > 1) {
616 return NT_STATUS_INTERNAL_DB_CORRUPTION;
617 } else {
618 *lm_pwd = &lmPwdHash[0];
620 } else {
621 *lm_pwd = NULL;
624 return NT_STATUS_OK;
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);
635 ZERO_STRUCT(hours);
636 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
637 if (!hours.bits) {
638 return hours;
640 hours.units_per_week = units_per_week;
641 memset(hours.bits, 0xFF, units_per_week);
642 if (val) {
643 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
645 return hours;
649 pull a set of account_flags from a result set.
651 This requires that the attributes:
652 pwdLastSet
653 userAccountControl
654 be included in 'msg'
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;
662 NTTIME now;
664 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
665 domain_dn, msg);
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;
673 return acct_flags;
676 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
677 struct ldb_message *msg,
678 const char *attr)
680 struct lsa_BinaryString s;
681 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
683 ZERO_STRUCT(s);
685 if (!val) {
686 return s;
689 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
690 if (!s.array) {
691 return s;
693 s.length = s.size = val->length/2;
694 memcpy(s.array, val->data, val->length);
696 return s;
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)
709 int i;
710 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
712 if (!el) {
713 return NULL;
716 for (i=0;i<el->num_values;i++) {
717 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
718 return el;
722 return NULL;
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);
730 return LDB_SUCCESS;
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);
738 if (el) {
739 return LDB_SUCCESS;
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)
767 struct ldb_val v;
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")),
772 sid,
773 (ndr_push_flags_fn_t)ndr_push_dom_sid);
774 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
775 return -1;
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;
799 char *a, *v;
800 int ret;
801 a = talloc_strdup(mem_ctx, attr_name);
802 if (a == NULL)
803 return -1;
804 v = talloc_strdup(mem_ctx, value);
805 if (v == NULL)
806 return -1;
807 ret = ldb_msg_add_string(msg, a, v);
808 if (ret != 0)
809 return ret;
810 el = ldb_msg_find_element(msg, a);
811 if (el == NULL)
812 return -1;
813 el->flags = LDB_FLAG_MOD_ADD;
814 return 0;
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;
824 char *a, *v;
825 int ret;
826 a = talloc_strdup(mem_ctx, attr_name);
827 if (a == NULL)
828 return -1;
829 v = talloc_strdup(mem_ctx, value);
830 if (v == NULL)
831 return -1;
832 ret = ldb_msg_add_string(msg, a, v);
833 if (ret != 0)
834 return ret;
835 el = ldb_msg_find_element(msg, a);
836 if (el == NULL)
837 return -1;
838 el->flags = LDB_FLAG_MOD_DELETE;
839 return 0;
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)
888 struct ldb_val val;
889 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
890 if (!val.data) {
891 return -1;
893 val.length = 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)
903 struct ldb_val val;
904 int i;
905 val.data = talloc_array_size(mem_ctx, 16, count);
906 val.length = count*16;
907 if (!val.data) {
908 return -1;
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)
931 struct ldb_val val;
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)
943 struct ldb_val val;
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);
966 if (el) {
967 el->num_values = 0;
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);
981 if (el) {
982 el->num_values = 0;
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)
992 int i;
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);
1012 return sd;
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);
1042 return NULL;
1044 return 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);
1054 return NULL;
1056 return 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[] = {
1067 "objectSid",
1068 NULL
1070 struct ldb_result *res;
1071 int ret;
1073 /* see if we have a cached copy */
1074 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1075 if (domain_sid) {
1076 return domain_sid;
1079 tmp_ctx = talloc_new(ldb);
1080 if (tmp_ctx == NULL) {
1081 goto failed;
1084 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1086 if (ret != LDB_SUCCESS) {
1087 goto failed;
1090 if (res->count != 1) {
1091 goto failed;
1094 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1095 if (domain_sid == NULL) {
1096 goto failed;
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) {
1101 goto failed;
1104 talloc_steal(ldb, domain_sid);
1105 talloc_free(tmp_ctx);
1107 return domain_sid;
1109 failed:
1110 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1111 talloc_free(tmp_ctx);
1112 return NULL;
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) {
1127 goto failed;
1130 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1131 if (!dom_sid_new) {
1132 goto failed;
1135 /* cache the domain_sid in the ldb */
1136 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1137 goto failed;
1140 talloc_steal(ldb, dom_sid_new);
1141 talloc_free(tmp_ctx);
1142 talloc_free(dom_sid_old);
1144 return true;
1146 failed:
1147 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1148 talloc_free(tmp_ctx);
1149 return false;
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,
1155 const char *attr)
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
1165 * ascii string */
1166 return NULL;
1168 if (val) {
1169 return (char *)val->data;
1171 return NULL;
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 };
1181 int ret;
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");
1187 if (settings_dn) {
1188 return settings_dn;
1191 tmp_ctx = talloc_new(ldb);
1192 if (tmp_ctx == NULL) {
1193 goto failed;
1196 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1197 if (ret) {
1198 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1199 ldb_errstring(ldb)));
1200 goto failed;
1203 if (root_res->count != 1) {
1204 goto failed;
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) {
1211 goto failed;
1214 talloc_steal(ldb, settings_dn);
1215 talloc_free(tmp_ctx);
1217 return settings_dn;
1219 failed:
1220 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1221 talloc_free(tmp_ctx);
1222 return NULL;
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 };
1232 int ret;
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) {
1244 goto failed;
1247 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1248 if (ret) {
1249 goto failed;
1252 if (res->count != 1) {
1253 goto failed;
1256 invocation_id = talloc(tmp_ctx, struct GUID);
1257 if (!invocation_id) {
1258 goto failed;
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) {
1265 goto failed;
1268 talloc_steal(ldb, invocation_id);
1269 talloc_free(tmp_ctx);
1271 return invocation_id;
1273 failed:
1274 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1275 talloc_free(tmp_ctx);
1276 return NULL;
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) {
1291 goto failed;
1294 invocation_id_new = talloc(tmp_ctx, struct GUID);
1295 if (!invocation_id_new) {
1296 goto failed;
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) {
1303 goto failed;
1306 talloc_steal(ldb, invocation_id_new);
1307 talloc_free(tmp_ctx);
1308 talloc_free(invocation_id_old);
1310 return true;
1312 failed:
1313 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314 talloc_free(tmp_ctx);
1315 return false;
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 };
1325 int ret;
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");
1331 if (ntds_guid) {
1332 return ntds_guid;
1335 tmp_ctx = talloc_new(ldb);
1336 if (tmp_ctx == NULL) {
1337 goto failed;
1340 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1341 if (ret) {
1342 goto failed;
1345 if (res->count != 1) {
1346 goto failed;
1349 ntds_guid = talloc(tmp_ctx, struct GUID);
1350 if (!ntds_guid) {
1351 goto failed;
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) {
1358 goto failed;
1361 talloc_steal(ldb, ntds_guid);
1362 talloc_free(tmp_ctx);
1364 return ntds_guid;
1366 failed:
1367 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1368 talloc_free(tmp_ctx);
1369 return NULL;
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) {
1383 goto failed;
1386 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1387 if (!ntds_guid_new) {
1388 goto failed;
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) {
1395 goto failed;
1398 talloc_steal(ldb, ntds_guid_new);
1399 talloc_free(tmp_ctx);
1400 talloc_free(ntds_guid_old);
1402 return true;
1404 failed:
1405 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1406 talloc_free(tmp_ctx);
1407 return false;
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));
1439 if (val != NULL)
1440 return (const char *) val->data;
1441 else
1442 return NULL;
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 };
1451 int ret;
1452 struct ldb_result *dom_res;
1453 TALLOC_CTX *tmp_ctx;
1454 bool is_pdc;
1455 struct ldb_dn *pdc;
1457 tmp_ctx = talloc_new(ldb);
1458 if (tmp_ctx == NULL) {
1459 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1460 return false;
1463 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1464 if (ret) {
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)));
1468 goto failed;
1470 if (dom_res->count != 1) {
1471 goto failed;
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) {
1477 is_pdc = true;
1478 } else {
1479 is_pdc = false;
1482 talloc_free(tmp_ctx);
1484 return is_pdc;
1486 failed:
1487 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1488 talloc_free(tmp_ctx);
1489 return false;
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 };
1498 int ret, options;
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"));
1505 return false;
1508 /* Query cn=ntds settings,.... */
1509 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1510 if (ret) {
1511 talloc_free(tmp_ctx);
1512 return false;
1514 if (res->count != 1) {
1515 talloc_free(tmp_ctx);
1516 return false;
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) {
1524 return true;
1526 return false;
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;
1536 int ret = 0;
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) {
1547 break;
1549 } else {
1550 break;
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);
1560 return ret;
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);
1572 return ret;
1577 * Performs checks on a user password (plaintext UNIX format - attribute
1578 * "password"). The remaining parameters have to be extracted from the domain
1579 * object in the AD.
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,
1618 bool user_change,
1619 enum samPwdChangeReason *reject_reason,
1620 struct samr_DomInfo1 **_dominfo)
1622 const char * const user_attrs[] = { "userAccountControl",
1623 "lmPwdHistory",
1624 "ntPwdHistory",
1625 "dBCSPwd", "unicodePwd",
1626 "objectSid",
1627 "pwdLastSet", NULL };
1628 const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1629 "pwdHistoryLength",
1630 "maxPwdAge", "minPwdAge", NULL };
1631 NTTIME pwdLastSet;
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;
1641 bool restrictions;
1642 int count;
1643 time_t now = time(NULL);
1644 NTTIME now_nt;
1645 int i;
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);
1652 if (count != 1) {
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
1670 * if possible */
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,
1678 domain_attrs);
1679 if (count != 1) {
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;
1685 } else {
1686 /* work out the domain sid, and pull the domain from there */
1687 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1688 "objectSid");
1689 if (domain_sid == NULL) {
1690 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1693 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1694 "(objectSid=%s)",
1695 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1696 if (count != 1) {
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 */
1712 minPwdLength = 0;
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)) {
1731 char *new_pass;
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")),
1752 CH_UTF16, CH_UNIX,
1753 new_password->data, new_password->length,
1754 (void **)&new_pass, NULL, false)) {
1756 /* checks the password complexity */
1757 if ((restrictions != 0)
1758 && ((pwdProperties
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,
1819 pwdHistoryLength);
1820 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1821 pwdHistoryLength);
1823 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1824 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
1825 16) == 0) {
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,
1834 16) == 0) {
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
1849 * hashes */
1850 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1851 } else {
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"));
1856 if (lmNewHash) {
1857 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1858 } else {
1859 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1862 if (ntNewHash) {
1863 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1864 } else {
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
1883 * than a user DN.
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,
1897 bool user_change,
1898 enum samPwdChangeReason *reject_reason,
1899 struct samr_DomInfo1 **_dominfo)
1901 NTSTATUS nt_status;
1902 struct ldb_dn *user_dn;
1903 struct ldb_message *msg;
1904 int ret;
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));
1915 if (!user_dn) {
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);
1923 if (msg == NULL) {
1924 ldb_transaction_cancel(ldb);
1925 return NT_STATUS_NO_MEMORY;
1928 msg->dn = ldb_dn_copy(msg, user_dn);
1929 if (!msg->dn) {
1930 ldb_transaction_cancel(ldb);
1931 return NT_STATUS_NO_MEMORY;
1934 nt_status = samdb_set_password(ldb, mem_ctx,
1935 user_dn, NULL,
1936 msg, new_password,
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);
1942 return nt_status;
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;
1968 const char *sidstr;
1969 int ret;
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);
1978 if (msg == NULL) {
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,
2003 "objectClass",
2004 "foreignSecurityPrincipal");
2006 /* create the alias */
2007 ret = ldb_add(sam_ctx, msg);
2008 if (ret != 0) {
2009 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2010 "record %s: %s\n",
2011 ldb_dn_get_linearized(msg->dn),
2012 ldb_errstring(sam_ctx)));
2013 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2015 *ret_dn = msg->dn;
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)
2026 int i;
2027 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2028 const char *binary_encoded;
2029 const char **split_realm;
2030 struct ldb_dn *dn;
2032 if (!tmp_ctx) {
2033 return NULL;
2036 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2037 if (!split_realm) {
2038 talloc_free(tmp_ctx);
2039 return NULL;
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);
2048 return NULL;
2051 if (!ldb_dn_validate(dn)) {
2052 DEBUG(2, ("Failed to validated DN %s\n",
2053 ldb_dn_get_linearized(dn)));
2054 return NULL;
2056 return 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[] = {
2066 "ncName", NULL
2068 const char * const domain_ref2_attrs[] = {
2069 NULL
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,
2075 &res_domain_ref,
2076 samdb_partitions_dn(ldb, mem_ctx),
2077 LDB_SCOPE_ONELEVEL,
2078 domain_ref_attrs,
2079 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2080 escaped_domain);
2081 if (ret_domain != 0) {
2082 return NULL;
2085 if (res_domain_ref->count == 0) {
2086 ret_domain = ldb_search(ldb, mem_ctx,
2087 &res_domain_ref,
2088 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2089 LDB_SCOPE_BASE,
2090 domain_ref2_attrs,
2091 "(objectclass=domain)");
2092 if (ret_domain != 0) {
2093 return NULL;
2096 if (res_domain_ref->count == 1) {
2097 return res_domain_ref->msgs[0]->dn;
2099 return NULL;
2102 if (res_domain_ref->count > 1) {
2103 DEBUG(0,("Found %d records matching domain [%s]\n",
2104 ret_domain, domain_name));
2105 return NULL;
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)
2120 int ret;
2121 struct ldb_result *res;
2122 const char *attrs[] = { NULL };
2123 struct ldb_request *search_req;
2124 char *expression;
2125 struct ldb_search_options_control *options;
2127 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2128 if (!expression) {
2129 DEBUG(0, (__location__ ": out of memory\n"));
2130 return LDB_ERR_OPERATIONS_ERROR;
2133 res = talloc_zero(mem_ctx, struct ldb_result);
2134 if (!res) {
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),
2141 LDB_SCOPE_SUBTREE,
2142 expression, attrs,
2143 NULL,
2144 res, ldb_search_default_callback,
2145 NULL);
2146 if (ret != LDB_SUCCESS) {
2147 return ret;
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) {
2161 return ret;
2164 ret = ldb_request_add_control(search_req,
2165 LDB_CONTROL_SEARCH_OPTIONS_OID,
2166 true, options);
2167 if (ret != LDB_SUCCESS) {
2168 return ret;
2171 ret = ldb_request(ldb, search_req);
2172 if (ret != LDB_SUCCESS) {
2173 return ret;
2176 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2177 if (ret != LDB_SUCCESS) {
2178 return ret;
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;
2190 return LDB_SUCCESS;
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)
2202 int ret;
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);
2210 if (!res) {
2211 return LDB_ERR_OPERATIONS_ERROR;
2214 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2215 basedn,
2216 LDB_SCOPE_BASE,
2217 NULL,
2218 attrs,
2219 NULL,
2220 res,
2221 ldb_search_default_callback,
2222 NULL);
2223 if (ret != LDB_SUCCESS) {
2224 talloc_free(tmp_ctx);
2225 return ret;
2228 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2229 if (ret != LDB_SUCCESS) {
2230 return ret;
2233 ret = ldb_request(ldb, req);
2234 if (ret == LDB_SUCCESS) {
2235 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2238 talloc_free(req);
2239 *_res = talloc_steal(mem_ctx, res);
2240 return ret;
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)
2250 int ret;
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);
2258 return ret;
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);
2266 return LDB_SUCCESS;
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)
2275 int ret;
2276 struct ldb_result *res;
2277 const char *attrs[] = { "objectSID", NULL };
2278 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2279 struct dom_sid *s;
2281 ZERO_STRUCTP(sid);
2283 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2284 if (ret != LDB_SUCCESS) {
2285 talloc_free(tmp_ctx);
2286 return ret;
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");
2293 if (s == NULL) {
2294 talloc_free(tmp_ctx);
2295 return LDB_ERR_NO_SUCH_OBJECT;
2297 *sid = *s;
2298 talloc_free(tmp_ctx);
2299 return LDB_SUCCESS;
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);
2314 int i;
2315 struct ldb_message_element *el;
2317 *r = NULL;
2318 *count = 0;
2320 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2321 res->count < 1) {
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);
2328 if (el == NULL) {
2329 /* it's OK to be empty */
2330 talloc_free(tmp_ctx);
2331 return WERR_OK;
2334 *count = el->num_values;
2335 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2336 if (*r == NULL) {
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")),
2345 &(*r)[i],
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);
2355 return WERR_OK;
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;
2368 int i;
2370 msg = ldb_msg_new(tmp_ctx);
2371 msg->dn = dn;
2372 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2373 goto failed;
2376 el->values = talloc_array(msg, struct ldb_val, count);
2377 if (!el->values) {
2378 goto failed;
2381 for (i=0; i<count; i++) {
2382 struct ldb_val v;
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")),
2386 &r[i],
2387 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2389 goto failed;
2392 el->num_values++;
2393 el->values[i] = v;
2396 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2397 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2398 goto failed;
2401 talloc_free(tmp_ctx);
2403 return WERR_OK;
2405 failed:
2406 talloc_free(tmp_ctx);
2407 return WERR_DS_DRA_INTERNAL_ERROR;
2412 load the uSNHighest attribute from the @REPLCHANGED object for a
2413 partition
2415 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2417 struct ldb_request *req;
2418 int ret;
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);
2424 if (!res) {
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"),
2431 LDB_SCOPE_BASE,
2432 NULL, NULL,
2433 NULL,
2434 res, ldb_search_default_callback,
2435 NULL);
2436 if (ret != LDB_SUCCESS) {
2437 talloc_free(tmp_ctx);
2438 return ret;
2441 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2442 if (p_ctrl == NULL) {
2443 talloc_free(res);
2444 return LDB_ERR_OPERATIONS_ERROR;
2446 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2447 p_ctrl->dn = dn;
2450 ret = ldb_request_add_control(req,
2451 DSDB_CONTROL_CURRENT_PARTITION_OID,
2452 false, p_ctrl);
2453 if (ret != LDB_SUCCESS) {
2454 talloc_free(tmp_ctx);
2455 return ret;
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 */
2468 *uSN = 0;
2469 talloc_free(tmp_ctx);
2470 return LDB_SUCCESS;
2473 if (ret != LDB_SUCCESS) {
2474 talloc_free(tmp_ctx);
2475 return ret;
2478 if (res->count < 1) {
2479 *uSN = 0;
2480 } else {
2481 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2484 talloc_free(tmp_ctx);
2486 return LDB_SUCCESS;
2490 save the uSNHighest attribute in the @REPLCHANGED object for a
2491 partition
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;
2498 int ret;
2500 msg = ldb_msg_new(ldb);
2501 if (msg == NULL) {
2502 return LDB_ERR_OPERATIONS_ERROR;
2505 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2506 if (msg->dn == NULL) {
2507 talloc_free(msg);
2508 return LDB_ERR_OPERATIONS_ERROR;
2511 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2512 if (ret != LDB_SUCCESS) {
2513 talloc_free(msg);
2514 return ret;
2516 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2519 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2520 if (p_ctrl == NULL) {
2521 talloc_free(msg);
2522 return LDB_ERR_OPERATIONS_ERROR;
2524 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2525 p_ctrl->dn = dn;
2527 ret = ldb_build_mod_req(&req, ldb, msg,
2528 msg,
2529 NULL,
2530 NULL, ldb_op_default_callback,
2531 NULL);
2532 again:
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(msg);
2535 return ret;
2538 ret = ldb_request_add_control(req,
2539 DSDB_CONTROL_CURRENT_PARTITION_OID,
2540 false, p_ctrl);
2541 if (ret != LDB_SUCCESS) {
2542 talloc_free(msg);
2543 return ret;
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,
2554 msg,
2555 NULL,
2556 NULL, ldb_op_default_callback,
2557 NULL);
2558 goto again;
2561 talloc_free(msg);
2563 return ret;
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
2576 a cache)
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 };
2593 int ret;
2594 struct ldb_result *res;
2596 tmp_ctx = talloc_new(ldb);
2597 if (tmp_ctx == NULL) {
2598 goto failed;
2601 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2602 if (ret) {
2603 goto failed;
2606 if (res->count != 1) {
2607 goto failed;
2610 *options = samdb_result_uint(res->msgs[0], "options", 0);
2612 talloc_free(tmp_ctx);
2614 return LDB_SUCCESS;
2616 failed:
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;