s4-dsdb: added dsdb_find_sid_by_dn()
[Samba.git] / source4 / dsdb / common / util.c
blob9a49417d91f8e3a002e9e1aa18529b2487a17fea
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;
1436 * This works out if we are running on a supported forest/domain function
1437 * level. Basically this means that we don't support mixed/interim (NT 4 DC
1438 * support) levels.
1439 * If errmsg isn't NULL we write in an adequate error message for printing out
1440 * to the screen.
1442 bool samdb_is_capable_dc(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1443 char **errmsg)
1445 int32_t level_forest, level_domain, level_domain_mixed;
1446 bool ret = true;
1448 level_forest = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1449 samdb_partitions_dn(ldb, mem_ctx), "msDS-Behavior-Version",
1450 NULL);
1451 level_domain = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1452 samdb_base_dn(ldb), "msDS-Behavior-Version", NULL);
1453 level_domain_mixed = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1454 samdb_base_dn(ldb), "nTMixedDomain", NULL);
1456 if (errmsg != NULL)
1457 *errmsg = talloc_strdup(mem_ctx, "");
1459 if (level_forest == -1 || level_domain == -1 || level_domain_mixed == -1) {
1460 ret = false;
1461 if (errmsg != NULL)
1462 *errmsg = talloc_strdup_append(*errmsg,
1463 "\nATTENTION: Invalid values for forest and/or domain function level!"
1467 if (level_forest == DS_DOMAIN_FUNCTION_2003_MIXED) {
1468 ret = false;
1469 if (errmsg != NULL)
1470 *errmsg = talloc_strdup_append(*errmsg,
1471 "\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported!"
1474 if ((level_domain == DS_DOMAIN_FUNCTION_2000 && level_domain_mixed != 0)
1475 || level_domain == DS_DOMAIN_FUNCTION_2003_MIXED) {
1476 ret = false;
1477 if (errmsg != NULL)
1478 *errmsg = talloc_strdup_append(*errmsg,
1479 "\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported!"
1483 if ((!ret) && (errmsg != NULL)) {
1484 *errmsg = talloc_strdup_append(*errmsg,
1485 "\nPlease raise the domain and/or forest level to an adequate value. Use for this the 'domainlevel' tool, the MS AD MMC tools or manipulate the needed attributes directly."
1489 return ret;
1493 work out if we are the PDC for the domain of the current open ldb
1495 bool samdb_is_pdc(struct ldb_context *ldb)
1497 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1498 int ret;
1499 struct ldb_result *dom_res;
1500 TALLOC_CTX *tmp_ctx;
1501 bool is_pdc;
1502 struct ldb_dn *pdc;
1504 tmp_ctx = talloc_new(ldb);
1505 if (tmp_ctx == NULL) {
1506 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1507 return false;
1510 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1511 if (ret) {
1512 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1513 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1514 ldb_errstring(ldb)));
1515 goto failed;
1517 if (dom_res->count != 1) {
1518 goto failed;
1521 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1523 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1524 is_pdc = true;
1525 } else {
1526 is_pdc = false;
1529 talloc_free(tmp_ctx);
1531 return is_pdc;
1533 failed:
1534 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1535 talloc_free(tmp_ctx);
1536 return false;
1540 work out if we are a Global Catalog server for the domain of the current open ldb
1542 bool samdb_is_gc(struct ldb_context *ldb)
1544 const char *attrs[] = { "options", NULL };
1545 int ret, options;
1546 struct ldb_result *res;
1547 TALLOC_CTX *tmp_ctx;
1549 tmp_ctx = talloc_new(ldb);
1550 if (tmp_ctx == NULL) {
1551 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1552 return false;
1555 /* Query cn=ntds settings,.... */
1556 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1557 if (ret) {
1558 talloc_free(tmp_ctx);
1559 return false;
1561 if (res->count != 1) {
1562 talloc_free(tmp_ctx);
1563 return false;
1566 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1567 talloc_free(tmp_ctx);
1569 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1570 if (options & 0x000000001) {
1571 return true;
1573 return false;
1576 /* Find a domain object in the parents of a particular DN. */
1577 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1578 struct ldb_dn **parent_dn, const char **errstring)
1580 TALLOC_CTX *local_ctx;
1581 struct ldb_dn *sdn = dn;
1582 struct ldb_result *res = NULL;
1583 int ret = 0;
1584 const char *attrs[] = { NULL };
1586 local_ctx = talloc_new(mem_ctx);
1587 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1589 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1590 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1591 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1592 if (ret == LDB_SUCCESS) {
1593 if (res->count == 1) {
1594 break;
1596 } else {
1597 break;
1601 if (ret != LDB_SUCCESS) {
1602 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1603 ldb_dn_get_linearized(dn),
1604 ldb_dn_get_linearized(sdn),
1605 ldb_errstring(ldb));
1606 talloc_free(local_ctx);
1607 return ret;
1609 if (res->count != 1) {
1610 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1611 ldb_dn_get_linearized(dn));
1612 DEBUG(0,(__location__ ": %s\n", *errstring));
1613 talloc_free(local_ctx);
1614 return LDB_ERR_CONSTRAINT_VIOLATION;
1617 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1618 talloc_free(local_ctx);
1619 return ret;
1624 set the user password using plaintext, obeying any user or domain
1625 password restrictions
1627 note that this function doesn't actually store the result in the
1628 database, it just fills in the "mod" structure with ldb modify
1629 elements to setup the correct change when samdb_replace() is
1630 called. This allows the caller to combine the change with other
1631 changes (as is needed by some of the set user info levels)
1633 The caller should probably have a transaction wrapping this
1635 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1636 struct ldb_dn *user_dn,
1637 struct ldb_dn *domain_dn,
1638 struct ldb_message *mod,
1639 const DATA_BLOB *new_password,
1640 struct samr_Password *param_lmNewHash,
1641 struct samr_Password *param_ntNewHash,
1642 bool user_change,
1643 enum samr_RejectReason *reject_reason,
1644 struct samr_DomInfo1 **_dominfo)
1646 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1647 "ntPwdHistory",
1648 "dBCSPwd", "unicodePwd",
1649 "objectSid",
1650 "pwdLastSet", NULL };
1651 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1652 "maxPwdAge", "minPwdAge",
1653 "minPwdLength", NULL };
1654 NTTIME pwdLastSet;
1655 int64_t minPwdAge;
1656 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1657 uint_t userAccountControl;
1658 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1659 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1660 struct samr_Password local_lmNewHash, local_ntNewHash;
1661 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1662 struct dom_sid *domain_sid;
1663 struct ldb_message **res;
1664 bool restrictions;
1665 int count;
1666 time_t now = time(NULL);
1667 NTTIME now_nt;
1668 int i;
1670 /* we need to know the time to compute password age */
1671 unix_to_nt_time(&now_nt, now);
1673 /* pull all the user parameters */
1674 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1675 if (count != 1) {
1676 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1678 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1679 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1680 "lmPwdHistory", &sambaLMPwdHistory);
1681 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1682 "ntPwdHistory", &sambaNTPwdHistory);
1683 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1684 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1685 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1687 /* Copy parameters */
1688 lmNewHash = param_lmNewHash;
1689 ntNewHash = param_ntNewHash;
1691 /* Only non-trust accounts have restrictions (possibly this
1692 * test is the wrong way around, but I like to be restrictive
1693 * if possible */
1694 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1695 |UF_WORKSTATION_TRUST_ACCOUNT
1696 |UF_SERVER_TRUST_ACCOUNT));
1698 if (domain_dn) {
1699 /* pull the domain parameters */
1700 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1701 if (count != 1) {
1702 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1703 ldb_dn_get_linearized(domain_dn),
1704 ldb_dn_get_linearized(user_dn)));
1705 return NT_STATUS_NO_SUCH_DOMAIN;
1707 } else {
1708 /* work out the domain sid, and pull the domain from there */
1709 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1710 if (domain_sid == NULL) {
1711 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1714 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1715 "(objectSid=%s)",
1716 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1717 if (count != 1) {
1718 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1719 dom_sid_string(mem_ctx, domain_sid),
1720 ldb_dn_get_linearized(user_dn)));
1721 return NT_STATUS_NO_SUCH_DOMAIN;
1725 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1726 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1727 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1728 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1730 if (userAccountControl & UF_PASSWD_NOTREQD) {
1731 /* see [MS-ADTS] 2.2.15 */
1732 minPwdLength = 0;
1735 if (_dominfo) {
1736 struct samr_DomInfo1 *dominfo;
1737 /* on failure we need to fill in the reject reasons */
1738 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1739 if (dominfo == NULL) {
1740 return NT_STATUS_NO_MEMORY;
1742 dominfo->min_password_length = minPwdLength;
1743 dominfo->password_properties = pwdProperties;
1744 dominfo->password_history_length = pwdHistoryLength;
1745 dominfo->max_password_age = minPwdAge;
1746 dominfo->min_password_age = minPwdAge;
1747 *_dominfo = dominfo;
1750 if (restrictions && new_password) {
1751 char *new_pass;
1753 /* check the various password restrictions */
1754 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1755 if (reject_reason) {
1756 *reject_reason = SAMR_REJECT_TOO_SHORT;
1758 return NT_STATUS_PASSWORD_RESTRICTION;
1761 /* Create the NT hash */
1762 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1764 ntNewHash = &local_ntNewHash;
1766 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1767 if (convert_string_talloc_convenience(mem_ctx,
1768 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1769 CH_UTF16, CH_UNIX,
1770 new_password->data, new_password->length,
1771 (void **)&new_pass, NULL, false)) {
1773 /* possibly check password complexity */
1774 if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
1775 !check_password_quality(new_pass)) {
1776 if (reject_reason) {
1777 *reject_reason = SAMR_REJECT_COMPLEXITY;
1779 return NT_STATUS_PASSWORD_RESTRICTION;
1782 /* compute the new lm hashes (for checking history - case insenitivly!) */
1783 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1784 lmNewHash = &local_lmNewHash;
1789 if (restrictions && user_change) {
1790 /* are all password changes disallowed? */
1791 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1792 if (reject_reason) {
1793 *reject_reason = SAMR_REJECT_OTHER;
1795 return NT_STATUS_PASSWORD_RESTRICTION;
1798 /* can this user change password? */
1799 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1800 if (reject_reason) {
1801 *reject_reason = SAMR_REJECT_OTHER;
1803 return NT_STATUS_PASSWORD_RESTRICTION;
1806 /* yes, this is a minus. The ages are in negative 100nsec units! */
1807 if (pwdLastSet - minPwdAge > now_nt) {
1808 if (reject_reason) {
1809 *reject_reason = SAMR_REJECT_OTHER;
1811 return NT_STATUS_PASSWORD_RESTRICTION;
1814 /* check the immediately past password */
1815 if (pwdHistoryLength > 0) {
1816 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1817 if (reject_reason) {
1818 *reject_reason = SAMR_REJECT_IN_HISTORY;
1820 return NT_STATUS_PASSWORD_RESTRICTION;
1822 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1823 if (reject_reason) {
1824 *reject_reason = SAMR_REJECT_IN_HISTORY;
1826 return NT_STATUS_PASSWORD_RESTRICTION;
1830 /* check the password history */
1831 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1832 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1834 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1835 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1836 if (reject_reason) {
1837 *reject_reason = SAMR_REJECT_IN_HISTORY;
1839 return NT_STATUS_PASSWORD_RESTRICTION;
1842 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1843 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1844 if (reject_reason) {
1845 *reject_reason = SAMR_REJECT_IN_HISTORY;
1847 return NT_STATUS_PASSWORD_RESTRICTION;
1852 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1854 /* the password is acceptable. Start forming the new fields */
1855 if (new_password) {
1856 /* if we know the cleartext UTF16 password, then set it.
1857 * Modules in ldb will set all the appropriate
1858 * hashes */
1859 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1860 } else {
1861 /* We don't have the cleartext, so delete the old one
1862 * and set what we have of the hashes */
1863 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1865 if (lmNewHash) {
1866 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1867 } else {
1868 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1871 if (ntNewHash) {
1872 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1873 } else {
1874 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1878 return NT_STATUS_OK;
1883 set the user password using plaintext, obeying any user or domain
1884 password restrictions
1886 This wrapper function takes a SID as input, rather than a user DN,
1887 and actually performs the password change
1890 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1891 const struct dom_sid *user_sid,
1892 const DATA_BLOB *new_pass,
1893 struct samr_Password *lmNewHash,
1894 struct samr_Password *ntNewHash,
1895 bool user_change,
1896 enum samr_RejectReason *reject_reason,
1897 struct samr_DomInfo1 **_dominfo)
1899 NTSTATUS nt_status;
1900 struct ldb_dn *user_dn;
1901 struct ldb_message *msg;
1902 int ret;
1904 ret = ldb_transaction_start(ctx);
1905 if (ret) {
1906 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1907 return NT_STATUS_TRANSACTION_ABORTED;
1910 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1911 "(&(objectSid=%s)(objectClass=user))",
1912 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1913 if (!user_dn) {
1914 ldb_transaction_cancel(ctx);
1915 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1916 dom_sid_string(mem_ctx, user_sid)));
1917 return NT_STATUS_NO_SUCH_USER;
1920 msg = ldb_msg_new(mem_ctx);
1921 if (msg == NULL) {
1922 ldb_transaction_cancel(ctx);
1923 return NT_STATUS_NO_MEMORY;
1926 msg->dn = ldb_dn_copy(msg, user_dn);
1927 if (!msg->dn) {
1928 ldb_transaction_cancel(ctx);
1929 return NT_STATUS_NO_MEMORY;
1932 nt_status = samdb_set_password(ctx, mem_ctx,
1933 user_dn, NULL,
1934 msg, new_pass,
1935 lmNewHash, ntNewHash,
1936 user_change, /* This is a password set, not change */
1937 reject_reason, _dominfo);
1938 if (!NT_STATUS_IS_OK(nt_status)) {
1939 ldb_transaction_cancel(ctx);
1940 return nt_status;
1943 /* modify the samdb record */
1944 ret = samdb_replace(ctx, mem_ctx, msg);
1945 if (ret != 0) {
1946 ldb_transaction_cancel(ctx);
1947 return NT_STATUS_ACCESS_DENIED;
1950 ret = ldb_transaction_commit(ctx);
1951 if (ret != 0) {
1952 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1953 ldb_dn_get_linearized(msg->dn),
1954 ldb_errstring(ctx)));
1955 return NT_STATUS_TRANSACTION_ABORTED;
1957 return NT_STATUS_OK;
1962 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1963 struct dom_sid *sid, struct ldb_dn **ret_dn)
1965 struct ldb_message *msg;
1966 struct ldb_dn *basedn;
1967 const char *sidstr;
1968 int ret;
1970 sidstr = dom_sid_string(mem_ctx, sid);
1971 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1973 /* We might have to create a ForeignSecurityPrincipal, even if this user
1974 * is in our own domain */
1976 msg = ldb_msg_new(mem_ctx);
1977 if (msg == NULL) {
1978 return NT_STATUS_NO_MEMORY;
1981 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1982 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1983 * not work, this is wrong for the Builtin domain, there's no
1984 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1987 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1988 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1990 if (basedn == NULL) {
1991 DEBUG(0, ("Failed to find DN for "
1992 "ForeignSecurityPrincipal container\n"));
1993 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1996 /* add core elements to the ldb_message for the alias */
1997 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1998 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1999 return NT_STATUS_NO_MEMORY;
2001 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
2002 "objectClass",
2003 "foreignSecurityPrincipal");
2005 /* create the alias */
2006 ret = ldb_add(sam_ctx, msg);
2007 if (ret != 0) {
2008 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2009 "record %s: %s\n",
2010 ldb_dn_get_linearized(msg->dn),
2011 ldb_errstring(sam_ctx)));
2012 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2014 *ret_dn = msg->dn;
2015 return NT_STATUS_OK;
2020 Find the DN of a domain, assuming it to be a dotted.dns name
2023 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2025 int i;
2026 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2027 const char *binary_encoded;
2028 const char **split_realm;
2029 struct ldb_dn *dn;
2031 if (!tmp_ctx) {
2032 return NULL;
2035 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2036 if (!split_realm) {
2037 talloc_free(tmp_ctx);
2038 return NULL;
2040 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2041 for (i=0; split_realm[i]; i++) {
2042 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2043 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2044 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2045 binary_encoded, ldb_dn_get_linearized(dn)));
2046 talloc_free(tmp_ctx);
2047 return NULL;
2050 if (!ldb_dn_validate(dn)) {
2051 DEBUG(2, ("Failed to validated DN %s\n",
2052 ldb_dn_get_linearized(dn)));
2053 return NULL;
2055 return dn;
2058 Find the DN of a domain, be it the netbios or DNS name
2061 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2062 const char *domain_name)
2064 const char * const domain_ref_attrs[] = {
2065 "ncName", NULL
2067 const char * const domain_ref2_attrs[] = {
2068 NULL
2070 struct ldb_result *res_domain_ref;
2071 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2072 /* find the domain's DN */
2073 int ret_domain = ldb_search(ldb, mem_ctx,
2074 &res_domain_ref,
2075 samdb_partitions_dn(ldb, mem_ctx),
2076 LDB_SCOPE_ONELEVEL,
2077 domain_ref_attrs,
2078 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2079 escaped_domain);
2080 if (ret_domain != 0) {
2081 return NULL;
2084 if (res_domain_ref->count == 0) {
2085 ret_domain = ldb_search(ldb, mem_ctx,
2086 &res_domain_ref,
2087 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2088 LDB_SCOPE_BASE,
2089 domain_ref2_attrs,
2090 "(objectclass=domain)");
2091 if (ret_domain != 0) {
2092 return NULL;
2095 if (res_domain_ref->count == 1) {
2096 return res_domain_ref->msgs[0]->dn;
2098 return NULL;
2101 if (res_domain_ref->count > 1) {
2102 DEBUG(0,("Found %d records matching domain [%s]\n",
2103 ret_domain, domain_name));
2104 return NULL;
2107 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2113 use a GUID to find a DN
2115 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2116 TALLOC_CTX *mem_ctx,
2117 const char *guid_str, struct ldb_dn **dn)
2119 int ret;
2120 struct ldb_result *res;
2121 const char *attrs[] = { NULL };
2122 struct ldb_request *search_req;
2123 char *expression;
2124 struct ldb_search_options_control *options;
2126 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2127 if (!expression) {
2128 DEBUG(0, (__location__ ": out of memory\n"));
2129 return LDB_ERR_OPERATIONS_ERROR;
2132 res = talloc_zero(mem_ctx, struct ldb_result);
2133 if (!res) {
2134 DEBUG(0, (__location__ ": out of memory\n"));
2135 return LDB_ERR_OPERATIONS_ERROR;
2138 ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2139 ldb_get_default_basedn(ldb),
2140 LDB_SCOPE_SUBTREE,
2141 expression, attrs,
2142 NULL,
2143 res, ldb_search_default_callback,
2144 NULL);
2145 if (ret != LDB_SUCCESS) {
2146 return ret;
2149 /* we need to cope with cross-partition links, so search for
2150 the GUID over all partitions */
2151 options = talloc(search_req, struct ldb_search_options_control);
2152 if (options == NULL) {
2153 DEBUG(0, (__location__ ": out of memory\n"));
2154 return LDB_ERR_OPERATIONS_ERROR;
2156 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2158 ret = ldb_request_add_control(search_req,
2159 LDB_CONTROL_SEARCH_OPTIONS_OID,
2160 true, options);
2161 if (ret != LDB_SUCCESS) {
2162 return ret;
2165 ret = ldb_request(ldb, search_req);
2166 if (ret != LDB_SUCCESS) {
2167 return ret;
2170 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2171 if (ret != LDB_SUCCESS) {
2172 return ret;
2175 /* this really should be exactly 1, but there is a bug in the
2176 partitions module that can return two here with the
2177 search_options control set */
2178 if (res->count < 1) {
2179 return LDB_ERR_NO_SUCH_OBJECT;
2182 *dn = res->msgs[0]->dn;
2184 return LDB_SUCCESS;
2189 use a DN to find a GUID
2191 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2192 struct ldb_dn *dn, struct GUID *guid)
2194 int ret;
2195 struct ldb_result *res;
2196 const char *attrs[] = { "objectGUID", NULL };
2197 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2199 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
2200 if (ret != LDB_SUCCESS) {
2201 talloc_free(tmp_ctx);
2202 return ret;
2204 *guid = samdb_result_guid(res->msgs[0], "objectGUID");
2205 talloc_free(tmp_ctx);
2206 return LDB_SUCCESS;
2210 use a DN to find a SID
2212 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2213 struct ldb_dn *dn, struct dom_sid *sid)
2215 int ret;
2216 struct ldb_result *res;
2217 const char *attrs[] = { "objectSID", NULL };
2218 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2219 struct dom_sid *s;
2221 ZERO_STRUCTP(sid);
2223 ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
2224 if (ret != LDB_SUCCESS) {
2225 talloc_free(tmp_ctx);
2226 return ret;
2228 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2229 if (s == NULL) {
2230 talloc_free(tmp_ctx);
2231 return LDB_ERR_NO_SUCH_OBJECT;
2233 *sid = *s;
2234 talloc_free(tmp_ctx);
2235 return LDB_SUCCESS;
2241 load a repsFromTo blob list for a given partition GUID
2242 attr must be "repsFrom" or "repsTo"
2244 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2245 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2247 const char *attrs[] = { attr, NULL };
2248 struct ldb_result *res = NULL;
2249 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2250 int i;
2251 struct ldb_message_element *el;
2253 *r = NULL;
2254 *count = 0;
2256 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2257 res->count < 1) {
2258 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2259 talloc_free(tmp_ctx);
2260 return WERR_DS_DRA_INTERNAL_ERROR;
2263 el = ldb_msg_find_element(res->msgs[0], attr);
2264 if (el == NULL) {
2265 /* it's OK to be empty */
2266 talloc_free(tmp_ctx);
2267 return WERR_OK;
2270 *count = el->num_values;
2271 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2272 if (*r == NULL) {
2273 talloc_free(tmp_ctx);
2274 return WERR_DS_DRA_INTERNAL_ERROR;
2277 for (i=0; i<(*count); i++) {
2278 enum ndr_err_code ndr_err;
2279 ndr_err = ndr_pull_struct_blob(&el->values[i],
2280 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2281 &(*r)[i],
2282 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2284 talloc_free(tmp_ctx);
2285 return WERR_DS_DRA_INTERNAL_ERROR;
2289 talloc_free(tmp_ctx);
2291 return WERR_OK;
2295 save the repsFromTo blob list for a given partition GUID
2296 attr must be "repsFrom" or "repsTo"
2298 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2299 const char *attr, struct repsFromToBlob *r, uint32_t count)
2301 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2302 struct ldb_message *msg;
2303 struct ldb_message_element *el;
2304 int i;
2306 msg = ldb_msg_new(tmp_ctx);
2307 msg->dn = dn;
2308 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2309 goto failed;
2312 el->values = talloc_array(msg, struct ldb_val, count);
2313 if (!el->values) {
2314 goto failed;
2317 for (i=0; i<count; i++) {
2318 struct ldb_val v;
2319 enum ndr_err_code ndr_err;
2321 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2322 &r[i],
2323 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2324 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2325 goto failed;
2328 el->num_values++;
2329 el->values[i] = v;
2332 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2333 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2334 goto failed;
2337 talloc_free(tmp_ctx);
2339 return WERR_OK;
2341 failed:
2342 talloc_free(tmp_ctx);
2343 return WERR_DS_DRA_INTERNAL_ERROR;
2348 load the uSNHighest attribute from the @REPLCHANGED object for a
2349 partition
2351 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2353 struct ldb_request *req;
2354 int ret;
2355 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2356 struct dsdb_control_current_partition *p_ctrl;
2357 struct ldb_result *res;
2359 res = talloc_zero(tmp_ctx, struct ldb_result);
2360 if (!res) {
2361 talloc_free(tmp_ctx);
2362 return LDB_ERR_OPERATIONS_ERROR;
2365 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2366 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2367 LDB_SCOPE_BASE,
2368 NULL, NULL,
2369 NULL,
2370 res, ldb_search_default_callback,
2371 NULL);
2372 if (ret != LDB_SUCCESS) {
2373 talloc_free(tmp_ctx);
2374 return ret;
2377 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2378 if (p_ctrl == NULL) {
2379 talloc_free(res);
2380 return LDB_ERR_OPERATIONS_ERROR;
2382 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2383 p_ctrl->dn = dn;
2386 ret = ldb_request_add_control(req,
2387 DSDB_CONTROL_CURRENT_PARTITION_OID,
2388 false, p_ctrl);
2389 if (ret != LDB_SUCCESS) {
2390 talloc_free(tmp_ctx);
2391 return ret;
2394 /* Run the new request */
2395 ret = ldb_request(ldb, req);
2397 if (ret == LDB_SUCCESS) {
2398 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2401 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2402 /* it hasn't been created yet, which means
2403 an implicit value of zero */
2404 *uSN = 0;
2405 talloc_free(tmp_ctx);
2406 return LDB_SUCCESS;
2409 if (ret != LDB_SUCCESS) {
2410 talloc_free(tmp_ctx);
2411 return ret;
2414 if (res->count < 1) {
2415 *uSN = 0;
2416 } else {
2417 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2420 talloc_free(tmp_ctx);
2422 return LDB_SUCCESS;
2426 save the uSNHighest attribute in the @REPLCHANGED object for a
2427 partition
2429 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2431 struct ldb_request *req;
2432 struct ldb_message *msg;
2433 struct dsdb_control_current_partition *p_ctrl;
2434 int ret;
2436 msg = ldb_msg_new(ldb);
2437 if (msg == NULL) {
2438 return LDB_ERR_OPERATIONS_ERROR;
2441 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2442 if (msg->dn == NULL) {
2443 talloc_free(msg);
2444 return LDB_ERR_OPERATIONS_ERROR;
2447 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2448 if (ret != LDB_SUCCESS) {
2449 talloc_free(msg);
2450 return ret;
2452 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2455 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2456 if (p_ctrl == NULL) {
2457 talloc_free(msg);
2458 return LDB_ERR_OPERATIONS_ERROR;
2460 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2461 p_ctrl->dn = dn;
2463 ret = ldb_build_mod_req(&req, ldb, msg,
2464 msg,
2465 NULL,
2466 NULL, ldb_op_default_callback,
2467 NULL);
2468 again:
2469 if (ret != LDB_SUCCESS) {
2470 talloc_free(msg);
2471 return ret;
2474 ret = ldb_request_add_control(req,
2475 DSDB_CONTROL_CURRENT_PARTITION_OID,
2476 false, p_ctrl);
2477 if (ret != LDB_SUCCESS) {
2478 talloc_free(msg);
2479 return ret;
2482 /* Run the new request */
2483 ret = ldb_request(ldb, req);
2485 if (ret == LDB_SUCCESS) {
2486 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2488 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2489 ret = ldb_build_add_req(&req, ldb, msg,
2490 msg,
2491 NULL,
2492 NULL, ldb_op_default_callback,
2493 NULL);
2494 goto again;
2497 talloc_free(msg);
2499 return ret;
2502 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2503 const struct drsuapi_DsReplicaCursor2 *c2)
2505 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);