Return infinite time for last last logoff when last logoff = 0
[Samba.git] / source4 / dsdb / common / util.c
blob5c5386b64c9cafdb5ca126562cf9b054dbec6488
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"
41 search the sam for the specified attributes in a specific domain, filter on
42 objectSid being in domain_sid.
44 int samdb_search_domain(struct ldb_context *sam_ldb,
45 TALLOC_CTX *mem_ctx,
46 struct ldb_dn *basedn,
47 struct ldb_message ***res,
48 const char * const *attrs,
49 const struct dom_sid *domain_sid,
50 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
52 va_list ap;
53 int i, count;
55 va_start(ap, format);
56 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
57 res, attrs, format, ap);
58 va_end(ap);
60 i=0;
62 while (i<count) {
63 struct dom_sid *entry_sid;
65 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
67 if ((entry_sid == NULL) ||
68 (!dom_sid_in_domain(domain_sid, entry_sid))) {
69 /* Delete that entry from the result set */
70 (*res)[i] = (*res)[count-1];
71 count -= 1;
72 talloc_free(entry_sid);
73 continue;
75 talloc_free(entry_sid);
76 i += 1;
79 return count;
83 search the sam for a single string attribute in exactly 1 record
85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
86 TALLOC_CTX *mem_ctx,
87 struct ldb_dn *basedn,
88 const char *attr_name,
89 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
91 int count;
92 const char *attrs[2] = { NULL, NULL };
93 struct ldb_message **res = NULL;
95 attrs[0] = attr_name;
97 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
98 if (count > 1) {
99 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
100 attr_name, format, count));
102 if (count != 1) {
103 talloc_free(res);
104 return NULL;
107 return samdb_result_string(res[0], attr_name, NULL);
111 search the sam for a single string attribute in exactly 1 record
113 const char *samdb_search_string(struct ldb_context *sam_ldb,
114 TALLOC_CTX *mem_ctx,
115 struct ldb_dn *basedn,
116 const char *attr_name,
117 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
119 va_list ap;
120 const char *str;
122 va_start(ap, format);
123 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
124 va_end(ap);
126 return str;
129 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
130 TALLOC_CTX *mem_ctx,
131 struct ldb_dn *basedn,
132 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
134 va_list ap;
135 struct ldb_dn *ret;
136 struct ldb_message **res = NULL;
137 int count;
139 va_start(ap, format);
140 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
141 va_end(ap);
143 if (count != 1) return NULL;
145 ret = talloc_steal(mem_ctx, res[0]->dn);
146 talloc_free(res);
148 return ret;
152 search the sam for a dom_sid attribute in exactly 1 record
154 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
155 TALLOC_CTX *mem_ctx,
156 struct ldb_dn *basedn,
157 const char *attr_name,
158 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
160 va_list ap;
161 int count;
162 struct ldb_message **res;
163 const char *attrs[2] = { NULL, NULL };
164 struct dom_sid *sid;
166 attrs[0] = attr_name;
168 va_start(ap, format);
169 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
170 va_end(ap);
171 if (count > 1) {
172 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
173 attr_name, format, count));
175 if (count != 1) {
176 talloc_free(res);
177 return NULL;
179 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
180 talloc_free(res);
181 return sid;
185 return the count of the number of records in the sam matching the query
187 int samdb_search_count(struct ldb_context *sam_ldb,
188 TALLOC_CTX *mem_ctx,
189 struct ldb_dn *basedn,
190 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
192 va_list ap;
193 struct ldb_message **res;
194 const char * const attrs[] = { NULL };
195 int ret;
197 va_start(ap, format);
198 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
199 va_end(ap);
201 return ret;
206 search the sam for a single integer attribute in exactly 1 record
208 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
209 TALLOC_CTX *mem_ctx,
210 uint_t default_value,
211 struct ldb_dn *basedn,
212 const char *attr_name,
213 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 va_list ap;
216 int count;
217 struct ldb_message **res;
218 const char *attrs[2] = { NULL, NULL };
220 attrs[0] = attr_name;
222 va_start(ap, format);
223 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
224 va_end(ap);
226 if (count != 1) {
227 return default_value;
230 return samdb_result_uint(res[0], attr_name, default_value);
234 search the sam for a single signed 64 bit integer attribute in exactly 1 record
236 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
237 TALLOC_CTX *mem_ctx,
238 int64_t default_value,
239 struct ldb_dn *basedn,
240 const char *attr_name,
241 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243 va_list ap;
244 int count;
245 struct ldb_message **res;
246 const char *attrs[2] = { NULL, NULL };
248 attrs[0] = attr_name;
250 va_start(ap, format);
251 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
252 va_end(ap);
254 if (count != 1) {
255 return default_value;
258 return samdb_result_int64(res[0], attr_name, default_value);
262 search the sam for multipe records each giving a single string attribute
263 return the number of matches, or -1 on error
265 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
266 TALLOC_CTX *mem_ctx,
267 struct ldb_dn *basedn,
268 const char ***strs,
269 const char *attr_name,
270 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
272 va_list ap;
273 int count, i;
274 const char *attrs[2] = { NULL, NULL };
275 struct ldb_message **res = NULL;
277 attrs[0] = attr_name;
279 va_start(ap, format);
280 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
281 va_end(ap);
283 if (count <= 0) {
284 return count;
287 /* make sure its single valued */
288 for (i=0;i<count;i++) {
289 if (res[i]->num_elements != 1) {
290 DEBUG(1,("samdb: search for %s %s not single valued\n",
291 attr_name, format));
292 talloc_free(res);
293 return -1;
297 *strs = talloc_array(mem_ctx, const char *, count+1);
298 if (! *strs) {
299 talloc_free(res);
300 return -1;
303 for (i=0;i<count;i++) {
304 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
306 (*strs)[count] = NULL;
308 return count;
312 pull a uint from a result set.
314 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
316 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
320 pull a (signed) int64 from a result set.
322 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
324 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
328 pull a string from a result set.
330 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
331 const char *default_value)
333 return ldb_msg_find_attr_as_string(msg, attr, default_value);
336 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
337 const char *attr, struct ldb_dn *default_value)
339 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
340 if (!ret_dn) {
341 return default_value;
343 return ret_dn;
347 pull a rid from a objectSid in a result set.
349 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
350 const char *attr, uint32_t default_value)
352 struct dom_sid *sid;
353 uint32_t rid;
355 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
356 if (sid == NULL) {
357 return default_value;
359 rid = sid->sub_auths[sid->num_auths-1];
360 talloc_free(sid);
361 return rid;
365 pull a dom_sid structure from a objectSid in a result set.
367 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
368 const char *attr)
370 const struct ldb_val *v;
371 struct dom_sid *sid;
372 enum ndr_err_code ndr_err;
373 v = ldb_msg_find_ldb_val(msg, attr);
374 if (v == NULL) {
375 return NULL;
377 sid = talloc(mem_ctx, struct dom_sid);
378 if (sid == NULL) {
379 return NULL;
381 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
382 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384 talloc_free(sid);
385 return NULL;
387 return sid;
391 pull a guid structure from a objectGUID in a result set.
393 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
395 const struct ldb_val *v;
396 enum ndr_err_code ndr_err;
397 struct GUID guid;
398 TALLOC_CTX *mem_ctx;
400 ZERO_STRUCT(guid);
402 v = ldb_msg_find_ldb_val(msg, attr);
403 if (!v) return guid;
405 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
406 if (!mem_ctx) return guid;
407 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
408 (ndr_pull_flags_fn_t)ndr_pull_GUID);
409 talloc_free(mem_ctx);
410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
411 return guid;
414 return guid;
418 pull a sid prefix from a objectSid in a result set.
419 this is used to find the domain sid for a user
421 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
422 const char *attr)
424 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
425 if (!sid || sid->num_auths < 1) return NULL;
426 sid->num_auths--;
427 return sid;
431 pull a NTTIME in a result set.
433 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
435 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
439 * Windows stores 0 for lastLogoff.
440 * But when a MS DC return the lastLogoff (as Logoff Time)
441 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
442 * cause windows 2008 and newer version to fail for SMB requests
444 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
446 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
448 if (ret == 0)
449 ret = 0x7FFFFFFFFFFFFFFFULL;
451 return ret;
455 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
456 * indicate an account doesn't expire.
458 * When Windows initially creates an account, it sets
459 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
460 * when changing from an account having a specific expiration date to
461 * that account never expiring, it sets accountExpires = 0.
463 * Consolidate that logic here to allow clearer logic for account expiry in
464 * the rest of the code.
466 NTTIME samdb_result_account_expires(struct ldb_message *msg)
468 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
471 if (ret == 0)
472 ret = 0x7FFFFFFFFFFFFFFFULL;
474 return ret;
478 pull a uint64_t from a result set.
480 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
482 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
487 construct the allow_password_change field from the PwdLastSet attribute and the
488 domain password settings
490 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
491 TALLOC_CTX *mem_ctx,
492 struct ldb_dn *domain_dn,
493 struct ldb_message *msg,
494 const char *attr)
496 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
497 int64_t minPwdAge;
499 if (attr_time == 0) {
500 return 0;
503 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
505 /* yes, this is a -= not a += as minPwdAge is stored as the negative
506 of the number of 100-nano-seconds */
507 attr_time -= minPwdAge;
509 return attr_time;
513 construct the force_password_change field from the PwdLastSet
514 attribute, the userAccountControl and the domain password settings
516 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
517 TALLOC_CTX *mem_ctx,
518 struct ldb_dn *domain_dn,
519 struct ldb_message *msg)
521 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
522 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
523 int64_t maxPwdAge;
525 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
526 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
527 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
528 return 0x7FFFFFFFFFFFFFFFULL;
531 if (attr_time == 0) {
532 return 0;
535 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
536 if (maxPwdAge == 0) {
537 return 0x7FFFFFFFFFFFFFFFULL;
538 } else {
539 attr_time -= maxPwdAge;
542 return attr_time;
546 pull a samr_Password structutre from a result set.
548 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
550 struct samr_Password *hash = NULL;
551 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
552 if (val && (val->length >= sizeof(hash->hash))) {
553 hash = talloc(mem_ctx, struct samr_Password);
554 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
556 return hash;
560 pull an array of samr_Password structutres from a result set.
562 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
563 const char *attr, struct samr_Password **hashes)
565 uint_t count = 0;
566 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
567 int i;
569 *hashes = NULL;
570 if (!val) {
571 return 0;
573 count = val->length / 16;
574 if (count == 0) {
575 return 0;
578 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
579 if (! *hashes) {
580 return 0;
583 for (i=0;i<count;i++) {
584 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
587 return count;
590 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
591 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
593 struct samr_Password *lmPwdHash, *ntPwdHash;
594 if (nt_pwd) {
595 int num_nt;
596 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
597 if (num_nt == 0) {
598 *nt_pwd = NULL;
599 } else if (num_nt > 1) {
600 return NT_STATUS_INTERNAL_DB_CORRUPTION;
601 } else {
602 *nt_pwd = &ntPwdHash[0];
605 if (lm_pwd) {
606 /* Ensure that if we have turned off LM
607 * authentication, that we never use the LM hash, even
608 * if we store it */
609 if (lp_lanman_auth(lp_ctx)) {
610 int num_lm;
611 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
612 if (num_lm == 0) {
613 *lm_pwd = NULL;
614 } else if (num_lm > 1) {
615 return NT_STATUS_INTERNAL_DB_CORRUPTION;
616 } else {
617 *lm_pwd = &lmPwdHash[0];
619 } else {
620 *lm_pwd = NULL;
623 return NT_STATUS_OK;
627 pull a samr_LogonHours structutre from a result set.
629 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
631 struct samr_LogonHours hours;
632 const int units_per_week = 168;
633 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
634 ZERO_STRUCT(hours);
635 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
636 if (!hours.bits) {
637 return hours;
639 hours.units_per_week = units_per_week;
640 memset(hours.bits, 0xFF, units_per_week);
641 if (val) {
642 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
644 return hours;
648 pull a set of account_flags from a result set.
650 This requires that the attributes:
651 pwdLastSet
652 userAccountControl
653 be included in 'msg'
655 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
656 struct ldb_message *msg, struct ldb_dn *domain_dn)
658 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
659 uint32_t acct_flags = ds_uf2acb(userAccountControl);
660 NTTIME must_change_time;
661 NTTIME now;
663 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
664 domain_dn, msg);
666 /* Test account expire time */
667 unix_to_nt_time(&now, time(NULL));
668 /* check for expired password */
669 if (must_change_time < now) {
670 acct_flags |= ACB_PW_EXPIRED;
672 return acct_flags;
675 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
676 struct ldb_message *msg,
677 const char *attr)
679 struct lsa_BinaryString s;
680 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
682 ZERO_STRUCT(s);
684 if (!val) {
685 return s;
688 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
689 if (!s.array) {
690 return s;
692 s.length = s.size = val->length/2;
693 memcpy(s.array, val->data, val->length);
695 return s;
698 /* Find an attribute, with a particular value */
700 /* The current callers of this function expect a very specific
701 * behaviour: In particular, objectClass subclass equivilance is not
702 * wanted. This means that we should not lookup the schema for the
703 * comparison function */
704 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
705 const struct ldb_message *msg,
706 const char *name, const char *value)
708 int i;
709 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
711 if (!el) {
712 return NULL;
715 for (i=0;i<el->num_values;i++) {
716 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
717 return el;
721 return NULL;
724 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
726 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
727 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
729 return LDB_SUCCESS;
732 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
734 struct ldb_message_element *el;
736 el = ldb_msg_find_element(msg, name);
737 if (el) {
738 return LDB_SUCCESS;
741 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
747 add a string element to a message
749 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
750 const char *attr_name, const char *str)
752 char *s = talloc_strdup(mem_ctx, str);
753 char *a = talloc_strdup(mem_ctx, attr_name);
754 if (s == NULL || a == NULL) {
755 return LDB_ERR_OPERATIONS_ERROR;
757 return ldb_msg_add_string(msg, a, s);
761 add a dom_sid element to a message
763 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
764 const char *attr_name, struct dom_sid *sid)
766 struct ldb_val v;
767 enum ndr_err_code ndr_err;
769 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
770 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
771 sid,
772 (ndr_push_flags_fn_t)ndr_push_dom_sid);
773 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
774 return -1;
776 return ldb_msg_add_value(msg, attr_name, &v, NULL);
781 add a delete element operation to a message
783 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name)
786 /* we use an empty replace rather than a delete, as it allows for
787 samdb_replace() to be used everywhere */
788 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
792 add a add attribute value to a message
794 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
795 const char *attr_name, const char *value)
797 struct ldb_message_element *el;
798 char *a, *v;
799 int ret;
800 a = talloc_strdup(mem_ctx, attr_name);
801 if (a == NULL)
802 return -1;
803 v = talloc_strdup(mem_ctx, value);
804 if (v == NULL)
805 return -1;
806 ret = ldb_msg_add_string(msg, a, v);
807 if (ret != 0)
808 return ret;
809 el = ldb_msg_find_element(msg, a);
810 if (el == NULL)
811 return -1;
812 el->flags = LDB_FLAG_MOD_ADD;
813 return 0;
817 add a delete attribute value to a message
819 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820 const char *attr_name, const char *value)
822 struct ldb_message_element *el;
823 char *a, *v;
824 int ret;
825 a = talloc_strdup(mem_ctx, attr_name);
826 if (a == NULL)
827 return -1;
828 v = talloc_strdup(mem_ctx, value);
829 if (v == NULL)
830 return -1;
831 ret = ldb_msg_add_string(msg, a, v);
832 if (ret != 0)
833 return ret;
834 el = ldb_msg_find_element(msg, a);
835 if (el == NULL)
836 return -1;
837 el->flags = LDB_FLAG_MOD_DELETE;
838 return 0;
842 add a int element to a message
844 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
845 const char *attr_name, int v)
847 const char *s = talloc_asprintf(mem_ctx, "%d", v);
848 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
852 add a uint_t element to a message
854 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
855 const char *attr_name, uint_t v)
857 const char *s = talloc_asprintf(mem_ctx, "%u", v);
858 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
862 add a (signed) int64_t element to a message
864 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
865 const char *attr_name, int64_t v)
867 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
868 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
872 add a uint64_t element to a message
874 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
875 const char *attr_name, uint64_t v)
877 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
878 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
882 add a samr_Password element to a message
884 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
885 const char *attr_name, struct samr_Password *hash)
887 struct ldb_val val;
888 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
889 if (!val.data) {
890 return -1;
892 val.length = 16;
893 return ldb_msg_add_value(msg, attr_name, &val, NULL);
897 add a samr_Password array to a message
899 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
900 const char *attr_name, struct samr_Password *hashes, uint_t count)
902 struct ldb_val val;
903 int i;
904 val.data = talloc_array_size(mem_ctx, 16, count);
905 val.length = count*16;
906 if (!val.data) {
907 return -1;
909 for (i=0;i<count;i++) {
910 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
912 return ldb_msg_add_value(msg, attr_name, &val, NULL);
916 add a acct_flags element to a message
918 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
919 const char *attr_name, uint32_t v)
921 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
925 add a logon_hours element to a message
927 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
928 const char *attr_name, struct samr_LogonHours *hours)
930 struct ldb_val val;
931 val.length = hours->units_per_week / 8;
932 val.data = hours->bits;
933 return ldb_msg_add_value(msg, attr_name, &val, NULL);
937 add a parameters element to a message
939 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
940 const char *attr_name, struct lsa_BinaryString *parameters)
942 struct ldb_val val;
943 val.length = parameters->length * 2;
944 val.data = (uint8_t *)parameters->array;
945 return ldb_msg_add_value(msg, attr_name, &val, NULL);
948 add a general value element to a message
950 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
951 const char *attr_name, const struct ldb_val *val)
953 return ldb_msg_add_value(msg, attr_name, val, NULL);
957 sets a general value element to a message
959 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
960 const char *attr_name, const struct ldb_val *val)
962 struct ldb_message_element *el;
964 el = ldb_msg_find_element(msg, attr_name);
965 if (el) {
966 el->num_values = 0;
968 return ldb_msg_add_value(msg, attr_name, val, NULL);
972 set a string element in a message
974 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
975 const char *attr_name, const char *str)
977 struct ldb_message_element *el;
979 el = ldb_msg_find_element(msg, attr_name);
980 if (el) {
981 el->num_values = 0;
983 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
987 replace elements in a record
989 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
991 int i;
993 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
994 for (i=0;i<msg->num_elements;i++) {
995 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
998 /* modify the samdb record */
999 return ldb_modify(sam_ldb, msg);
1003 return a default security descriptor
1005 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1007 struct security_descriptor *sd;
1009 sd = security_descriptor_initialise(mem_ctx);
1011 return sd;
1014 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1016 return ldb_get_default_basedn(sam_ctx);
1019 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1021 return ldb_get_config_basedn(sam_ctx);
1024 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1026 return ldb_get_schema_basedn(sam_ctx);
1029 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1031 return ldb_get_root_basedn(sam_ctx);
1034 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1036 struct ldb_dn *new_dn;
1038 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1039 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1040 talloc_free(new_dn);
1041 return NULL;
1043 return new_dn;
1046 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1048 struct ldb_dn *new_dn;
1050 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1051 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1052 talloc_free(new_dn);
1053 return NULL;
1055 return new_dn;
1059 work out the domain sid for the current open ldb
1061 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1063 TALLOC_CTX *tmp_ctx;
1064 const struct dom_sid *domain_sid;
1065 const char *attrs[] = {
1066 "objectSid",
1067 NULL
1069 struct ldb_result *res;
1070 int ret;
1072 /* see if we have a cached copy */
1073 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1074 if (domain_sid) {
1075 return domain_sid;
1078 tmp_ctx = talloc_new(ldb);
1079 if (tmp_ctx == NULL) {
1080 goto failed;
1083 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1085 if (ret != LDB_SUCCESS) {
1086 goto failed;
1089 if (res->count != 1) {
1090 goto failed;
1093 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1094 if (domain_sid == NULL) {
1095 goto failed;
1098 /* cache the domain_sid in the ldb */
1099 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1100 goto failed;
1103 talloc_steal(ldb, domain_sid);
1104 talloc_free(tmp_ctx);
1106 return domain_sid;
1108 failed:
1109 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1110 talloc_free(tmp_ctx);
1111 return NULL;
1114 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1116 TALLOC_CTX *tmp_ctx;
1117 struct dom_sid *dom_sid_new;
1118 struct dom_sid *dom_sid_old;
1120 /* see if we have a cached copy */
1121 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1122 "cache.domain_sid"), struct dom_sid);
1124 tmp_ctx = talloc_new(ldb);
1125 if (tmp_ctx == NULL) {
1126 goto failed;
1129 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1130 if (!dom_sid_new) {
1131 goto failed;
1134 /* cache the domain_sid in the ldb */
1135 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1136 goto failed;
1139 talloc_steal(ldb, dom_sid_new);
1140 talloc_free(tmp_ctx);
1141 talloc_free(dom_sid_old);
1143 return true;
1145 failed:
1146 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1147 talloc_free(tmp_ctx);
1148 return false;
1151 /* Obtain the short name of the flexible single master operator
1152 * (FSMO), such as the PDC Emulator */
1153 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1154 const char *attr)
1156 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1157 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1158 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1159 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1161 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1162 /* Ensure this matches the format. This gives us a
1163 * bit more confidence that a 'cn' value will be a
1164 * ascii string */
1165 return NULL;
1167 if (val) {
1168 return (char *)val->data;
1170 return NULL;
1174 work out the ntds settings dn for the current open ldb
1176 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1178 TALLOC_CTX *tmp_ctx;
1179 const char *root_attrs[] = { "dsServiceName", NULL };
1180 int ret;
1181 struct ldb_result *root_res;
1182 struct ldb_dn *settings_dn;
1184 /* see if we have a cached copy */
1185 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1186 if (settings_dn) {
1187 return settings_dn;
1190 tmp_ctx = talloc_new(ldb);
1191 if (tmp_ctx == NULL) {
1192 goto failed;
1195 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1196 if (ret) {
1197 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1198 ldb_errstring(ldb)));
1199 goto failed;
1202 if (root_res->count != 1) {
1203 goto failed;
1206 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1208 /* cache the domain_sid in the ldb */
1209 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1210 goto failed;
1213 talloc_steal(ldb, settings_dn);
1214 talloc_free(tmp_ctx);
1216 return settings_dn;
1218 failed:
1219 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1220 talloc_free(tmp_ctx);
1221 return NULL;
1225 work out the ntds settings invocationId for the current open ldb
1227 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1229 TALLOC_CTX *tmp_ctx;
1230 const char *attrs[] = { "invocationId", NULL };
1231 int ret;
1232 struct ldb_result *res;
1233 struct GUID *invocation_id;
1235 /* see if we have a cached copy */
1236 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1237 if (invocation_id) {
1238 return invocation_id;
1241 tmp_ctx = talloc_new(ldb);
1242 if (tmp_ctx == NULL) {
1243 goto failed;
1246 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1247 if (ret) {
1248 goto failed;
1251 if (res->count != 1) {
1252 goto failed;
1255 invocation_id = talloc(tmp_ctx, struct GUID);
1256 if (!invocation_id) {
1257 goto failed;
1260 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1262 /* cache the domain_sid in the ldb */
1263 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1264 goto failed;
1267 talloc_steal(ldb, invocation_id);
1268 talloc_free(tmp_ctx);
1270 return invocation_id;
1272 failed:
1273 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1274 talloc_free(tmp_ctx);
1275 return NULL;
1278 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1280 TALLOC_CTX *tmp_ctx;
1281 struct GUID *invocation_id_new;
1282 struct GUID *invocation_id_old;
1284 /* see if we have a cached copy */
1285 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1286 "cache.invocation_id");
1288 tmp_ctx = talloc_new(ldb);
1289 if (tmp_ctx == NULL) {
1290 goto failed;
1293 invocation_id_new = talloc(tmp_ctx, struct GUID);
1294 if (!invocation_id_new) {
1295 goto failed;
1298 *invocation_id_new = *invocation_id_in;
1300 /* cache the domain_sid in the ldb */
1301 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1302 goto failed;
1305 talloc_steal(ldb, invocation_id_new);
1306 talloc_free(tmp_ctx);
1307 talloc_free(invocation_id_old);
1309 return true;
1311 failed:
1312 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1313 talloc_free(tmp_ctx);
1314 return false;
1318 work out the ntds settings objectGUID for the current open ldb
1320 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1322 TALLOC_CTX *tmp_ctx;
1323 const char *attrs[] = { "objectGUID", NULL };
1324 int ret;
1325 struct ldb_result *res;
1326 struct GUID *ntds_guid;
1328 /* see if we have a cached copy */
1329 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1330 if (ntds_guid) {
1331 return ntds_guid;
1334 tmp_ctx = talloc_new(ldb);
1335 if (tmp_ctx == NULL) {
1336 goto failed;
1339 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1340 if (ret) {
1341 goto failed;
1344 if (res->count != 1) {
1345 goto failed;
1348 ntds_guid = talloc(tmp_ctx, struct GUID);
1349 if (!ntds_guid) {
1350 goto failed;
1353 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1355 /* cache the domain_sid in the ldb */
1356 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1357 goto failed;
1360 talloc_steal(ldb, ntds_guid);
1361 talloc_free(tmp_ctx);
1363 return ntds_guid;
1365 failed:
1366 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1367 talloc_free(tmp_ctx);
1368 return NULL;
1371 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1373 TALLOC_CTX *tmp_ctx;
1374 struct GUID *ntds_guid_new;
1375 struct GUID *ntds_guid_old;
1377 /* see if we have a cached copy */
1378 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1380 tmp_ctx = talloc_new(ldb);
1381 if (tmp_ctx == NULL) {
1382 goto failed;
1385 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1386 if (!ntds_guid_new) {
1387 goto failed;
1390 *ntds_guid_new = *ntds_guid_in;
1392 /* cache the domain_sid in the ldb */
1393 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1394 goto failed;
1397 talloc_steal(ldb, ntds_guid_new);
1398 talloc_free(tmp_ctx);
1399 talloc_free(ntds_guid_old);
1401 return true;
1403 failed:
1404 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1405 talloc_free(tmp_ctx);
1406 return false;
1410 work out the server dn for the current open ldb
1412 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1414 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1418 work out the server dn for the current open ldb
1420 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1422 struct ldb_dn *server_dn;
1423 struct ldb_dn *server_site_dn;
1425 server_dn = samdb_server_dn(ldb, mem_ctx);
1426 if (!server_dn) return NULL;
1428 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1430 talloc_free(server_dn);
1431 return server_site_dn;
1435 work out if we are the PDC for the domain of the current open ldb
1437 bool samdb_is_pdc(struct ldb_context *ldb)
1439 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1440 int ret;
1441 struct ldb_result *dom_res;
1442 TALLOC_CTX *tmp_ctx;
1443 bool is_pdc;
1444 struct ldb_dn *pdc;
1446 tmp_ctx = talloc_new(ldb);
1447 if (tmp_ctx == NULL) {
1448 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1449 return false;
1452 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1453 if (ret) {
1454 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1455 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1456 ldb_errstring(ldb)));
1457 goto failed;
1459 if (dom_res->count != 1) {
1460 goto failed;
1463 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1465 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1466 is_pdc = true;
1467 } else {
1468 is_pdc = false;
1471 talloc_free(tmp_ctx);
1473 return is_pdc;
1475 failed:
1476 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1477 talloc_free(tmp_ctx);
1478 return false;
1482 work out if we are a Global Catalog server for the domain of the current open ldb
1484 bool samdb_is_gc(struct ldb_context *ldb)
1486 const char *attrs[] = { "options", NULL };
1487 int ret, options;
1488 struct ldb_result *res;
1489 TALLOC_CTX *tmp_ctx;
1491 tmp_ctx = talloc_new(ldb);
1492 if (tmp_ctx == NULL) {
1493 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1494 return false;
1497 /* Query cn=ntds settings,.... */
1498 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1499 if (ret) {
1500 talloc_free(tmp_ctx);
1501 return false;
1503 if (res->count != 1) {
1504 talloc_free(tmp_ctx);
1505 return false;
1508 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1509 talloc_free(tmp_ctx);
1511 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1512 if (options & 0x000000001) {
1513 return true;
1515 return false;
1518 /* Find a domain object in the parents of a particular DN. */
1519 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1520 struct ldb_dn **parent_dn, const char **errstring)
1522 TALLOC_CTX *local_ctx;
1523 struct ldb_dn *sdn = dn;
1524 struct ldb_result *res = NULL;
1525 int ret = 0;
1526 const char *attrs[] = { NULL };
1528 local_ctx = talloc_new(mem_ctx);
1529 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1531 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1532 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1533 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1534 if (ret == LDB_SUCCESS) {
1535 if (res->count == 1) {
1536 break;
1538 } else {
1539 break;
1543 if (ret != LDB_SUCCESS) {
1544 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1545 ldb_dn_get_linearized(dn),
1546 ldb_dn_get_linearized(sdn),
1547 ldb_errstring(ldb));
1548 talloc_free(local_ctx);
1549 return ret;
1551 if (res->count != 1) {
1552 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1553 ldb_dn_get_linearized(dn));
1554 talloc_free(local_ctx);
1555 return LDB_ERR_CONSTRAINT_VIOLATION;
1558 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1559 talloc_free(local_ctx);
1560 return ret;
1564 check that a password is sufficiently complex
1566 static bool samdb_password_complexity_ok(const char *pass)
1568 return check_password_quality(pass);
1574 set the user password using plaintext, obeying any user or domain
1575 password restrictions
1577 note that this function doesn't actually store the result in the
1578 database, it just fills in the "mod" structure with ldb modify
1579 elements to setup the correct change when samdb_replace() is
1580 called. This allows the caller to combine the change with other
1581 changes (as is needed by some of the set user info levels)
1583 The caller should probably have a transaction wrapping this
1585 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1586 struct ldb_dn *user_dn,
1587 struct ldb_dn *domain_dn,
1588 struct ldb_message *mod,
1589 const DATA_BLOB *new_password,
1590 struct samr_Password *lmNewHash,
1591 struct samr_Password *ntNewHash,
1592 bool user_change,
1593 enum samr_RejectReason *reject_reason,
1594 struct samr_DomInfo1 **_dominfo)
1596 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1597 "ntPwdHistory",
1598 "dBCSPwd", "unicodePwd",
1599 "objectSid",
1600 "pwdLastSet", NULL };
1601 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1602 "maxPwdAge", "minPwdAge",
1603 "minPwdLength", NULL };
1604 NTTIME pwdLastSet;
1605 int64_t minPwdAge;
1606 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1607 uint_t userAccountControl;
1608 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1609 struct samr_Password local_lmNewHash, local_ntNewHash;
1610 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1611 struct dom_sid *domain_sid;
1612 struct ldb_message **res;
1613 bool restrictions;
1614 int count;
1615 time_t now = time(NULL);
1616 NTTIME now_nt;
1617 int i;
1619 /* we need to know the time to compute password age */
1620 unix_to_nt_time(&now_nt, now);
1622 /* pull all the user parameters */
1623 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1624 if (count != 1) {
1625 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1627 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1628 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1629 "lmPwdHistory", &sambaLMPwdHistory);
1630 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1631 "ntPwdHistory", &sambaNTPwdHistory);
1632 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1633 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1634 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1636 /* Only non-trust accounts have restrictions (possibly this
1637 * test is the wrong way around, but I like to be restrictive
1638 * if possible */
1639 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1640 |UF_WORKSTATION_TRUST_ACCOUNT
1641 |UF_SERVER_TRUST_ACCOUNT));
1643 if (domain_dn) {
1644 /* pull the domain parameters */
1645 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1646 if (count != 1) {
1647 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1648 ldb_dn_get_linearized(domain_dn),
1649 ldb_dn_get_linearized(user_dn)));
1650 return NT_STATUS_NO_SUCH_DOMAIN;
1652 } else {
1653 /* work out the domain sid, and pull the domain from there */
1654 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1655 if (domain_sid == NULL) {
1656 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1659 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1660 "(objectSid=%s)",
1661 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1662 if (count != 1) {
1663 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1664 dom_sid_string(mem_ctx, domain_sid),
1665 ldb_dn_get_linearized(user_dn)));
1666 return NT_STATUS_NO_SUCH_DOMAIN;
1670 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1671 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1672 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1673 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1675 if (userAccountControl & UF_PASSWD_NOTREQD) {
1676 /* see [MS-ADTS] 2.2.15 */
1677 minPwdLength = 0;
1680 if (_dominfo) {
1681 struct samr_DomInfo1 *dominfo;
1682 /* on failure we need to fill in the reject reasons */
1683 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1684 if (dominfo == NULL) {
1685 return NT_STATUS_NO_MEMORY;
1687 dominfo->min_password_length = minPwdLength;
1688 dominfo->password_properties = pwdProperties;
1689 dominfo->password_history_length = pwdHistoryLength;
1690 dominfo->max_password_age = minPwdAge;
1691 dominfo->min_password_age = minPwdAge;
1692 *_dominfo = dominfo;
1695 if (restrictions && new_password) {
1696 char *new_pass;
1698 /* check the various password restrictions */
1699 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1700 if (reject_reason) {
1701 *reject_reason = SAMR_REJECT_TOO_SHORT;
1703 return NT_STATUS_PASSWORD_RESTRICTION;
1706 /* Create the NT hash */
1707 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1709 ntNewHash = &local_ntNewHash;
1711 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1712 if (convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1713 CH_UTF16, CH_UNIX,
1714 new_password->data, new_password->length,
1715 (void **)&new_pass, NULL, false)) {
1717 /* possibly check password complexity */
1718 if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
1719 !samdb_password_complexity_ok(new_pass)) {
1720 if (reject_reason) {
1721 *reject_reason = SAMR_REJECT_COMPLEXITY;
1723 return NT_STATUS_PASSWORD_RESTRICTION;
1726 /* compute the new lm hashes (for checking history - case insenitivly!) */
1727 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1728 lmNewHash = &local_lmNewHash;
1733 if (restrictions && user_change) {
1734 /* are all password changes disallowed? */
1735 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1736 if (reject_reason) {
1737 *reject_reason = SAMR_REJECT_OTHER;
1739 return NT_STATUS_PASSWORD_RESTRICTION;
1742 /* can this user change password? */
1743 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1744 if (reject_reason) {
1745 *reject_reason = SAMR_REJECT_OTHER;
1747 return NT_STATUS_PASSWORD_RESTRICTION;
1750 /* yes, this is a minus. The ages are in negative 100nsec units! */
1751 if (pwdLastSet - minPwdAge > now_nt) {
1752 if (reject_reason) {
1753 *reject_reason = SAMR_REJECT_OTHER;
1755 return NT_STATUS_PASSWORD_RESTRICTION;
1758 /* check the immediately past password */
1759 if (pwdHistoryLength > 0) {
1760 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1761 if (reject_reason) {
1762 *reject_reason = SAMR_REJECT_IN_HISTORY;
1764 return NT_STATUS_PASSWORD_RESTRICTION;
1766 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1767 if (reject_reason) {
1768 *reject_reason = SAMR_REJECT_IN_HISTORY;
1770 return NT_STATUS_PASSWORD_RESTRICTION;
1774 /* check the password history */
1775 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1776 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1778 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1779 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1780 if (reject_reason) {
1781 *reject_reason = SAMR_REJECT_IN_HISTORY;
1783 return NT_STATUS_PASSWORD_RESTRICTION;
1786 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1787 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1788 if (reject_reason) {
1789 *reject_reason = SAMR_REJECT_IN_HISTORY;
1791 return NT_STATUS_PASSWORD_RESTRICTION;
1796 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1798 /* the password is acceptable. Start forming the new fields */
1799 if (new_password) {
1800 /* if we know the cleartext UTF16 password, then set it.
1801 * Modules in ldb will set all the appropriate
1802 * hashes */
1803 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1804 } else {
1805 /* We don't have the cleartext, so delete the old one
1806 * and set what we have of the hashes */
1807 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1809 if (lmNewHash) {
1810 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1811 } else {
1812 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1815 if (ntNewHash) {
1816 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1817 } else {
1818 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1822 return NT_STATUS_OK;
1827 set the user password using plaintext, obeying any user or domain
1828 password restrictions
1830 This wrapper function takes a SID as input, rather than a user DN,
1831 and actually performs the password change
1834 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1835 const struct dom_sid *user_sid,
1836 const DATA_BLOB *new_pass,
1837 struct samr_Password *lmNewHash,
1838 struct samr_Password *ntNewHash,
1839 bool user_change,
1840 enum samr_RejectReason *reject_reason,
1841 struct samr_DomInfo1 **_dominfo)
1843 NTSTATUS nt_status;
1844 struct ldb_dn *user_dn;
1845 struct ldb_message *msg;
1846 int ret;
1848 ret = ldb_transaction_start(ctx);
1849 if (ret) {
1850 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1851 return NT_STATUS_TRANSACTION_ABORTED;
1854 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1855 "(&(objectSid=%s)(objectClass=user))",
1856 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1857 if (!user_dn) {
1858 ldb_transaction_cancel(ctx);
1859 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1860 dom_sid_string(mem_ctx, user_sid)));
1861 return NT_STATUS_NO_SUCH_USER;
1864 msg = ldb_msg_new(mem_ctx);
1865 if (msg == NULL) {
1866 ldb_transaction_cancel(ctx);
1867 return NT_STATUS_NO_MEMORY;
1870 msg->dn = ldb_dn_copy(msg, user_dn);
1871 if (!msg->dn) {
1872 ldb_transaction_cancel(ctx);
1873 return NT_STATUS_NO_MEMORY;
1876 nt_status = samdb_set_password(ctx, mem_ctx,
1877 user_dn, NULL,
1878 msg, new_pass,
1879 lmNewHash, ntNewHash,
1880 user_change, /* This is a password set, not change */
1881 reject_reason, _dominfo);
1882 if (!NT_STATUS_IS_OK(nt_status)) {
1883 ldb_transaction_cancel(ctx);
1884 return nt_status;
1887 /* modify the samdb record */
1888 ret = samdb_replace(ctx, mem_ctx, msg);
1889 if (ret != 0) {
1890 ldb_transaction_cancel(ctx);
1891 return NT_STATUS_ACCESS_DENIED;
1894 ret = ldb_transaction_commit(ctx);
1895 if (ret != 0) {
1896 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1897 ldb_dn_get_linearized(msg->dn),
1898 ldb_errstring(ctx)));
1899 return NT_STATUS_TRANSACTION_ABORTED;
1901 return NT_STATUS_OK;
1906 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1907 struct dom_sid *sid, struct ldb_dn **ret_dn)
1909 struct ldb_message *msg;
1910 struct ldb_dn *basedn;
1911 const char *sidstr;
1912 int ret;
1914 sidstr = dom_sid_string(mem_ctx, sid);
1915 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1917 /* We might have to create a ForeignSecurityPrincipal, even if this user
1918 * is in our own domain */
1920 msg = ldb_msg_new(mem_ctx);
1921 if (msg == NULL) {
1922 return NT_STATUS_NO_MEMORY;
1925 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1926 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1927 * not work, this is wrong for the Builtin domain, there's no
1928 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1931 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1932 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1934 if (basedn == NULL) {
1935 DEBUG(0, ("Failed to find DN for "
1936 "ForeignSecurityPrincipal container\n"));
1937 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1940 /* add core elements to the ldb_message for the alias */
1941 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1942 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1943 return NT_STATUS_NO_MEMORY;
1945 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1946 "objectClass",
1947 "foreignSecurityPrincipal");
1949 /* create the alias */
1950 ret = ldb_add(sam_ctx, msg);
1951 if (ret != 0) {
1952 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1953 "record %s: %s\n",
1954 ldb_dn_get_linearized(msg->dn),
1955 ldb_errstring(sam_ctx)));
1956 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1958 *ret_dn = msg->dn;
1959 return NT_STATUS_OK;
1964 Find the DN of a domain, assuming it to be a dotted.dns name
1967 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1969 int i;
1970 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1971 const char *binary_encoded;
1972 const char **split_realm;
1973 struct ldb_dn *dn;
1975 if (!tmp_ctx) {
1976 return NULL;
1979 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1980 if (!split_realm) {
1981 talloc_free(tmp_ctx);
1982 return NULL;
1984 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1985 for (i=0; split_realm[i]; i++) {
1986 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1987 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1988 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1989 binary_encoded, ldb_dn_get_linearized(dn)));
1990 talloc_free(tmp_ctx);
1991 return NULL;
1994 if (!ldb_dn_validate(dn)) {
1995 DEBUG(2, ("Failed to validated DN %s\n",
1996 ldb_dn_get_linearized(dn)));
1997 return NULL;
1999 return dn;
2002 Find the DN of a domain, be it the netbios or DNS name
2005 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2006 const char *domain_name)
2008 const char * const domain_ref_attrs[] = {
2009 "ncName", NULL
2011 const char * const domain_ref2_attrs[] = {
2012 NULL
2014 struct ldb_result *res_domain_ref;
2015 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2016 /* find the domain's DN */
2017 int ret_domain = ldb_search(ldb, mem_ctx,
2018 &res_domain_ref,
2019 samdb_partitions_dn(ldb, mem_ctx),
2020 LDB_SCOPE_ONELEVEL,
2021 domain_ref_attrs,
2022 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2023 escaped_domain);
2024 if (ret_domain != 0) {
2025 return NULL;
2028 if (res_domain_ref->count == 0) {
2029 ret_domain = ldb_search(ldb, mem_ctx,
2030 &res_domain_ref,
2031 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2032 LDB_SCOPE_BASE,
2033 domain_ref2_attrs,
2034 "(objectclass=domain)");
2035 if (ret_domain != 0) {
2036 return NULL;
2039 if (res_domain_ref->count == 1) {
2040 return res_domain_ref->msgs[0]->dn;
2042 return NULL;
2045 if (res_domain_ref->count > 1) {
2046 DEBUG(0,("Found %d records matching domain [%s]\n",
2047 ret_domain, domain_name));
2048 return NULL;
2051 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);