s4:dsdb/common: let samdb_msg_add_uint64() call samdb_msg_add_int64()
[Samba/fernandojvsilva.git] / source4 / dsdb / common / util.c
blob3f222d27d7cf98cd35889a3c11785e135dd1be1e
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"
40 #include "system/locale.h"
43 search the sam for the specified attributes in a specific domain, filter on
44 objectSid being in domain_sid.
46 int samdb_search_domain(struct ldb_context *sam_ldb,
47 TALLOC_CTX *mem_ctx,
48 struct ldb_dn *basedn,
49 struct ldb_message ***res,
50 const char * const *attrs,
51 const struct dom_sid *domain_sid,
52 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
54 va_list ap;
55 int i, count;
57 va_start(ap, format);
58 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
59 res, attrs, format, ap);
60 va_end(ap);
62 i=0;
64 while (i<count) {
65 struct dom_sid *entry_sid;
67 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
69 if ((entry_sid == NULL) ||
70 (!dom_sid_in_domain(domain_sid, entry_sid))) {
71 /* Delete that entry from the result set */
72 (*res)[i] = (*res)[count-1];
73 count -= 1;
74 talloc_free(entry_sid);
75 continue;
77 talloc_free(entry_sid);
78 i += 1;
81 return count;
85 search the sam for a single string attribute in exactly 1 record
87 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
88 TALLOC_CTX *mem_ctx,
89 struct ldb_dn *basedn,
90 const char *attr_name,
91 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
93 int count;
94 const char *attrs[2] = { NULL, NULL };
95 struct ldb_message **res = NULL;
97 attrs[0] = attr_name;
99 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
100 if (count > 1) {
101 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
102 attr_name, format, count));
104 if (count != 1) {
105 talloc_free(res);
106 return NULL;
109 return samdb_result_string(res[0], attr_name, NULL);
113 search the sam for a single string attribute in exactly 1 record
115 const char *samdb_search_string(struct ldb_context *sam_ldb,
116 TALLOC_CTX *mem_ctx,
117 struct ldb_dn *basedn,
118 const char *attr_name,
119 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
121 va_list ap;
122 const char *str;
124 va_start(ap, format);
125 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
126 va_end(ap);
128 return str;
131 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
132 TALLOC_CTX *mem_ctx,
133 struct ldb_dn *basedn,
134 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
136 va_list ap;
137 struct ldb_dn *ret;
138 struct ldb_message **res = NULL;
139 int count;
141 va_start(ap, format);
142 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
143 va_end(ap);
145 if (count != 1) return NULL;
147 ret = talloc_steal(mem_ctx, res[0]->dn);
148 talloc_free(res);
150 return ret;
154 search the sam for a dom_sid attribute in exactly 1 record
156 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
157 TALLOC_CTX *mem_ctx,
158 struct ldb_dn *basedn,
159 const char *attr_name,
160 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
162 va_list ap;
163 int count;
164 struct ldb_message **res;
165 const char *attrs[2] = { NULL, NULL };
166 struct dom_sid *sid;
168 attrs[0] = attr_name;
170 va_start(ap, format);
171 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
172 va_end(ap);
173 if (count > 1) {
174 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
175 attr_name, format, count));
177 if (count != 1) {
178 talloc_free(res);
179 return NULL;
181 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
182 talloc_free(res);
183 return sid;
187 return the count of the number of records in the sam matching the query
189 int samdb_search_count(struct ldb_context *sam_ldb,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
193 va_list ap;
194 struct ldb_message **res;
195 const char *attrs[] = { NULL };
196 int ret;
197 TALLOC_CTX *tmp_ctx = talloc_new(sam_ldb);
199 va_start(ap, format);
200 ret = gendb_search_v(sam_ldb, tmp_ctx, basedn, &res, attrs, format, ap);
201 va_end(ap);
202 talloc_free(tmp_ctx);
204 return ret;
209 search the sam for a single integer attribute in exactly 1 record
211 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
212 TALLOC_CTX *mem_ctx,
213 uint_t default_value,
214 struct ldb_dn *basedn,
215 const char *attr_name,
216 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
218 va_list ap;
219 int count;
220 struct ldb_message **res;
221 const char *attrs[2] = { NULL, NULL };
223 attrs[0] = attr_name;
225 va_start(ap, format);
226 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
227 va_end(ap);
229 if (count != 1) {
230 return default_value;
233 return samdb_result_uint(res[0], attr_name, default_value);
237 search the sam for a single signed 64 bit integer attribute in exactly 1 record
239 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
240 TALLOC_CTX *mem_ctx,
241 int64_t default_value,
242 struct ldb_dn *basedn,
243 const char *attr_name,
244 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
246 va_list ap;
247 int count;
248 struct ldb_message **res;
249 const char *attrs[2] = { NULL, NULL };
251 attrs[0] = attr_name;
253 va_start(ap, format);
254 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
255 va_end(ap);
257 if (count != 1) {
258 return default_value;
261 return samdb_result_int64(res[0], attr_name, default_value);
265 search the sam for multipe records each giving a single string attribute
266 return the number of matches, or -1 on error
268 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
269 TALLOC_CTX *mem_ctx,
270 struct ldb_dn *basedn,
271 const char ***strs,
272 const char *attr_name,
273 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
275 va_list ap;
276 int count, i;
277 const char *attrs[2] = { NULL, NULL };
278 struct ldb_message **res = NULL;
280 attrs[0] = attr_name;
282 va_start(ap, format);
283 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
284 va_end(ap);
286 if (count <= 0) {
287 return count;
290 /* make sure its single valued */
291 for (i=0;i<count;i++) {
292 if (res[i]->num_elements != 1) {
293 DEBUG(1,("samdb: search for %s %s not single valued\n",
294 attr_name, format));
295 talloc_free(res);
296 return -1;
300 *strs = talloc_array(mem_ctx, const char *, count+1);
301 if (! *strs) {
302 talloc_free(res);
303 return -1;
306 for (i=0;i<count;i++) {
307 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
309 (*strs)[count] = NULL;
311 return count;
315 pull a uint from a result set.
317 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
319 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
323 pull a (signed) int64 from a result set.
325 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
327 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
331 pull a string from a result set.
333 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
334 const char *default_value)
336 return ldb_msg_find_attr_as_string(msg, attr, default_value);
339 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
340 const char *attr, struct ldb_dn *default_value)
342 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
343 if (!ret_dn) {
344 return default_value;
346 return ret_dn;
350 pull a rid from a objectSid in a result set.
352 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
353 const char *attr, uint32_t default_value)
355 struct dom_sid *sid;
356 uint32_t rid;
358 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
359 if (sid == NULL) {
360 return default_value;
362 rid = sid->sub_auths[sid->num_auths-1];
363 talloc_free(sid);
364 return rid;
368 pull a dom_sid structure from a objectSid in a result set.
370 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
371 const char *attr)
373 const struct ldb_val *v;
374 struct dom_sid *sid;
375 enum ndr_err_code ndr_err;
376 v = ldb_msg_find_ldb_val(msg, attr);
377 if (v == NULL) {
378 return NULL;
380 sid = talloc(mem_ctx, struct dom_sid);
381 if (sid == NULL) {
382 return NULL;
384 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
385 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
386 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
387 talloc_free(sid);
388 return NULL;
390 return sid;
394 pull a guid structure from a objectGUID in a result set.
396 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
398 const struct ldb_val *v;
399 struct GUID guid;
400 NTSTATUS status;
402 v = ldb_msg_find_ldb_val(msg, attr);
403 if (!v) return GUID_zero();
405 status = GUID_from_ndr_blob(v, &guid);
406 if (!NT_STATUS_IS_OK(status)) {
407 return GUID_zero();
410 return guid;
414 pull a sid prefix from a objectSid in a result set.
415 this is used to find the domain sid for a user
417 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
418 const char *attr)
420 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
421 if (!sid || sid->num_auths < 1) return NULL;
422 sid->num_auths--;
423 return sid;
427 pull a NTTIME in a result set.
429 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
430 NTTIME default_value)
432 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
436 * Windows stores 0 for lastLogoff.
437 * But when a MS DC return the lastLogoff (as Logoff Time)
438 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
439 * cause windows 2008 and newer version to fail for SMB requests
441 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
443 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
445 if (ret == 0)
446 ret = 0x7FFFFFFFFFFFFFFFULL;
448 return ret;
452 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
453 * indicate an account doesn't expire.
455 * When Windows initially creates an account, it sets
456 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
457 * when changing from an account having a specific expiration date to
458 * that account never expiring, it sets accountExpires = 0.
460 * Consolidate that logic here to allow clearer logic for account expiry in
461 * the rest of the code.
463 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
465 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
468 if (ret == 0)
469 ret = 0x7FFFFFFFFFFFFFFFULL;
471 return ret;
475 pull a uint64_t from a result set.
477 uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
478 uint64_t default_value)
480 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
485 construct the allow_password_change field from the PwdLastSet attribute and the
486 domain password settings
488 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
489 TALLOC_CTX *mem_ctx,
490 struct ldb_dn *domain_dn,
491 struct ldb_message *msg,
492 const char *attr)
494 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
495 int64_t minPwdAge;
497 if (attr_time == 0) {
498 return 0;
501 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
503 /* yes, this is a -= not a += as minPwdAge is stored as the negative
504 of the number of 100-nano-seconds */
505 attr_time -= minPwdAge;
507 return attr_time;
511 construct the force_password_change field from the PwdLastSet
512 attribute, the userAccountControl and the domain password settings
514 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
515 TALLOC_CTX *mem_ctx,
516 struct ldb_dn *domain_dn,
517 struct ldb_message *msg)
519 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
520 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
521 int64_t maxPwdAge;
523 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
524 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
525 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
526 return 0x7FFFFFFFFFFFFFFFULL;
529 if (attr_time == 0) {
530 return 0;
533 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
534 if (maxPwdAge == 0) {
535 return 0x7FFFFFFFFFFFFFFFULL;
536 } else {
537 attr_time -= maxPwdAge;
540 return attr_time;
544 pull a samr_Password structutre from a result set.
546 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
548 struct samr_Password *hash = NULL;
549 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
550 if (val && (val->length >= sizeof(hash->hash))) {
551 hash = talloc(mem_ctx, struct samr_Password);
552 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
554 return hash;
558 pull an array of samr_Password structutres from a result set.
560 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
561 const char *attr, struct samr_Password **hashes)
563 uint_t count, i;
564 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
566 *hashes = NULL;
567 if (!val) {
568 return 0;
570 count = val->length / 16;
571 if (count == 0) {
572 return 0;
575 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
576 if (! *hashes) {
577 return 0;
580 for (i=0;i<count;i++) {
581 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
584 return count;
587 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
588 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
590 struct samr_Password *lmPwdHash, *ntPwdHash;
591 if (nt_pwd) {
592 int num_nt;
593 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
594 if (num_nt == 0) {
595 *nt_pwd = NULL;
596 } else if (num_nt > 1) {
597 return NT_STATUS_INTERNAL_DB_CORRUPTION;
598 } else {
599 *nt_pwd = &ntPwdHash[0];
602 if (lm_pwd) {
603 /* Ensure that if we have turned off LM
604 * authentication, that we never use the LM hash, even
605 * if we store it */
606 if (lp_lanman_auth(lp_ctx)) {
607 int num_lm;
608 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
609 if (num_lm == 0) {
610 *lm_pwd = NULL;
611 } else if (num_lm > 1) {
612 return NT_STATUS_INTERNAL_DB_CORRUPTION;
613 } else {
614 *lm_pwd = &lmPwdHash[0];
616 } else {
617 *lm_pwd = NULL;
620 return NT_STATUS_OK;
624 pull a samr_LogonHours structutre from a result set.
626 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
628 struct samr_LogonHours hours;
629 const int units_per_week = 168;
630 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
631 ZERO_STRUCT(hours);
632 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
633 if (!hours.bits) {
634 return hours;
636 hours.units_per_week = units_per_week;
637 memset(hours.bits, 0xFF, units_per_week);
638 if (val) {
639 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
641 return hours;
645 pull a set of account_flags from a result set.
647 This requires that the attributes:
648 pwdLastSet
649 userAccountControl
650 be included in 'msg'
652 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
653 struct ldb_message *msg, struct ldb_dn *domain_dn)
655 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
656 uint32_t acct_flags = ds_uf2acb(userAccountControl);
657 NTTIME must_change_time;
658 NTTIME now;
660 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
661 domain_dn, msg);
663 /* Test account expire time */
664 unix_to_nt_time(&now, time(NULL));
665 /* check for expired password */
666 if (must_change_time < now) {
667 acct_flags |= ACB_PW_EXPIRED;
669 return acct_flags;
672 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
673 struct ldb_message *msg,
674 const char *attr)
676 struct lsa_BinaryString s;
677 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
679 ZERO_STRUCT(s);
681 if (!val) {
682 return s;
685 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
686 if (!s.array) {
687 return s;
689 s.length = s.size = val->length/2;
690 memcpy(s.array, val->data, val->length);
692 return s;
695 /* Find an attribute, with a particular value */
697 /* The current callers of this function expect a very specific
698 * behaviour: In particular, objectClass subclass equivilance is not
699 * wanted. This means that we should not lookup the schema for the
700 * comparison function */
701 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
702 const struct ldb_message *msg,
703 const char *name, const char *value)
705 int i;
706 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
708 if (!el) {
709 return NULL;
712 for (i=0;i<el->num_values;i++) {
713 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
714 return el;
718 return NULL;
721 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
723 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
724 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
726 return LDB_SUCCESS;
729 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
731 struct ldb_message_element *el;
733 el = ldb_msg_find_element(msg, name);
734 if (el) {
735 return LDB_SUCCESS;
738 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
744 add a string element to a message
746 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
747 const char *attr_name, const char *str)
749 char *s = talloc_strdup(mem_ctx, str);
750 char *a = talloc_strdup(mem_ctx, attr_name);
751 if (s == NULL || a == NULL) {
752 return LDB_ERR_OPERATIONS_ERROR;
754 return ldb_msg_add_string(msg, a, s);
758 add a dom_sid element to a message
760 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
761 const char *attr_name, struct dom_sid *sid)
763 struct ldb_val v;
764 enum ndr_err_code ndr_err;
766 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
767 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
768 sid,
769 (ndr_push_flags_fn_t)ndr_push_dom_sid);
770 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
771 return -1;
773 return ldb_msg_add_value(msg, attr_name, &v, NULL);
778 add a delete element operation to a message
780 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
781 const char *attr_name)
783 /* we use an empty replace rather than a delete, as it allows for
784 samdb_replace() to be used everywhere */
785 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
789 add a add attribute value to a message
791 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
792 const char *attr_name, const char *value)
794 struct ldb_message_element *el;
795 char *a, *v;
796 int ret;
797 a = talloc_strdup(mem_ctx, attr_name);
798 if (a == NULL)
799 return -1;
800 v = talloc_strdup(mem_ctx, value);
801 if (v == NULL)
802 return -1;
803 ret = ldb_msg_add_string(msg, a, v);
804 if (ret != 0)
805 return ret;
806 el = ldb_msg_find_element(msg, a);
807 if (el == NULL)
808 return -1;
809 el->flags = LDB_FLAG_MOD_ADD;
810 return 0;
814 add a delete attribute value to a message
816 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
817 const char *attr_name, const char *value)
819 struct ldb_message_element *el;
820 char *a, *v;
821 int ret;
822 a = talloc_strdup(mem_ctx, attr_name);
823 if (a == NULL)
824 return -1;
825 v = talloc_strdup(mem_ctx, value);
826 if (v == NULL)
827 return -1;
828 ret = ldb_msg_add_string(msg, a, v);
829 if (ret != 0)
830 return ret;
831 el = ldb_msg_find_element(msg, a);
832 if (el == NULL)
833 return -1;
834 el->flags = LDB_FLAG_MOD_DELETE;
835 return 0;
839 add a int element to a message
841 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
842 const char *attr_name, int v)
844 const char *s = talloc_asprintf(mem_ctx, "%d", v);
845 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
849 add a uint_t element to a message
851 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
852 const char *attr_name, uint_t v)
854 const char *s = talloc_asprintf(mem_ctx, "%u", v);
855 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
859 add a (signed) int64_t element to a message
861 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
862 const char *attr_name, int64_t v)
864 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
865 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
869 add a uint64_t element to a message
871 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
872 const char *attr_name, uint64_t v)
874 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
878 add a samr_Password element to a message
880 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
881 const char *attr_name, struct samr_Password *hash)
883 struct ldb_val val;
884 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
885 if (!val.data) {
886 return -1;
888 val.length = 16;
889 return ldb_msg_add_value(msg, attr_name, &val, NULL);
893 add a samr_Password array to a message
895 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
896 const char *attr_name, struct samr_Password *hashes, uint_t count)
898 struct ldb_val val;
899 int i;
900 val.data = talloc_array_size(mem_ctx, 16, count);
901 val.length = count*16;
902 if (!val.data) {
903 return -1;
905 for (i=0;i<count;i++) {
906 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
908 return ldb_msg_add_value(msg, attr_name, &val, NULL);
912 add a acct_flags element to a message
914 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
915 const char *attr_name, uint32_t v)
917 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
921 add a logon_hours element to a message
923 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
924 const char *attr_name, struct samr_LogonHours *hours)
926 struct ldb_val val;
927 val.length = hours->units_per_week / 8;
928 val.data = hours->bits;
929 return ldb_msg_add_value(msg, attr_name, &val, NULL);
933 add a parameters element to a message
935 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
936 const char *attr_name, struct lsa_BinaryString *parameters)
938 struct ldb_val val;
939 val.length = parameters->length * 2;
940 val.data = (uint8_t *)parameters->array;
941 return ldb_msg_add_value(msg, attr_name, &val, NULL);
944 add a general value element to a message
946 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
947 const char *attr_name, const struct ldb_val *val)
949 return ldb_msg_add_value(msg, attr_name, val, NULL);
953 sets a general value element to a message
955 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
956 const char *attr_name, const struct ldb_val *val)
958 struct ldb_message_element *el;
960 el = ldb_msg_find_element(msg, attr_name);
961 if (el) {
962 el->num_values = 0;
964 return ldb_msg_add_value(msg, attr_name, val, NULL);
968 set a string element in a message
970 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
971 const char *attr_name, const char *str)
973 struct ldb_message_element *el;
975 el = ldb_msg_find_element(msg, attr_name);
976 if (el) {
977 el->num_values = 0;
979 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
983 replace elements in a record
985 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
987 int i;
989 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
990 for (i=0;i<msg->num_elements;i++) {
991 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
994 /* modify the samdb record */
995 return ldb_modify(sam_ldb, msg);
999 * Handle ldb_request in transaction
1001 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1002 struct ldb_request *req)
1004 int ret;
1006 ret = ldb_transaction_start(sam_ldb);
1007 if (ret != LDB_SUCCESS) {
1008 return ret;
1011 ret = ldb_request(sam_ldb, req);
1012 if (ret == LDB_SUCCESS) {
1013 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1016 if (ret == LDB_SUCCESS) {
1017 return ldb_transaction_commit(sam_ldb);
1019 ldb_transaction_cancel(sam_ldb);
1021 return ret;
1025 * replace elements in a record using LDB_CONTROL_AS_SYSTEM
1026 * used to skip access checks on operations
1027 * that are performed by the system
1029 int samdb_replace_as_system(struct ldb_context *sam_ldb,
1030 TALLOC_CTX *mem_ctx,
1031 struct ldb_message *msg)
1033 int i;
1034 int ldb_ret;
1035 struct ldb_request *req = NULL;
1037 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1038 for (i=0;i<msg->num_elements;i++) {
1039 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1043 ldb_ret = ldb_msg_sanity_check(sam_ldb, msg);
1044 if (ldb_ret != LDB_SUCCESS) {
1045 return ldb_ret;
1048 ldb_ret = ldb_build_mod_req(&req, sam_ldb, mem_ctx,
1049 msg,
1050 NULL,
1051 NULL,
1052 ldb_op_default_callback,
1053 NULL);
1055 if (ldb_ret != LDB_SUCCESS) {
1056 talloc_free(req);
1057 return ldb_ret;
1060 ldb_ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
1061 if (ldb_ret != LDB_SUCCESS) {
1062 talloc_free(req);
1063 return ldb_ret;
1066 /* do request and auto start a transaction */
1067 ldb_ret = dsdb_autotransaction_request(sam_ldb, req);
1069 talloc_free(req);
1070 return ldb_ret;
1074 return a default security descriptor
1076 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1078 struct security_descriptor *sd;
1080 sd = security_descriptor_initialise(mem_ctx);
1082 return sd;
1085 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1087 return ldb_get_default_basedn(sam_ctx);
1090 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1092 return ldb_get_config_basedn(sam_ctx);
1095 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1097 return ldb_get_schema_basedn(sam_ctx);
1100 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1102 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1103 struct ldb_dn *aggregate_dn;
1104 if (!schema_dn) {
1105 return NULL;
1108 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1109 if (!aggregate_dn) {
1110 return NULL;
1112 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1113 return NULL;
1115 return aggregate_dn;
1118 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1120 return ldb_get_root_basedn(sam_ctx);
1123 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1125 struct ldb_dn *new_dn;
1127 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1128 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1129 talloc_free(new_dn);
1130 return NULL;
1132 return new_dn;
1135 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1137 struct ldb_dn *new_dn;
1139 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1140 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1141 talloc_free(new_dn);
1142 return NULL;
1144 return new_dn;
1148 work out the domain sid for the current open ldb
1150 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1152 TALLOC_CTX *tmp_ctx;
1153 const struct dom_sid *domain_sid;
1154 const char *attrs[] = {
1155 "objectSid",
1156 NULL
1158 struct ldb_result *res;
1159 int ret;
1161 /* see if we have a cached copy */
1162 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1163 if (domain_sid) {
1164 return domain_sid;
1167 tmp_ctx = talloc_new(ldb);
1168 if (tmp_ctx == NULL) {
1169 goto failed;
1172 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1174 if (ret != LDB_SUCCESS) {
1175 goto failed;
1178 if (res->count != 1) {
1179 goto failed;
1182 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1183 if (domain_sid == NULL) {
1184 goto failed;
1187 /* cache the domain_sid in the ldb */
1188 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1189 goto failed;
1192 talloc_steal(ldb, domain_sid);
1193 talloc_free(tmp_ctx);
1195 return domain_sid;
1197 failed:
1198 talloc_free(tmp_ctx);
1199 return NULL;
1203 get domain sid from cache
1205 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1207 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1210 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1212 TALLOC_CTX *tmp_ctx;
1213 struct dom_sid *dom_sid_new;
1214 struct dom_sid *dom_sid_old;
1216 /* see if we have a cached copy */
1217 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1218 "cache.domain_sid"), struct dom_sid);
1220 tmp_ctx = talloc_new(ldb);
1221 if (tmp_ctx == NULL) {
1222 goto failed;
1225 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1226 if (!dom_sid_new) {
1227 goto failed;
1230 /* cache the domain_sid in the ldb */
1231 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1232 goto failed;
1235 talloc_steal(ldb, dom_sid_new);
1236 talloc_free(tmp_ctx);
1237 talloc_free(dom_sid_old);
1239 return true;
1241 failed:
1242 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1243 talloc_free(tmp_ctx);
1244 return false;
1247 /* Obtain the short name of the flexible single master operator
1248 * (FSMO), such as the PDC Emulator */
1249 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1250 const char *attr)
1252 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1253 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1254 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1255 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1257 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1258 /* Ensure this matches the format. This gives us a
1259 * bit more confidence that a 'cn' value will be a
1260 * ascii string */
1261 return NULL;
1263 if (val) {
1264 return (char *)val->data;
1266 return NULL;
1270 work out the ntds settings dn for the current open ldb
1272 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1274 TALLOC_CTX *tmp_ctx;
1275 const char *root_attrs[] = { "dsServiceName", NULL };
1276 int ret;
1277 struct ldb_result *root_res;
1278 struct ldb_dn *settings_dn;
1280 /* see if we have a cached copy */
1281 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1282 if (settings_dn) {
1283 return settings_dn;
1286 tmp_ctx = talloc_new(ldb);
1287 if (tmp_ctx == NULL) {
1288 goto failed;
1291 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1292 if (ret) {
1293 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1294 ldb_errstring(ldb)));
1295 goto failed;
1298 if (root_res->count != 1) {
1299 goto failed;
1302 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1304 /* cache the domain_sid in the ldb */
1305 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1306 goto failed;
1309 talloc_steal(ldb, settings_dn);
1310 talloc_free(tmp_ctx);
1312 return settings_dn;
1314 failed:
1315 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1316 talloc_free(tmp_ctx);
1317 return NULL;
1321 work out the ntds settings invocationId for the current open ldb
1323 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1325 TALLOC_CTX *tmp_ctx;
1326 const char *attrs[] = { "invocationId", NULL };
1327 int ret;
1328 struct ldb_result *res;
1329 struct GUID *invocation_id;
1331 /* see if we have a cached copy */
1332 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1333 if (invocation_id) {
1334 return invocation_id;
1337 tmp_ctx = talloc_new(ldb);
1338 if (tmp_ctx == NULL) {
1339 goto failed;
1342 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1343 if (ret) {
1344 goto failed;
1347 if (res->count != 1) {
1348 goto failed;
1351 invocation_id = talloc(tmp_ctx, struct GUID);
1352 if (!invocation_id) {
1353 goto failed;
1356 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1358 /* cache the domain_sid in the ldb */
1359 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1360 goto failed;
1363 talloc_steal(ldb, invocation_id);
1364 talloc_free(tmp_ctx);
1366 return invocation_id;
1368 failed:
1369 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1370 talloc_free(tmp_ctx);
1371 return NULL;
1374 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1376 TALLOC_CTX *tmp_ctx;
1377 struct GUID *invocation_id_new;
1378 struct GUID *invocation_id_old;
1380 /* see if we have a cached copy */
1381 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1382 "cache.invocation_id");
1384 tmp_ctx = talloc_new(ldb);
1385 if (tmp_ctx == NULL) {
1386 goto failed;
1389 invocation_id_new = talloc(tmp_ctx, struct GUID);
1390 if (!invocation_id_new) {
1391 goto failed;
1394 *invocation_id_new = *invocation_id_in;
1396 /* cache the domain_sid in the ldb */
1397 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1398 goto failed;
1401 talloc_steal(ldb, invocation_id_new);
1402 talloc_free(tmp_ctx);
1403 talloc_free(invocation_id_old);
1405 return true;
1407 failed:
1408 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1409 talloc_free(tmp_ctx);
1410 return false;
1414 work out the ntds settings objectGUID for the current open ldb
1416 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1418 TALLOC_CTX *tmp_ctx;
1419 const char *attrs[] = { "objectGUID", NULL };
1420 int ret;
1421 struct ldb_result *res;
1422 struct GUID *ntds_guid;
1424 /* see if we have a cached copy */
1425 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1426 if (ntds_guid) {
1427 return ntds_guid;
1430 tmp_ctx = talloc_new(ldb);
1431 if (tmp_ctx == NULL) {
1432 goto failed;
1435 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1436 if (ret) {
1437 goto failed;
1440 if (res->count != 1) {
1441 goto failed;
1444 ntds_guid = talloc(tmp_ctx, struct GUID);
1445 if (!ntds_guid) {
1446 goto failed;
1449 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1451 /* cache the domain_sid in the ldb */
1452 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1453 goto failed;
1456 talloc_steal(ldb, ntds_guid);
1457 talloc_free(tmp_ctx);
1459 return ntds_guid;
1461 failed:
1462 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1463 talloc_free(tmp_ctx);
1464 return NULL;
1467 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1469 TALLOC_CTX *tmp_ctx;
1470 struct GUID *ntds_guid_new;
1471 struct GUID *ntds_guid_old;
1473 /* see if we have a cached copy */
1474 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1476 tmp_ctx = talloc_new(ldb);
1477 if (tmp_ctx == NULL) {
1478 goto failed;
1481 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1482 if (!ntds_guid_new) {
1483 goto failed;
1486 *ntds_guid_new = *ntds_guid_in;
1488 /* cache the domain_sid in the ldb */
1489 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1490 goto failed;
1493 talloc_steal(ldb, ntds_guid_new);
1494 talloc_free(tmp_ctx);
1495 talloc_free(ntds_guid_old);
1497 return true;
1499 failed:
1500 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1501 talloc_free(tmp_ctx);
1502 return false;
1506 work out the server dn for the current open ldb
1508 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1510 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1514 work out the server dn for the current open ldb
1516 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1518 struct ldb_dn *server_dn;
1519 struct ldb_dn *server_site_dn;
1521 server_dn = samdb_server_dn(ldb, mem_ctx);
1522 if (!server_dn) return NULL;
1524 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1526 talloc_free(server_dn);
1527 return server_site_dn;
1531 find a 'reference' DN that points at another object
1532 (eg. serverReference, rIDManagerReference etc)
1534 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1535 const char *attribute, struct ldb_dn **dn)
1537 const char *attrs[2];
1538 struct ldb_result *res;
1539 int ret;
1541 attrs[0] = attribute;
1542 attrs[1] = NULL;
1544 ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
1545 if (ret != LDB_SUCCESS) {
1546 return ret;
1548 if (res->count != 1) {
1549 talloc_free(res);
1550 return LDB_ERR_NO_SUCH_OBJECT;
1553 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1554 if (!*dn) {
1555 talloc_free(res);
1556 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1559 talloc_free(res);
1560 return LDB_SUCCESS;
1564 find our machine account via the serverReference attribute in the
1565 server DN
1567 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1569 struct ldb_dn *server_dn;
1570 int ret;
1572 server_dn = samdb_server_dn(ldb, mem_ctx);
1573 if (server_dn == NULL) {
1574 return LDB_ERR_NO_SUCH_OBJECT;
1577 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1578 talloc_free(server_dn);
1580 return ret;
1584 find the RID Manager$ DN via the rIDManagerReference attribute in the
1585 base DN
1587 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1589 return samdb_reference_dn(ldb, mem_ctx, samdb_base_dn(ldb), "rIDManagerReference", dn);
1593 find the RID Set DN via the rIDSetReferences attribute in our
1594 machine account DN
1596 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1598 struct ldb_dn *server_ref_dn;
1599 int ret;
1601 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1602 if (ret != LDB_SUCCESS) {
1603 return ret;
1605 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1606 talloc_free(server_ref_dn);
1607 return ret;
1610 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1612 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
1614 if (val != NULL)
1615 return (const char *) val->data;
1616 else
1617 return NULL;
1621 work out if we are the PDC for the domain of the current open ldb
1623 bool samdb_is_pdc(struct ldb_context *ldb)
1625 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1626 int ret;
1627 struct ldb_result *dom_res;
1628 TALLOC_CTX *tmp_ctx;
1629 bool is_pdc;
1630 struct ldb_dn *pdc;
1632 tmp_ctx = talloc_new(ldb);
1633 if (tmp_ctx == NULL) {
1634 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1635 return false;
1638 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1639 if (ret) {
1640 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1641 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1642 ldb_errstring(ldb)));
1643 goto failed;
1645 if (dom_res->count != 1) {
1646 goto failed;
1649 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1651 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1652 is_pdc = true;
1653 } else {
1654 is_pdc = false;
1657 talloc_free(tmp_ctx);
1659 return is_pdc;
1661 failed:
1662 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1663 talloc_free(tmp_ctx);
1664 return false;
1668 work out if we are a Global Catalog server for the domain of the current open ldb
1670 bool samdb_is_gc(struct ldb_context *ldb)
1672 const char *attrs[] = { "options", NULL };
1673 int ret, options;
1674 struct ldb_result *res;
1675 TALLOC_CTX *tmp_ctx;
1677 tmp_ctx = talloc_new(ldb);
1678 if (tmp_ctx == NULL) {
1679 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1680 return false;
1683 /* Query cn=ntds settings,.... */
1684 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1685 if (ret) {
1686 talloc_free(tmp_ctx);
1687 return false;
1689 if (res->count != 1) {
1690 talloc_free(tmp_ctx);
1691 return false;
1694 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1695 talloc_free(tmp_ctx);
1697 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1698 if (options & 0x000000001) {
1699 return true;
1701 return false;
1704 /* Find a domain object in the parents of a particular DN. */
1705 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1706 struct ldb_dn **parent_dn, const char **errstring)
1708 TALLOC_CTX *local_ctx;
1709 struct ldb_dn *sdn = dn;
1710 struct ldb_result *res = NULL;
1711 int ret = 0;
1712 const char *attrs[] = { NULL };
1714 local_ctx = talloc_new(mem_ctx);
1715 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1717 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1718 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1719 "(|(objectClass=domain)(objectClass=builtinDomain))");
1720 if (ret == LDB_SUCCESS) {
1721 if (res->count == 1) {
1722 break;
1724 } else {
1725 break;
1729 if (ret != LDB_SUCCESS) {
1730 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1731 ldb_dn_get_linearized(dn),
1732 ldb_dn_get_linearized(sdn),
1733 ldb_errstring(ldb));
1734 talloc_free(local_ctx);
1735 return ret;
1737 if (res->count != 1) {
1738 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1739 ldb_dn_get_linearized(dn));
1740 DEBUG(0,(__location__ ": %s\n", *errstring));
1741 talloc_free(local_ctx);
1742 return LDB_ERR_CONSTRAINT_VIOLATION;
1745 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1746 talloc_free(local_ctx);
1747 return ret;
1752 * Performs checks on a user password (plaintext UNIX format - attribute
1753 * "password"). The remaining parameters have to be extracted from the domain
1754 * object in the AD.
1756 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
1758 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
1759 const uint32_t pwdProperties,
1760 const uint32_t minPwdLength)
1762 /* checks if the "minPwdLength" property is satisfied */
1763 if (minPwdLength > password->length)
1764 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
1766 /* checks the password complexity */
1767 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
1768 && (password->data != NULL)
1769 && (!check_password_quality((const char *) password->data)))
1770 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
1772 return SAMR_VALIDATION_STATUS_SUCCESS;
1776 * Sets the user password using plaintext UTF16 (attribute "new_password") or
1777 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
1778 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
1779 * gives some more informations if the changed failed.
1781 * The caller should have a LDB transaction wrapping this.
1783 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
1784 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
1785 * NT_STATUS_PASSWORD_RESTRICTION
1787 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1788 struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
1789 struct ldb_message *mod,
1790 const DATA_BLOB *new_password,
1791 struct samr_Password *param_lmNewHash,
1792 struct samr_Password *param_ntNewHash,
1793 bool user_change,
1794 enum samPwdChangeReason *reject_reason,
1795 struct samr_DomInfo1 **_dominfo)
1797 const char * const user_attrs[] = { "userAccountControl",
1798 "lmPwdHistory",
1799 "ntPwdHistory",
1800 "dBCSPwd", "unicodePwd",
1801 "objectSid",
1802 "pwdLastSet", NULL };
1803 const char * const domain_attrs[] = { "minPwdLength", "pwdProperties",
1804 "pwdHistoryLength",
1805 "maxPwdAge", "minPwdAge", NULL };
1806 NTTIME pwdLastSet;
1807 uint32_t minPwdLength, pwdProperties, pwdHistoryLength;
1808 int64_t maxPwdAge, minPwdAge;
1809 uint32_t userAccountControl;
1810 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1811 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1812 struct samr_Password local_lmNewHash, local_ntNewHash;
1813 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1814 struct dom_sid *domain_sid;
1815 struct ldb_message **res;
1816 bool restrictions;
1817 int count;
1818 time_t now = time(NULL);
1819 NTTIME now_nt;
1820 int i;
1822 /* we need to know the time to compute password age */
1823 unix_to_nt_time(&now_nt, now);
1825 /* pull all the user parameters */
1826 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1827 if (count != 1) {
1828 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1830 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1831 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1832 "lmPwdHistory", &sambaLMPwdHistory);
1833 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1834 "ntPwdHistory", &sambaNTPwdHistory);
1835 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1836 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1837 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1839 /* Copy parameters */
1840 lmNewHash = param_lmNewHash;
1841 ntNewHash = param_ntNewHash;
1843 /* Only non-trust accounts have restrictions (possibly this
1844 * test is the wrong way around, but I like to be restrictive
1845 * if possible */
1846 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1847 |UF_WORKSTATION_TRUST_ACCOUNT
1848 |UF_SERVER_TRUST_ACCOUNT));
1850 if (domain_dn != NULL) {
1851 /* pull the domain parameters */
1852 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res,
1853 domain_attrs);
1854 if (count != 1) {
1855 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1856 ldb_dn_get_linearized(domain_dn),
1857 ldb_dn_get_linearized(user_dn)));
1858 return NT_STATUS_NO_SUCH_DOMAIN;
1860 } else {
1861 /* work out the domain sid, and pull the domain from there */
1862 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0],
1863 "objectSid");
1864 if (domain_sid == NULL) {
1865 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1868 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1869 "(objectSid=%s)",
1870 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1871 if (count != 1) {
1872 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1873 dom_sid_string(mem_ctx, domain_sid),
1874 ldb_dn_get_linearized(user_dn)));
1875 return NT_STATUS_NO_SUCH_DOMAIN;
1879 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1880 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1881 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1882 maxPwdAge = samdb_result_int64(res[0], "maxPwdAge", 0);
1883 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1885 if ((userAccountControl & UF_PASSWD_NOTREQD) != 0) {
1886 /* see [MS-ADTS] 2.2.15 */
1887 minPwdLength = 0;
1890 if (_dominfo != NULL) {
1891 struct samr_DomInfo1 *dominfo;
1892 /* on failure we need to fill in the reject reasons */
1893 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1894 if (dominfo == NULL) {
1895 return NT_STATUS_NO_MEMORY;
1897 dominfo->min_password_length = minPwdLength;
1898 dominfo->password_properties = pwdProperties;
1899 dominfo->password_history_length = pwdHistoryLength;
1900 dominfo->max_password_age = maxPwdAge;
1901 dominfo->min_password_age = minPwdAge;
1902 *_dominfo = dominfo;
1905 if ((restrictions != 0) && (new_password != 0)) {
1906 char *new_pass;
1908 /* checks if the "minPwdLength" property is satisfied */
1909 if ((restrictions != 0)
1910 && (minPwdLength > utf16_len_n(
1911 new_password->data, new_password->length)/2)) {
1912 if (reject_reason) {
1913 *reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
1915 return NT_STATUS_PASSWORD_RESTRICTION;
1918 /* Create the NT hash */
1919 mdfour(local_ntNewHash.hash, new_password->data,
1920 new_password->length);
1922 ntNewHash = &local_ntNewHash;
1924 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1925 if (convert_string_talloc_convenience(mem_ctx,
1926 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1927 CH_UTF16, CH_UNIX,
1928 new_password->data, new_password->length,
1929 (void **)&new_pass, NULL, false)) {
1931 /* checks the password complexity */
1932 if ((restrictions != 0)
1933 && ((pwdProperties
1934 & DOMAIN_PASSWORD_COMPLEX) != 0)
1935 && (!check_password_quality(new_pass))) {
1936 if (reject_reason) {
1937 *reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
1939 return NT_STATUS_PASSWORD_RESTRICTION;
1942 /* compute the new lm hashes (for checking history - case insenitivly!) */
1943 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1944 lmNewHash = &local_lmNewHash;
1949 if ((restrictions != 0) && user_change) {
1950 /* are all password changes disallowed? */
1951 if ((pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) != 0) {
1952 if (reject_reason) {
1953 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1955 return NT_STATUS_PASSWORD_RESTRICTION;
1958 /* can this user change the password? */
1959 if ((userAccountControl & UF_PASSWD_CANT_CHANGE) != 0) {
1960 if (reject_reason) {
1961 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1963 return NT_STATUS_PASSWORD_RESTRICTION;
1966 /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
1967 if (pwdLastSet - minPwdAge > now_nt) {
1968 if (reject_reason) {
1969 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
1971 return NT_STATUS_PASSWORD_RESTRICTION;
1974 /* check the immediately past password */
1975 if (pwdHistoryLength > 0) {
1976 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash,
1977 lmPwdHash->hash, 16) == 0) {
1978 if (reject_reason) {
1979 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1981 return NT_STATUS_PASSWORD_RESTRICTION;
1983 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash,
1984 ntPwdHash->hash, 16) == 0) {
1985 if (reject_reason) {
1986 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
1988 return NT_STATUS_PASSWORD_RESTRICTION;
1992 /* check the password history */
1993 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len,
1994 pwdHistoryLength);
1995 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len,
1996 pwdHistoryLength);
1998 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1999 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash,
2000 16) == 0) {
2001 if (reject_reason) {
2002 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2004 return NT_STATUS_PASSWORD_RESTRICTION;
2007 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
2008 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash,
2009 16) == 0) {
2010 if (reject_reason) {
2011 *reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
2013 return NT_STATUS_PASSWORD_RESTRICTION;
2018 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
2020 /* the password is acceptable. Start forming the new fields */
2021 if (new_password != NULL) {
2022 /* if we know the cleartext UTF16 password, then set it.
2023 * Modules in ldb will set all the appropriate
2024 * hashes */
2025 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
2026 } else {
2027 /* we don't have the cleartext, so set what we have of the
2028 * hashes */
2030 if (lmNewHash) {
2031 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
2034 if (ntNewHash) {
2035 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
2039 if (reject_reason) {
2040 *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2042 return NT_STATUS_OK;
2047 * Sets the user password using plaintext UTF16 (attribute "new_password") or
2048 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2049 * as parameter if it's a user change or not ("userChange"). The "rejectReason"
2050 * gives some more informations if the changed failed.
2052 * This wrapper function for "samdb_set_password" takes a SID as input rather
2053 * than a user DN.
2055 * This call encapsulates a new LDB transaction for changing the password;
2056 * therefore the user hasn't to start a new one.
2058 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2059 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2060 * NT_STATUS_PASSWORD_RESTRICTION
2062 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2063 const struct dom_sid *user_sid,
2064 const DATA_BLOB *new_password,
2065 struct samr_Password *lmNewHash,
2066 struct samr_Password *ntNewHash,
2067 bool user_change,
2068 enum samPwdChangeReason *reject_reason,
2069 struct samr_DomInfo1 **_dominfo)
2071 NTSTATUS nt_status;
2072 struct ldb_dn *user_dn;
2073 struct ldb_message *msg;
2074 int ret;
2076 ret = ldb_transaction_start(ldb);
2077 if (ret != LDB_SUCCESS) {
2078 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2079 return NT_STATUS_TRANSACTION_ABORTED;
2082 user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
2083 "(&(objectSid=%s)(objectClass=user))",
2084 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
2085 if (!user_dn) {
2086 ldb_transaction_cancel(ldb);
2087 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
2088 dom_sid_string(mem_ctx, user_sid)));
2089 return NT_STATUS_NO_SUCH_USER;
2092 msg = ldb_msg_new(mem_ctx);
2093 if (msg == NULL) {
2094 ldb_transaction_cancel(ldb);
2095 talloc_free(user_dn);
2096 return NT_STATUS_NO_MEMORY;
2099 msg->dn = ldb_dn_copy(msg, user_dn);
2100 if (!msg->dn) {
2101 ldb_transaction_cancel(ldb);
2102 talloc_free(user_dn);
2103 talloc_free(msg);
2104 return NT_STATUS_NO_MEMORY;
2107 nt_status = samdb_set_password(ldb, mem_ctx,
2108 user_dn, NULL,
2109 msg, new_password,
2110 lmNewHash, ntNewHash,
2111 user_change,
2112 reject_reason, _dominfo);
2113 if (!NT_STATUS_IS_OK(nt_status)) {
2114 ldb_transaction_cancel(ldb);
2115 talloc_free(user_dn);
2116 talloc_free(msg);
2117 return nt_status;
2120 /* modify the samdb record */
2121 ret = samdb_replace(ldb, mem_ctx, msg);
2122 if (ret != LDB_SUCCESS) {
2123 ldb_transaction_cancel(ldb);
2124 talloc_free(user_dn);
2125 talloc_free(msg);
2126 return NT_STATUS_ACCESS_DENIED;
2129 talloc_free(msg);
2131 ret = ldb_transaction_commit(ldb);
2132 if (ret != LDB_SUCCESS) {
2133 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2134 ldb_dn_get_linearized(user_dn),
2135 ldb_errstring(ldb)));
2136 talloc_free(user_dn);
2137 return NT_STATUS_TRANSACTION_ABORTED;
2140 talloc_free(user_dn);
2141 return NT_STATUS_OK;
2145 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
2146 struct dom_sid *sid, struct ldb_dn **ret_dn)
2148 struct ldb_message *msg;
2149 struct ldb_dn *basedn;
2150 char *sidstr;
2151 int ret;
2153 sidstr = dom_sid_string(mem_ctx, sid);
2154 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2156 /* We might have to create a ForeignSecurityPrincipal, even if this user
2157 * is in our own domain */
2159 msg = ldb_msg_new(sidstr);
2160 if (msg == NULL) {
2161 talloc_free(sidstr);
2162 return NT_STATUS_NO_MEMORY;
2165 ret = dsdb_wellknown_dn(sam_ctx, sidstr, samdb_base_dn(sam_ctx),
2166 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2167 &basedn);
2168 if (ret != LDB_SUCCESS) {
2169 DEBUG(0, ("Failed to find DN for "
2170 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2171 talloc_free(sidstr);
2172 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2175 /* add core elements to the ldb_message for the alias */
2176 msg->dn = basedn;
2177 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2178 talloc_free(sidstr);
2179 return NT_STATUS_NO_MEMORY;
2182 samdb_msg_add_string(sam_ctx, msg, msg,
2183 "objectClass",
2184 "foreignSecurityPrincipal");
2186 /* create the alias */
2187 ret = ldb_add(sam_ctx, msg);
2188 if (ret != LDB_SUCCESS) {
2189 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2190 "record %s: %s\n",
2191 ldb_dn_get_linearized(msg->dn),
2192 ldb_errstring(sam_ctx)));
2193 talloc_free(sidstr);
2194 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2197 *ret_dn = talloc_steal(mem_ctx, msg->dn);
2198 talloc_free(sidstr);
2200 return NT_STATUS_OK;
2205 Find the DN of a domain, assuming it to be a dotted.dns name
2208 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2210 int i;
2211 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2212 const char *binary_encoded;
2213 const char **split_realm;
2214 struct ldb_dn *dn;
2216 if (!tmp_ctx) {
2217 return NULL;
2220 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2221 if (!split_realm) {
2222 talloc_free(tmp_ctx);
2223 return NULL;
2225 dn = ldb_dn_new(mem_ctx, ldb, NULL);
2226 for (i=0; split_realm[i]; i++) {
2227 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2228 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2229 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2230 binary_encoded, ldb_dn_get_linearized(dn)));
2231 talloc_free(tmp_ctx);
2232 return NULL;
2235 if (!ldb_dn_validate(dn)) {
2236 DEBUG(2, ("Failed to validated DN %s\n",
2237 ldb_dn_get_linearized(dn)));
2238 talloc_free(tmp_ctx);
2239 return NULL;
2241 talloc_free(tmp_ctx);
2242 return dn;
2246 Find the DN of a domain, be it the netbios or DNS name
2248 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2249 const char *domain_name)
2251 const char * const domain_ref_attrs[] = {
2252 "ncName", NULL
2254 const char * const domain_ref2_attrs[] = {
2255 NULL
2257 struct ldb_result *res_domain_ref;
2258 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2259 /* find the domain's DN */
2260 int ret_domain = ldb_search(ldb, mem_ctx,
2261 &res_domain_ref,
2262 samdb_partitions_dn(ldb, mem_ctx),
2263 LDB_SCOPE_ONELEVEL,
2264 domain_ref_attrs,
2265 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2266 escaped_domain);
2267 if (ret_domain != 0) {
2268 return NULL;
2271 if (res_domain_ref->count == 0) {
2272 ret_domain = ldb_search(ldb, mem_ctx,
2273 &res_domain_ref,
2274 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2275 LDB_SCOPE_BASE,
2276 domain_ref2_attrs,
2277 "(objectclass=domain)");
2278 if (ret_domain != 0) {
2279 return NULL;
2282 if (res_domain_ref->count == 1) {
2283 return res_domain_ref->msgs[0]->dn;
2285 return NULL;
2288 if (res_domain_ref->count > 1) {
2289 DEBUG(0,("Found %d records matching domain [%s]\n",
2290 ret_domain, domain_name));
2291 return NULL;
2294 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2300 use a GUID to find a DN
2302 int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2303 TALLOC_CTX *mem_ctx,
2304 const char *guid_str, struct ldb_dn **dn)
2306 int ret;
2307 struct ldb_result *res;
2308 const char *attrs[] = { NULL };
2309 struct ldb_request *search_req;
2310 char *expression;
2311 struct ldb_search_options_control *options;
2313 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2314 if (!expression) {
2315 DEBUG(0, (__location__ ": out of memory\n"));
2316 return LDB_ERR_OPERATIONS_ERROR;
2319 res = talloc_zero(expression, struct ldb_result);
2320 if (!res) {
2321 DEBUG(0, (__location__ ": out of memory\n"));
2322 talloc_free(expression);
2323 return LDB_ERR_OPERATIONS_ERROR;
2326 ret = ldb_build_search_req(&search_req, ldb, expression,
2327 ldb_get_default_basedn(ldb),
2328 LDB_SCOPE_SUBTREE,
2329 expression, attrs,
2330 NULL,
2331 res, ldb_search_default_callback,
2332 NULL);
2333 if (ret != LDB_SUCCESS) {
2334 talloc_free(expression);
2335 return ret;
2338 /* we need to cope with cross-partition links, so search for
2339 the GUID over all partitions */
2340 options = talloc(search_req, struct ldb_search_options_control);
2341 if (options == NULL) {
2342 DEBUG(0, (__location__ ": out of memory\n"));
2343 talloc_free(expression);
2344 return LDB_ERR_OPERATIONS_ERROR;
2346 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2348 ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2349 if (ret != LDB_SUCCESS) {
2350 talloc_free(expression);
2351 return ret;
2354 ret = ldb_request_add_control(search_req,
2355 LDB_CONTROL_SEARCH_OPTIONS_OID,
2356 true, options);
2357 if (ret != LDB_SUCCESS) {
2358 talloc_free(expression);
2359 return ret;
2362 ret = ldb_request(ldb, search_req);
2363 if (ret != LDB_SUCCESS) {
2364 talloc_free(expression);
2365 return ret;
2368 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2369 if (ret != LDB_SUCCESS) {
2370 talloc_free(expression);
2371 return ret;
2374 /* this really should be exactly 1, but there is a bug in the
2375 partitions module that can return two here with the
2376 search_options control set */
2377 if (res->count < 1) {
2378 talloc_free(expression);
2379 return LDB_ERR_NO_SUCH_OBJECT;
2382 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2383 talloc_free(expression);
2385 return LDB_SUCCESS;
2389 search for attrs on one DN, allowing for deleted objects
2391 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2392 TALLOC_CTX *mem_ctx,
2393 struct ldb_result **_res,
2394 struct ldb_dn *basedn,
2395 const char * const *attrs)
2397 int ret;
2398 struct ldb_request *req;
2399 TALLOC_CTX *tmp_ctx;
2400 struct ldb_result *res;
2402 tmp_ctx = talloc_new(mem_ctx);
2404 res = talloc_zero(tmp_ctx, struct ldb_result);
2405 if (!res) {
2406 talloc_free(tmp_ctx);
2407 return LDB_ERR_OPERATIONS_ERROR;
2410 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2411 basedn,
2412 LDB_SCOPE_BASE,
2413 NULL,
2414 attrs,
2415 NULL,
2416 res,
2417 ldb_search_default_callback,
2418 NULL);
2419 if (ret != LDB_SUCCESS) {
2420 talloc_free(tmp_ctx);
2421 return ret;
2424 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2425 if (ret != LDB_SUCCESS) {
2426 talloc_free(tmp_ctx);
2427 return ret;
2430 ret = ldb_request(ldb, req);
2431 if (ret == LDB_SUCCESS) {
2432 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2435 *_res = talloc_steal(mem_ctx, res);
2436 talloc_free(tmp_ctx);
2437 return ret;
2442 use a DN to find a GUID with a given attribute name
2444 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
2445 struct ldb_dn *dn, const char *attribute,
2446 struct GUID *guid)
2448 int ret;
2449 struct ldb_result *res;
2450 const char *attrs[2];
2451 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2453 attrs[0] = attribute;
2454 attrs[1] = NULL;
2456 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2457 if (ret != LDB_SUCCESS) {
2458 talloc_free(tmp_ctx);
2459 return ret;
2461 if (res->count < 1) {
2462 talloc_free(tmp_ctx);
2463 return LDB_ERR_NO_SUCH_OBJECT;
2465 *guid = samdb_result_guid(res->msgs[0], attribute);
2466 talloc_free(tmp_ctx);
2467 return LDB_SUCCESS;
2471 use a DN to find a GUID
2473 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2474 struct ldb_dn *dn, struct GUID *guid)
2476 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
2482 adds the given GUID to the given ldb_message. This value is added
2483 for the given attr_name (may be either "objectGUID" or "parentGUID").
2485 int dsdb_msg_add_guid(struct ldb_message *msg,
2486 struct GUID *guid,
2487 const char *attr_name)
2489 int ret;
2490 struct ldb_val v;
2491 NTSTATUS status;
2492 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
2494 status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
2495 if (!NT_STATUS_IS_OK(status)) {
2496 ret = LDB_ERR_OPERATIONS_ERROR;
2497 goto done;
2500 ret = ldb_msg_add_steal_value(msg, attr_name, &v);
2501 if (ret != LDB_SUCCESS) {
2502 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
2503 attr_name));
2504 goto done;
2507 ret = LDB_SUCCESS;
2509 done:
2510 talloc_free(tmp_ctx);
2511 return ret;
2517 use a DN to find a SID
2519 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2520 struct ldb_dn *dn, struct dom_sid *sid)
2522 int ret;
2523 struct ldb_result *res;
2524 const char *attrs[] = { "objectSID", NULL };
2525 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2526 struct dom_sid *s;
2528 ZERO_STRUCTP(sid);
2530 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2531 if (ret != LDB_SUCCESS) {
2532 talloc_free(tmp_ctx);
2533 return ret;
2535 if (res->count < 1) {
2536 talloc_free(tmp_ctx);
2537 return LDB_ERR_NO_SUCH_OBJECT;
2539 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2540 if (s == NULL) {
2541 talloc_free(tmp_ctx);
2542 return LDB_ERR_NO_SUCH_OBJECT;
2544 *sid = *s;
2545 talloc_free(tmp_ctx);
2546 return LDB_SUCCESS;
2552 load a repsFromTo blob list for a given partition GUID
2553 attr must be "repsFrom" or "repsTo"
2555 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2556 const char *attr, struct repsFromToBlob **r, uint32_t *count)
2558 const char *attrs[] = { attr, NULL };
2559 struct ldb_result *res = NULL;
2560 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2561 int i;
2562 struct ldb_message_element *el;
2564 *r = NULL;
2565 *count = 0;
2567 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2568 res->count < 1) {
2569 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2570 talloc_free(tmp_ctx);
2571 return WERR_DS_DRA_INTERNAL_ERROR;
2574 el = ldb_msg_find_element(res->msgs[0], attr);
2575 if (el == NULL) {
2576 /* it's OK to be empty */
2577 talloc_free(tmp_ctx);
2578 return WERR_OK;
2581 *count = el->num_values;
2582 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2583 if (*r == NULL) {
2584 talloc_free(tmp_ctx);
2585 return WERR_DS_DRA_INTERNAL_ERROR;
2588 for (i=0; i<(*count); i++) {
2589 enum ndr_err_code ndr_err;
2590 ndr_err = ndr_pull_struct_blob(&el->values[i],
2591 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2592 &(*r)[i],
2593 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2594 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2595 talloc_free(tmp_ctx);
2596 return WERR_DS_DRA_INTERNAL_ERROR;
2600 talloc_free(tmp_ctx);
2602 return WERR_OK;
2606 save the repsFromTo blob list for a given partition GUID
2607 attr must be "repsFrom" or "repsTo"
2609 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2610 const char *attr, struct repsFromToBlob *r, uint32_t count)
2612 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2613 struct ldb_message *msg;
2614 struct ldb_message_element *el;
2615 int i;
2617 msg = ldb_msg_new(tmp_ctx);
2618 msg->dn = dn;
2619 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2620 goto failed;
2623 el->values = talloc_array(msg, struct ldb_val, count);
2624 if (!el->values) {
2625 goto failed;
2628 for (i=0; i<count; i++) {
2629 struct ldb_val v;
2630 enum ndr_err_code ndr_err;
2632 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2633 &r[i],
2634 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2635 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2636 goto failed;
2639 el->num_values++;
2640 el->values[i] = v;
2643 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2644 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2645 goto failed;
2648 talloc_free(tmp_ctx);
2650 return WERR_OK;
2652 failed:
2653 talloc_free(tmp_ctx);
2654 return WERR_DS_DRA_INTERNAL_ERROR;
2659 load the uSNHighest attribute from the @REPLCHANGED object for a
2660 partition
2662 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2664 struct ldb_request *req;
2665 int ret;
2666 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2667 struct dsdb_control_current_partition *p_ctrl;
2668 struct ldb_result *res;
2670 res = talloc_zero(tmp_ctx, struct ldb_result);
2671 if (!res) {
2672 talloc_free(tmp_ctx);
2673 return LDB_ERR_OPERATIONS_ERROR;
2676 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2677 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2678 LDB_SCOPE_BASE,
2679 NULL, NULL,
2680 NULL,
2681 res, ldb_search_default_callback,
2682 NULL);
2683 if (ret != LDB_SUCCESS) {
2684 talloc_free(tmp_ctx);
2685 return ret;
2688 p_ctrl = talloc(req, struct dsdb_control_current_partition);
2689 if (p_ctrl == NULL) {
2690 talloc_free(res);
2691 return LDB_ERR_OPERATIONS_ERROR;
2693 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2694 p_ctrl->dn = dn;
2697 ret = ldb_request_add_control(req,
2698 DSDB_CONTROL_CURRENT_PARTITION_OID,
2699 false, p_ctrl);
2700 if (ret != LDB_SUCCESS) {
2701 talloc_free(tmp_ctx);
2702 return ret;
2705 /* Run the new request */
2706 ret = ldb_request(ldb, req);
2708 if (ret == LDB_SUCCESS) {
2709 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2712 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2713 /* it hasn't been created yet, which means
2714 an implicit value of zero */
2715 *uSN = 0;
2716 talloc_free(tmp_ctx);
2717 return LDB_SUCCESS;
2720 if (ret != LDB_SUCCESS) {
2721 talloc_free(tmp_ctx);
2722 return ret;
2725 if (res->count < 1) {
2726 *uSN = 0;
2727 } else {
2728 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2731 talloc_free(tmp_ctx);
2733 return LDB_SUCCESS;
2737 save the uSNHighest attribute in the @REPLCHANGED object for a
2738 partition
2740 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2742 struct ldb_request *req;
2743 struct ldb_message *msg;
2744 struct dsdb_control_current_partition *p_ctrl;
2745 int ret;
2747 msg = ldb_msg_new(ldb);
2748 if (msg == NULL) {
2749 return LDB_ERR_OPERATIONS_ERROR;
2752 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2753 if (msg->dn == NULL) {
2754 talloc_free(msg);
2755 return LDB_ERR_OPERATIONS_ERROR;
2758 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2759 if (ret != LDB_SUCCESS) {
2760 talloc_free(msg);
2761 return ret;
2763 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2766 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2767 if (p_ctrl == NULL) {
2768 talloc_free(msg);
2769 return LDB_ERR_OPERATIONS_ERROR;
2771 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2772 p_ctrl->dn = dn;
2774 ret = ldb_build_mod_req(&req, ldb, msg,
2775 msg,
2776 NULL,
2777 NULL, ldb_op_default_callback,
2778 NULL);
2779 again:
2780 if (ret != LDB_SUCCESS) {
2781 talloc_free(msg);
2782 return ret;
2785 ret = ldb_request_add_control(req,
2786 DSDB_CONTROL_CURRENT_PARTITION_OID,
2787 false, p_ctrl);
2788 if (ret != LDB_SUCCESS) {
2789 talloc_free(msg);
2790 return ret;
2793 /* Run the new request */
2794 ret = ldb_request(ldb, req);
2796 if (ret == LDB_SUCCESS) {
2797 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2799 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2800 ret = ldb_build_add_req(&req, ldb, msg,
2801 msg,
2802 NULL,
2803 NULL, ldb_op_default_callback,
2804 NULL);
2805 goto again;
2808 talloc_free(msg);
2810 return ret;
2813 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2814 const struct drsuapi_DsReplicaCursor2 *c2)
2816 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2819 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
2820 const struct drsuapi_DsReplicaCursor *c2)
2822 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2826 see if we are a RODC
2828 TODO: This should take a sam_ctx, and lookup the right object (with
2829 a cache)
2831 bool samdb_rodc(struct loadparm_context *lp_ctx)
2833 return lp_parm_bool(lp_ctx, NULL, "repl", "RODC", false);
2838 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
2840 flags are DS_NTDS_OPTION_*
2842 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
2844 TALLOC_CTX *tmp_ctx;
2845 const char *attrs[] = { "options", NULL };
2846 int ret;
2847 struct ldb_result *res;
2849 tmp_ctx = talloc_new(ldb);
2850 if (tmp_ctx == NULL) {
2851 goto failed;
2854 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
2855 if (ret) {
2856 goto failed;
2859 if (res->count != 1) {
2860 goto failed;
2863 *options = samdb_result_uint(res->msgs[0], "options", 0);
2865 talloc_free(tmp_ctx);
2867 return LDB_SUCCESS;
2869 failed:
2870 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
2871 talloc_free(tmp_ctx);
2872 return LDB_ERR_NO_SUCH_OBJECT;
2876 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
2877 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
2879 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
2881 char **tokens, *ret;
2882 size_t i;
2884 tokens = str_list_make(mem_ctx, cn, " -_");
2885 if (tokens == NULL)
2886 return NULL;
2888 /* "tolower()" and "toupper()" should also work properly on 0x00 */
2889 tokens[0][0] = tolower(tokens[0][0]);
2890 for (i = 1; i < str_list_length((const char **)tokens); i++)
2891 tokens[i][0] = toupper(tokens[i][0]);
2893 ret = talloc_strdup(mem_ctx, tokens[0]);
2894 for (i = 1; i < str_list_length((const char **)tokens); i++)
2895 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
2897 talloc_free(tokens);
2899 return ret;
2903 return domain functional level
2904 returns DS_DOMAIN_FUNCTION_*
2906 int dsdb_functional_level(struct ldb_context *ldb)
2908 int *domainFunctionality =
2909 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
2910 if (!domainFunctionality) {
2911 DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
2912 return DS_DOMAIN_FUNCTION_2000;
2914 return *domainFunctionality;
2918 set a GUID in an extended DN structure
2920 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
2922 struct ldb_val v;
2923 NTSTATUS status;
2924 int ret;
2926 status = GUID_to_ndr_blob(guid, dn, &v);
2927 if (!NT_STATUS_IS_OK(status)) {
2928 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
2931 ret = ldb_dn_set_extended_component(dn, component_name, &v);
2932 data_blob_free(&v);
2933 return ret;
2937 return a GUID from a extended DN structure
2939 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
2941 const struct ldb_val *v;
2943 v = ldb_dn_get_extended_component(dn, component_name);
2944 if (v == NULL) {
2945 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2948 return GUID_from_ndr_blob(v, guid);
2952 return a uint64_t from a extended DN structure
2954 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
2956 const struct ldb_val *v;
2957 char *s;
2959 v = ldb_dn_get_extended_component(dn, component_name);
2960 if (v == NULL) {
2961 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2963 s = talloc_strndup(dn, (const char *)v->data, v->length);
2964 NT_STATUS_HAVE_NO_MEMORY(s);
2966 *val = strtoull(s, NULL, 0);
2968 talloc_free(s);
2969 return NT_STATUS_OK;
2973 return a NTTIME from a extended DN structure
2975 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
2977 return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
2981 return a uint32_t from a extended DN structure
2983 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
2985 const struct ldb_val *v;
2986 char *s;
2988 v = ldb_dn_get_extended_component(dn, component_name);
2989 if (v == NULL) {
2990 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2993 s = talloc_strndup(dn, (const char *)v->data, v->length);
2994 NT_STATUS_HAVE_NO_MEMORY(s);
2996 *val = strtoul(s, NULL, 0);
2998 talloc_free(s);
2999 return NT_STATUS_OK;
3003 return RMD_FLAGS directly from a ldb_dn
3004 returns 0 if not found
3006 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3008 const struct ldb_val *v;
3009 char buf[32];
3010 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
3011 if (!v || v->length > sizeof(buf)-1) return 0;
3012 strncpy(buf, (const char *)v->data, v->length);
3013 buf[v->length] = 0;
3014 return strtoul(buf, NULL, 10);
3018 return RMD_FLAGS directly from a ldb_val for a DN
3019 returns 0 if RMD_FLAGS is not found
3021 uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val)
3023 const char *p;
3024 uint32_t flags;
3025 char *end;
3027 if (val->length < 13) {
3028 return 0;
3030 p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
3031 if (!p) {
3032 return 0;
3034 flags = strtoul(p+11, &end, 10);
3035 if (!end || *end != '>') {
3036 /* it must end in a > */
3037 return 0;
3039 return flags;
3043 return true if a ldb_val containing a DN in storage form is deleted
3045 bool dsdb_dn_is_deleted_val(struct ldb_val *val)
3047 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3051 return true if a ldb_val containing a DN in storage form is
3052 in the upgraded w2k3 linked attribute format
3054 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
3056 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
3060 return a DN for a wellknown GUID
3062 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3063 struct ldb_dn *nc_root, const char *wk_guid,
3064 struct ldb_dn **wkguid_dn)
3066 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3067 const char *attrs[] = { NULL };
3068 int ret;
3069 struct ldb_dn *dn;
3070 struct ldb_result *res;
3072 /* construct the magic WKGUID DN */
3073 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3074 wk_guid, ldb_dn_get_linearized(nc_root));
3075 if (!wkguid_dn) {
3076 talloc_free(tmp_ctx);
3077 return LDB_ERR_OPERATIONS_ERROR;
3080 ret = dsdb_search_dn_with_deleted(samdb, tmp_ctx, &res, dn, attrs);
3081 if (ret != LDB_SUCCESS) {
3082 talloc_free(tmp_ctx);
3083 return ret;
3086 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3087 talloc_free(tmp_ctx);
3088 return LDB_SUCCESS;
3092 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
3094 return ldb_dn_compare(*dn1, *dn2);
3098 find a NC root given a DN within the NC
3100 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3101 struct ldb_dn **nc_root)
3103 const char *root_attrs[] = { "namingContexts", NULL };
3104 TALLOC_CTX *tmp_ctx;
3105 int ret;
3106 struct ldb_message_element *el;
3107 struct ldb_result *root_res;
3108 int i;
3109 struct ldb_dn **nc_dns;
3111 tmp_ctx = talloc_new(samdb);
3112 if (tmp_ctx == NULL) {
3113 return LDB_ERR_OPERATIONS_ERROR;
3116 ret = ldb_search(samdb, tmp_ctx, &root_res,
3117 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
3118 if (ret) {
3119 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
3120 talloc_free(tmp_ctx);
3121 return ret;
3124 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
3125 if (!el) {
3126 DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
3127 ldb_errstring(samdb)));
3128 talloc_free(tmp_ctx);
3129 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3132 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
3133 if (!nc_dns) {
3134 talloc_free(tmp_ctx);
3135 return LDB_ERR_OPERATIONS_ERROR;
3138 for (i=0; i<el->num_values; i++) {
3139 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
3140 if (nc_dns[i] == NULL) {
3141 talloc_free(tmp_ctx);
3142 return LDB_ERR_OPERATIONS_ERROR;
3146 qsort(nc_dns, el->num_values, sizeof(nc_dns[0]), (comparison_fn_t)dsdb_dn_compare_ptrs);
3148 for (i=0; i<el->num_values; i++) {
3149 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
3150 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
3151 talloc_free(tmp_ctx);
3152 return LDB_SUCCESS;
3156 talloc_free(tmp_ctx);
3157 return LDB_ERR_NO_SUCH_OBJECT;
3162 find the deleted objects DN for any object, by looking for the NC
3163 root, then looking up the wellknown GUID
3165 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
3166 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
3167 struct ldb_dn **do_dn)
3169 struct ldb_dn *nc_root;
3170 int ret;
3172 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
3173 if (ret != LDB_SUCCESS) {
3174 return ret;
3177 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
3178 talloc_free(nc_root);
3179 return ret;
3183 return the tombstoneLifetime, in days
3185 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
3187 struct ldb_dn *dn;
3188 dn = samdb_config_dn(ldb);
3189 if (!dn) {
3190 return LDB_ERR_NO_SUCH_OBJECT;
3192 dn = ldb_dn_copy(ldb, dn);
3193 if (!dn) {
3194 return LDB_ERR_OPERATIONS_ERROR;
3196 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
3197 be a wellknown GUID for this */
3198 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT")) {
3199 talloc_free(dn);
3200 return LDB_ERR_OPERATIONS_ERROR;
3203 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
3204 talloc_free(dn);
3205 return LDB_SUCCESS;
3209 compare a ldb_val to a string case insensitively
3211 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
3213 size_t len = strlen(s);
3214 int ret;
3215 if (len > v->length) return 1;
3216 ret = strncasecmp(s, (const char *)v->data, v->length);
3217 if (ret != 0) return ret;
3218 if (v->length > len && v->data[len] != 0) {
3219 return -1;
3221 return 0;