r20398: Revert this patch, which caused failures in the samba3sam.js build farm test.
[Samba/bb.git] / source4 / dsdb / samdb / samdb.c
blob405f15c83e7bfd96556f00cbcaa2380e4230c90b
1 /*
2 Unix SMB/CIFS implementation.
4 interface functions for the sam database
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/ldb/include/ldb_errors.h"
31 #include "libcli/security/security.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "libcli/ldap/ldap.h"
34 #include "system/time.h"
35 #include "system/filesys.h"
36 #include "db_wrap.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "dsdb/common/flags.h"
41 connect to the SAM database
42 return an opaque context pointer on success, or NULL on failure
44 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
45 struct auth_session_info *session_info)
47 struct ldb_context *ldb;
48 ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
49 NULL, 0, NULL);
50 if (!ldb) {
51 return NULL;
53 return ldb;
57 search the sam for the specified attributes in a specific domain, filter on
58 objectSid being in domain_sid.
60 int samdb_search_domain(struct ldb_context *sam_ldb,
61 TALLOC_CTX *mem_ctx,
62 struct ldb_dn *basedn,
63 struct ldb_message ***res,
64 const char * const *attrs,
65 const struct dom_sid *domain_sid,
66 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
68 va_list ap;
69 int i, count;
71 va_start(ap, format);
72 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73 res, attrs, format, ap);
74 va_end(ap);
76 i=0;
78 while (i<count) {
79 struct dom_sid *entry_sid;
81 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
83 if ((entry_sid == NULL) ||
84 (!dom_sid_in_domain(domain_sid, entry_sid))) {
85 /* Delete that entry from the result set */
86 (*res)[i] = (*res)[count-1];
87 count -= 1;
88 talloc_free(entry_sid);
89 continue;
91 talloc_free(entry_sid);
92 i += 1;
95 return count;
99 search the sam for a single string attribute in exactly 1 record
101 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
102 TALLOC_CTX *mem_ctx,
103 struct ldb_dn *basedn,
104 const char *attr_name,
105 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
107 int count;
108 const char *attrs[2] = { NULL, NULL };
109 struct ldb_message **res = NULL;
111 attrs[0] = attr_name;
113 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
114 if (count > 1) {
115 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
116 attr_name, format, count));
118 if (count != 1) {
119 talloc_free(res);
120 return NULL;
123 return samdb_result_string(res[0], attr_name, NULL);
128 search the sam for a single string attribute in exactly 1 record
130 const char *samdb_search_string(struct ldb_context *sam_ldb,
131 TALLOC_CTX *mem_ctx,
132 struct ldb_dn *basedn,
133 const char *attr_name,
134 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
136 va_list ap;
137 const char *str;
139 va_start(ap, format);
140 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
141 va_end(ap);
143 return str;
146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
147 TALLOC_CTX *mem_ctx,
148 struct ldb_dn *basedn,
149 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
151 va_list ap;
152 struct ldb_dn *ret;
153 struct ldb_message **res = NULL;
154 int count;
156 va_start(ap, format);
157 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
158 va_end(ap);
160 if (count != 1) return NULL;
162 ret = talloc_steal(mem_ctx, res[0]->dn);
163 talloc_free(res);
165 return ret;
169 search the sam for a dom_sid attribute in exactly 1 record
171 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
172 TALLOC_CTX *mem_ctx,
173 struct ldb_dn *basedn,
174 const char *attr_name,
175 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
177 va_list ap;
178 int count;
179 struct ldb_message **res;
180 const char *attrs[2] = { NULL, NULL };
181 struct dom_sid *sid;
183 attrs[0] = attr_name;
185 va_start(ap, format);
186 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
187 va_end(ap);
188 if (count > 1) {
189 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
190 attr_name, format, count));
192 if (count != 1) {
193 talloc_free(res);
194 return NULL;
196 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
197 talloc_free(res);
198 return sid;
202 return the count of the number of records in the sam matching the query
204 int samdb_search_count(struct ldb_context *sam_ldb,
205 TALLOC_CTX *mem_ctx,
206 struct ldb_dn *basedn,
207 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
209 va_list ap;
210 struct ldb_message **res;
211 const char * const attrs[] = { NULL };
212 int ret;
214 va_start(ap, format);
215 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
216 va_end(ap);
218 return ret;
223 search the sam for a single integer attribute in exactly 1 record
225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
226 TALLOC_CTX *mem_ctx,
227 uint_t default_value,
228 struct ldb_dn *basedn,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
232 va_list ap;
233 int count;
234 struct ldb_message **res;
235 const char *attrs[2] = { NULL, NULL };
237 attrs[0] = attr_name;
239 va_start(ap, format);
240 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
241 va_end(ap);
243 if (count != 1) {
244 return default_value;
247 return samdb_result_uint(res[0], attr_name, default_value);
251 search the sam for a single signed 64 bit integer attribute in exactly 1 record
253 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
254 TALLOC_CTX *mem_ctx,
255 int64_t default_value,
256 struct ldb_dn *basedn,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
260 va_list ap;
261 int count;
262 struct ldb_message **res;
263 const char *attrs[2] = { NULL, NULL };
265 attrs[0] = attr_name;
267 va_start(ap, format);
268 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
269 va_end(ap);
271 if (count != 1) {
272 return default_value;
275 return samdb_result_int64(res[0], attr_name, default_value);
279 search the sam for multipe records each giving a single string attribute
280 return the number of matches, or -1 on error
282 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
283 TALLOC_CTX *mem_ctx,
284 struct ldb_dn *basedn,
285 const char ***strs,
286 const char *attr_name,
287 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
289 va_list ap;
290 int count, i;
291 const char *attrs[2] = { NULL, NULL };
292 struct ldb_message **res = NULL;
294 attrs[0] = attr_name;
296 va_start(ap, format);
297 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
298 va_end(ap);
300 if (count <= 0) {
301 return count;
304 /* make sure its single valued */
305 for (i=0;i<count;i++) {
306 if (res[i]->num_elements != 1) {
307 DEBUG(1,("samdb: search for %s %s not single valued\n",
308 attr_name, format));
309 talloc_free(res);
310 return -1;
314 *strs = talloc_array(mem_ctx, const char *, count+1);
315 if (! *strs) {
316 talloc_free(res);
317 return -1;
320 for (i=0;i<count;i++) {
321 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
323 (*strs)[count] = NULL;
325 return count;
329 pull a uint from a result set.
331 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
333 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
337 pull a (signed) int64 from a result set.
339 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
341 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
345 pull a string from a result set.
347 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
348 const char *default_value)
350 return ldb_msg_find_attr_as_string(msg, attr, default_value);
353 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354 const char *attr, struct ldb_dn *default_value)
356 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
357 if (!ret_dn) {
358 return default_value;
360 return ret_dn;
364 pull a rid from a objectSid in a result set.
366 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
367 const char *attr, uint32_t default_value)
369 struct dom_sid *sid;
370 uint32_t rid;
372 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
373 if (sid == NULL) {
374 return default_value;
376 rid = sid->sub_auths[sid->num_auths-1];
377 talloc_free(sid);
378 return rid;
382 pull a dom_sid structure from a objectSid in a result set.
384 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
385 const char *attr)
387 const struct ldb_val *v;
388 struct dom_sid *sid;
389 NTSTATUS status;
390 v = ldb_msg_find_ldb_val(msg, attr);
391 if (v == NULL) {
392 return NULL;
394 sid = talloc(mem_ctx, struct dom_sid);
395 if (sid == NULL) {
396 return NULL;
398 status = ndr_pull_struct_blob(v, sid, sid,
399 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
400 if (!NT_STATUS_IS_OK(status)) {
401 talloc_free(sid);
402 return NULL;
404 return sid;
408 pull a guid structure from a objectGUID in a result set.
410 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
412 const struct ldb_val *v;
413 NTSTATUS status;
414 struct GUID guid;
415 TALLOC_CTX *mem_ctx;
417 ZERO_STRUCT(guid);
419 v = ldb_msg_find_ldb_val(msg, attr);
420 if (!v) return guid;
422 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
423 if (!mem_ctx) return guid;
424 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
425 (ndr_pull_flags_fn_t)ndr_pull_GUID);
426 talloc_free(mem_ctx);
427 if (!NT_STATUS_IS_OK(status)) {
428 return guid;
431 return guid;
435 pull a sid prefix from a objectSid in a result set.
436 this is used to find the domain sid for a user
438 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
439 const char *attr)
441 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
442 if (!sid || sid->num_auths < 1) return NULL;
443 sid->num_auths--;
444 return sid;
448 pull a NTTIME in a result set.
450 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
452 const char *str = ldb_msg_find_attr_as_string(msg, attr, NULL);
453 if (!str) return default_value;
454 return nttime_from_string(str);
458 pull a uint64_t from a result set.
460 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
462 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
467 construct the allow_password_change field from the PwdLastSet attribute and the
468 domain password settings
470 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
471 TALLOC_CTX *mem_ctx,
472 struct ldb_dn *domain_dn,
473 struct ldb_message *msg,
474 const char *attr)
476 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
477 int64_t minPwdAge;
479 if (attr_time == 0) {
480 return 0;
483 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
485 /* yes, this is a -= not a += as minPwdAge is stored as the negative
486 of the number of 100-nano-seconds */
487 attr_time -= minPwdAge;
489 return attr_time;
493 construct the force_password_change field from the PwdLastSet attribute and the
494 domain password settings
496 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
497 TALLOC_CTX *mem_ctx,
498 struct ldb_dn *domain_dn,
499 struct ldb_message *msg)
501 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
502 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
503 int64_t maxPwdAge;
505 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
506 return 0x7FFFFFFFFFFFFFFFULL;
509 if (attr_time == 0) {
510 return 0;
513 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
514 if (maxPwdAge == 0) {
515 return 0;
516 } else {
517 attr_time -= maxPwdAge;
520 return attr_time;
524 pull a samr_Password structutre from a result set.
526 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
528 struct samr_Password *hash = NULL;
529 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
530 if (val && (val->length >= sizeof(hash->hash))) {
531 hash = talloc(mem_ctx, struct samr_Password);
532 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
534 return hash;
538 pull an array of samr_Password structutres from a result set.
540 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
541 const char *attr, struct samr_Password **hashes)
543 uint_t count = 0;
544 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
545 int i;
547 *hashes = NULL;
548 if (!val) {
549 return 0;
551 count = val->length / 16;
552 if (count == 0) {
553 return 0;
556 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
557 if (! *hashes) {
558 return 0;
561 for (i=0;i<count;i++) {
562 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
565 return count;
568 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
569 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
571 struct samr_Password *lmPwdHash, *ntPwdHash;
572 if (nt_pwd) {
573 int num_nt;
574 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
575 if (num_nt == 0) {
576 *nt_pwd = NULL;
577 } else if (num_nt > 1) {
578 return NT_STATUS_INTERNAL_DB_CORRUPTION;
579 } else {
580 *nt_pwd = &ntPwdHash[0];
583 if (lm_pwd) {
584 int num_lm;
585 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
586 if (num_lm == 0) {
587 *lm_pwd = NULL;
588 } else if (num_lm > 1) {
589 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590 } else {
591 *lm_pwd = &lmPwdHash[0];
594 return NT_STATUS_OK;
598 pull a samr_LogonHours structutre from a result set.
600 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
602 struct samr_LogonHours hours;
603 const int units_per_week = 168;
604 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
605 ZERO_STRUCT(hours);
606 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
607 if (!hours.bits) {
608 return hours;
610 hours.units_per_week = units_per_week;
611 memset(hours.bits, 0xFF, units_per_week);
612 if (val) {
613 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
615 return hours;
619 pull a set of account_flags from a result set.
621 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
623 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
624 return samdb_uf2acb(userAccountControl);
628 /* Find an attribute, with a particular value */
630 /* The current callers of this function expect a very specific
631 * behaviour: In particular, objectClass subclass equivilance is not
632 * wanted. This means that we should not lookup the schema for the
633 * comparison function */
634 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
635 const struct ldb_message *msg,
636 const char *name, const char *value)
638 int i;
639 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
640 struct ldb_val v;
642 v.data = discard_const_p(uint8_t, value);
643 v.length = strlen(value);
645 if (!el) {
646 return NULL;
649 for (i=0;i<el->num_values;i++) {
650 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
651 return el;
655 return NULL;
658 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
660 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
661 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
663 return LDB_SUCCESS;
666 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
668 struct ldb_message_element *el;
670 el = ldb_msg_find_element(msg, name);
671 if (el) {
672 return LDB_SUCCESS;
675 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
680 copy from a template record to a message
682 int samdb_copy_template(struct ldb_context *ldb,
683 struct ldb_message *msg, const char *filter,
684 const char **errstring)
686 struct ldb_result *res;
687 struct ldb_message *t;
688 int ret, i, j;
689 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
691 *errstring = NULL;
693 /* pull the template record */
694 ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
695 talloc_free(basedn);
696 if (ret != LDB_SUCCESS) {
697 *errstring = talloc_steal(msg, ldb_errstring(ldb));
698 return ret;
700 if (res->count != 1) {
701 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
702 res->count);
703 talloc_free(res);
704 return LDB_ERR_OPERATIONS_ERROR;
706 t = res->msgs[0];
708 for (i = 0; i < t->num_elements; i++) {
709 struct ldb_message_element *el = &t->elements[i];
710 /* some elements should not be copied from the template */
711 if (strcasecmp(el->name, "cn") == 0 ||
712 strcasecmp(el->name, "name") == 0 ||
713 strcasecmp(el->name, "sAMAccountName") == 0 ||
714 strcasecmp(el->name, "sAMAccountName") == 0 ||
715 strcasecmp(el->name, "distinguishedName") == 0 ||
716 strcasecmp(el->name, "objectGUID") == 0) {
717 continue;
719 for (j = 0; j < el->num_values; j++) {
720 if (strcasecmp(el->name, "objectClass") == 0) {
721 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
722 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
723 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
724 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
725 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
726 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
727 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
728 continue;
730 ret = samdb_find_or_add_value(ldb, msg, el->name,
731 (char *)el->values[j].data);
732 if (ret) {
733 *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
734 talloc_free(res);
735 return ret;
737 } else {
738 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
739 (char *)el->values[j].data);
740 if (ret) {
741 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
742 talloc_free(res);
743 return ret;
749 talloc_free(res);
751 return LDB_SUCCESS;
756 add a string element to a message
758 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
759 const char *attr_name, const char *str)
761 char *s = talloc_strdup(mem_ctx, str);
762 char *a = talloc_strdup(mem_ctx, attr_name);
763 if (s == NULL || a == NULL) {
764 return LDB_ERR_OPERATIONS_ERROR;
766 return ldb_msg_add_string(msg, a, s);
770 add a dom_sid element to a message
772 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
773 const char *attr_name, struct dom_sid *sid)
775 struct ldb_val v;
776 NTSTATUS status;
777 status = ndr_push_struct_blob(&v, mem_ctx, sid,
778 (ndr_push_flags_fn_t)ndr_push_dom_sid);
779 if (!NT_STATUS_IS_OK(status)) {
780 return -1;
782 return ldb_msg_add_value(msg, attr_name, &v, NULL);
787 add a delete element operation to a message
789 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
790 const char *attr_name)
792 /* we use an empty replace rather than a delete, as it allows for
793 samdb_replace() to be used everywhere */
794 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
798 add a add attribute value to a message
800 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
801 const char *attr_name, const char *value)
803 struct ldb_message_element *el;
804 char *a, *v;
805 int ret;
806 a = talloc_strdup(mem_ctx, attr_name);
807 if (a == NULL)
808 return -1;
809 v = talloc_strdup(mem_ctx, value);
810 if (v == NULL)
811 return -1;
812 ret = ldb_msg_add_string(msg, a, v);
813 if (ret != 0)
814 return ret;
815 el = ldb_msg_find_element(msg, a);
816 if (el == NULL)
817 return -1;
818 el->flags = LDB_FLAG_MOD_ADD;
819 return 0;
823 add a delete attribute value to a message
825 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
826 const char *attr_name, const char *value)
828 struct ldb_message_element *el;
829 char *a, *v;
830 int ret;
831 a = talloc_strdup(mem_ctx, attr_name);
832 if (a == NULL)
833 return -1;
834 v = talloc_strdup(mem_ctx, value);
835 if (v == NULL)
836 return -1;
837 ret = ldb_msg_add_string(msg, a, v);
838 if (ret != 0)
839 return ret;
840 el = ldb_msg_find_element(msg, a);
841 if (el == NULL)
842 return -1;
843 el->flags = LDB_FLAG_MOD_DELETE;
844 return 0;
848 add a int element to a message
850 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
851 const char *attr_name, int v)
853 const char *s = talloc_asprintf(mem_ctx, "%d", v);
854 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
858 add a uint_t element to a message
860 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
861 const char *attr_name, uint_t v)
863 const char *s = talloc_asprintf(mem_ctx, "%u", v);
864 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
868 add a (signed) int64_t element to a message
870 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
871 const char *attr_name, int64_t v)
873 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
874 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
878 add a uint64_t element to a message
880 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
881 const char *attr_name, uint64_t v)
883 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
884 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
888 add a samr_Password element to a message
890 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
891 const char *attr_name, struct samr_Password *hash)
893 struct ldb_val val;
894 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
895 if (!val.data) {
896 return -1;
898 val.length = 16;
899 return ldb_msg_add_value(msg, attr_name, &val, NULL);
903 add a samr_Password array to a message
905 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
906 const char *attr_name, struct samr_Password *hashes, uint_t count)
908 struct ldb_val val;
909 int i;
910 val.data = talloc_array_size(mem_ctx, 16, count);
911 val.length = count*16;
912 if (!val.data) {
913 return -1;
915 for (i=0;i<count;i++) {
916 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
918 return ldb_msg_add_value(msg, attr_name, &val, NULL);
922 add a acct_flags element to a message
924 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
925 const char *attr_name, uint32_t v)
927 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
931 add a logon_hours element to a message
933 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
934 const char *attr_name, struct samr_LogonHours *hours)
936 struct ldb_val val;
937 val.length = hours->units_per_week / 8;
938 val.data = hours->bits;
939 return ldb_msg_add_value(msg, attr_name, &val, NULL);
943 add a general value element to a message
945 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
946 const char *attr_name, const struct ldb_val *val)
948 return ldb_msg_add_value(msg, attr_name, val, NULL);
952 sets a general value element to a message
954 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
955 const char *attr_name, const struct ldb_val *val)
957 struct ldb_message_element *el;
959 el = ldb_msg_find_element(msg, attr_name);
960 if (el) {
961 el->num_values = 0;
963 return ldb_msg_add_value(msg, attr_name, val, NULL);
967 set a string element in a message
969 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970 const char *attr_name, const char *str)
972 struct ldb_message_element *el;
974 el = ldb_msg_find_element(msg, attr_name);
975 if (el) {
976 el->num_values = 0;
978 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
982 add a record
984 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
986 return ldb_add(sam_ldb, msg);
990 delete a record
992 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
994 return ldb_delete(sam_ldb, dn);
998 modify a record
1000 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1002 return ldb_modify(sam_ldb, msg);
1006 replace elements in a record
1008 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1010 int i;
1012 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1013 for (i=0;i<msg->num_elements;i++) {
1014 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1017 /* modify the samdb record */
1018 return samdb_modify(sam_ldb, mem_ctx, msg);
1022 return a default security descriptor
1024 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1026 struct security_descriptor *sd;
1028 sd = security_descriptor_initialise(mem_ctx);
1030 return sd;
1033 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1035 return ldb_get_default_basedn(sam_ctx);
1038 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1040 return ldb_get_config_basedn(sam_ctx);
1043 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1045 return ldb_get_schema_basedn(sam_ctx);
1048 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1050 return ldb_get_root_basedn(sam_ctx);
1053 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1055 struct ldb_dn *new_dn;
1057 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1058 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1059 talloc_free(new_dn);
1060 return NULL;
1062 return new_dn;
1065 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1067 struct ldb_dn *new_dn;
1069 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1070 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1071 talloc_free(new_dn);
1072 return NULL;
1074 return new_dn;
1078 work out the domain sid for the current open ldb
1080 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1082 TALLOC_CTX *tmp_ctx;
1083 struct dom_sid *domain_sid;
1085 /* see if we have a cached copy */
1086 domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1087 if (domain_sid) {
1088 return domain_sid;
1091 tmp_ctx = talloc_new(ldb);
1092 if (tmp_ctx == NULL) {
1093 goto failed;
1096 /* find the domain_sid */
1097 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1098 "objectSid", "objectClass=domainDNS");
1099 if (domain_sid == NULL) {
1100 goto failed;
1103 /* cache the domain_sid in the ldb */
1104 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1105 goto failed;
1108 talloc_steal(ldb, domain_sid);
1109 talloc_free(tmp_ctx);
1111 return domain_sid;
1113 failed:
1114 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1115 talloc_free(tmp_ctx);
1116 return NULL;
1119 /* Obtain the short name of the flexible single master operator
1120 * (FSMO), such as the PDC Emulator */
1121 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1122 const char *attr)
1124 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1125 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1126 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1127 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1129 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1130 /* Ensure this matches the format. This gives us a
1131 * bit more confidence that a 'cn' value will be a
1132 * ascii string */
1133 return NULL;
1135 if (val) {
1136 return (char *)val->data;
1138 return NULL;
1142 work out the ntds settings dn for the current open ldb
1144 const struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1146 TALLOC_CTX *tmp_ctx;
1147 const char *root_attrs[] = { "dsServiceName", NULL };
1148 int ret;
1149 struct ldb_result *root_res;
1150 struct ldb_dn *settings_dn;
1152 /* see if we have a cached copy */
1153 settings_dn = ldb_get_opaque(ldb, "cache.settings_dn");
1154 if (settings_dn) {
1155 return settings_dn;
1158 tmp_ctx = talloc_new(ldb);
1159 if (tmp_ctx == NULL) {
1160 goto failed;
1164 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1165 if (ret) {
1166 goto failed;
1169 if (root_res->count != 1) {
1170 goto failed;
1173 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1175 /* cache the domain_sid in the ldb */
1176 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1177 goto failed;
1180 talloc_steal(ldb, settings_dn);
1181 talloc_free(tmp_ctx);
1183 return settings_dn;
1185 failed:
1186 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1187 talloc_free(tmp_ctx);
1188 return NULL;
1192 work out the server dn for the current open ldb
1194 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1196 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1200 work out if we are the PDC for the domain of the current open ldb
1202 BOOL samdb_is_pdc(struct ldb_context *ldb)
1204 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1205 int ret;
1206 struct ldb_result *dom_res;
1207 TALLOC_CTX *tmp_ctx;
1208 BOOL is_pdc;
1209 struct ldb_dn *pdc;
1211 tmp_ctx = talloc_new(ldb);
1212 if (tmp_ctx == NULL) {
1213 goto failed;
1216 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1217 if (ret) {
1218 goto failed;
1220 talloc_steal(tmp_ctx, dom_res);
1221 if (dom_res->count != 1) {
1222 goto failed;
1225 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1227 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1228 is_pdc = True;
1229 } else {
1230 is_pdc = False;
1233 talloc_free(tmp_ctx);
1235 return is_pdc;
1237 failed:
1238 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1239 talloc_free(tmp_ctx);
1240 return False;
1244 /* Find a domain object in the parents of a particular DN. */
1245 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1247 TALLOC_CTX *local_ctx;
1248 struct ldb_dn *sdn = dn;
1249 struct ldb_result *res = NULL;
1250 int ret = 0;
1251 const char *attrs[] = { NULL };
1253 local_ctx = talloc_new(mem_ctx);
1254 if (local_ctx == NULL) return NULL;
1256 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1257 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1258 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1259 if (ret == LDB_SUCCESS) {
1260 talloc_steal(local_ctx, res);
1261 if (res->count == 1) {
1262 break;
1267 if (ret != LDB_SUCCESS || res->count != 1) {
1268 talloc_free(local_ctx);
1269 return NULL;
1272 talloc_steal(mem_ctx, sdn);
1273 talloc_free(local_ctx);
1275 return sdn;
1279 check that a password is sufficiently complex
1281 static BOOL samdb_password_complexity_ok(const char *pass)
1283 return check_password_quality(pass);
1289 set the user password using plaintext, obeying any user or domain
1290 password restrictions
1292 note that this function doesn't actually store the result in the
1293 database, it just fills in the "mod" structure with ldb modify
1294 elements to setup the correct change when samdb_replace() is
1295 called. This allows the caller to combine the change with other
1296 changes (as is needed by some of the set user info levels)
1298 The caller should probably have a transaction wrapping this
1300 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1301 struct ldb_dn *user_dn,
1302 struct ldb_dn *domain_dn,
1303 struct ldb_message *mod,
1304 const char *new_pass,
1305 struct samr_Password *lmNewHash,
1306 struct samr_Password *ntNewHash,
1307 BOOL user_change,
1308 BOOL restrictions,
1309 enum samr_RejectReason *reject_reason,
1310 struct samr_DomInfo1 **_dominfo)
1312 const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory",
1313 "sambaNTPwdHistory",
1314 "lmPwdHash", "ntPwdHash",
1315 "objectSid",
1316 "pwdLastSet", NULL };
1317 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1318 "maxPwdAge", "minPwdAge",
1319 "minPwdLength", NULL };
1320 NTTIME pwdLastSet;
1321 int64_t minPwdAge;
1322 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1323 uint_t userAccountControl;
1324 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1325 struct samr_Password local_lmNewHash, local_ntNewHash;
1326 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1327 struct dom_sid *domain_sid;
1328 struct ldb_message **res;
1329 int count;
1330 time_t now = time(NULL);
1331 NTTIME now_nt;
1332 int i;
1334 /* we need to know the time to compute password age */
1335 unix_to_nt_time(&now_nt, now);
1337 /* pull all the user parameters */
1338 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1339 if (count != 1) {
1340 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1342 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1343 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1344 "sambaLMPwdHistory", &sambaLMPwdHistory);
1345 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1346 "sambaNTPwdHistory", &sambaNTPwdHistory);
1347 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "lmPwdHash");
1348 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "ntPwdHash");
1349 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1351 if (domain_dn) {
1352 /* pull the domain parameters */
1353 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1354 if (count != 1) {
1355 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1356 ldb_dn_get_linearized(domain_dn),
1357 ldb_dn_get_linearized(user_dn)));
1358 return NT_STATUS_NO_SUCH_DOMAIN;
1360 } else {
1361 /* work out the domain sid, and pull the domain from there */
1362 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1363 if (domain_sid == NULL) {
1364 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1367 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1368 "(objectSid=%s)",
1369 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1370 if (count != 1) {
1371 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1372 dom_sid_string(mem_ctx, domain_sid),
1373 ldb_dn_get_linearized(user_dn)));
1374 return NT_STATUS_NO_SUCH_DOMAIN;
1378 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1379 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1380 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1381 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1383 if (_dominfo) {
1384 struct samr_DomInfo1 *dominfo;
1385 /* on failure we need to fill in the reject reasons */
1386 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1387 if (dominfo == NULL) {
1388 return NT_STATUS_NO_MEMORY;
1390 dominfo->min_password_length = minPwdLength;
1391 dominfo->password_properties = pwdProperties;
1392 dominfo->password_history_length = pwdHistoryLength;
1393 dominfo->max_password_age = minPwdAge;
1394 dominfo->min_password_age = minPwdAge;
1395 *_dominfo = dominfo;
1398 if (new_pass) {
1399 /* check the various password restrictions */
1400 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1401 if (reject_reason) {
1402 *reject_reason = SAMR_REJECT_TOO_SHORT;
1404 return NT_STATUS_PASSWORD_RESTRICTION;
1407 /* possibly check password complexity */
1408 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1409 !samdb_password_complexity_ok(new_pass)) {
1410 if (reject_reason) {
1411 *reject_reason = SAMR_REJECT_COMPLEXITY;
1413 return NT_STATUS_PASSWORD_RESTRICTION;
1416 /* compute the new nt and lm hashes */
1417 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1418 lmNewHash = &local_lmNewHash;
1420 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1421 /* If we can't convert this password to UCS2, then we should not accept it */
1422 if (reject_reason) {
1423 *reject_reason = SAMR_REJECT_OTHER;
1425 return NT_STATUS_PASSWORD_RESTRICTION;
1427 ntNewHash = &local_ntNewHash;
1430 if (restrictions && user_change) {
1431 /* are all password changes disallowed? */
1432 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1433 if (reject_reason) {
1434 *reject_reason = SAMR_REJECT_OTHER;
1436 return NT_STATUS_PASSWORD_RESTRICTION;
1439 /* can this user change password? */
1440 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1441 if (reject_reason) {
1442 *reject_reason = SAMR_REJECT_OTHER;
1444 return NT_STATUS_PASSWORD_RESTRICTION;
1447 /* yes, this is a minus. The ages are in negative 100nsec units! */
1448 if (pwdLastSet - minPwdAge > now_nt) {
1449 if (reject_reason) {
1450 *reject_reason = SAMR_REJECT_OTHER;
1452 return NT_STATUS_PASSWORD_RESTRICTION;
1455 /* check the immediately past password */
1456 if (pwdHistoryLength > 0) {
1457 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1458 if (reject_reason) {
1459 *reject_reason = SAMR_REJECT_IN_HISTORY;
1461 return NT_STATUS_PASSWORD_RESTRICTION;
1463 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1464 if (reject_reason) {
1465 *reject_reason = SAMR_REJECT_IN_HISTORY;
1467 return NT_STATUS_PASSWORD_RESTRICTION;
1471 /* check the password history */
1472 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1473 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1475 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1476 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1477 if (reject_reason) {
1478 *reject_reason = SAMR_REJECT_IN_HISTORY;
1480 return NT_STATUS_PASSWORD_RESTRICTION;
1483 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1484 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1485 if (reject_reason) {
1486 *reject_reason = SAMR_REJECT_IN_HISTORY;
1488 return NT_STATUS_PASSWORD_RESTRICTION;
1493 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1495 /* the password is acceptable. Start forming the new fields */
1496 if (new_pass) {
1497 /* if we know the cleartext, then only set it.
1498 * Modules in ldb will set all the appropriate
1499 * hashes */
1500 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1501 "sambaPassword", new_pass));
1502 } else {
1503 /* We don't have the cleartext, so delete the old one
1504 * and set what we have of the hashes */
1505 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1507 if (lmNewHash) {
1508 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1509 } else {
1510 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1513 if (ntNewHash) {
1514 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1515 } else {
1516 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1520 return NT_STATUS_OK;
1525 set the user password using plaintext, obeying any user or domain
1526 password restrictions
1528 This wrapper function takes a SID as input, rather than a user DN,
1529 and actually performs the password change
1532 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1533 const struct dom_sid *user_sid,
1534 const char *new_pass,
1535 struct samr_Password *lmNewHash,
1536 struct samr_Password *ntNewHash,
1537 BOOL user_change,
1538 BOOL restrictions,
1539 enum samr_RejectReason *reject_reason,
1540 struct samr_DomInfo1 **_dominfo)
1542 NTSTATUS nt_status;
1543 struct ldb_dn *user_dn;
1544 struct ldb_message *msg;
1545 int ret;
1547 ret = ldb_transaction_start(ctx);
1548 if (ret) {
1549 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1550 return NT_STATUS_TRANSACTION_ABORTED;
1553 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1554 "(&(objectSid=%s)(objectClass=user))",
1555 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1556 if (!user_dn) {
1557 ldb_transaction_cancel(ctx);
1558 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1559 dom_sid_string(mem_ctx, user_sid)));
1560 return NT_STATUS_NO_SUCH_USER;
1563 msg = ldb_msg_new(mem_ctx);
1564 if (msg == NULL) {
1565 ldb_transaction_cancel(ctx);
1566 return NT_STATUS_NO_MEMORY;
1569 msg->dn = ldb_dn_copy(msg, user_dn);
1570 if (!msg->dn) {
1571 ldb_transaction_cancel(ctx);
1572 return NT_STATUS_NO_MEMORY;
1575 nt_status = samdb_set_password(ctx, mem_ctx,
1576 user_dn, NULL,
1577 msg, new_pass,
1578 lmNewHash, ntNewHash,
1579 user_change, /* This is a password set, not change */
1580 restrictions, /* run restriction tests */
1581 reject_reason, _dominfo);
1582 if (!NT_STATUS_IS_OK(nt_status)) {
1583 ldb_transaction_cancel(ctx);
1584 return nt_status;
1587 /* modify the samdb record */
1588 ret = samdb_replace(ctx, mem_ctx, msg);
1589 if (ret != 0) {
1590 ldb_transaction_cancel(ctx);
1591 return NT_STATUS_ACCESS_DENIED;
1594 ret = ldb_transaction_commit(ctx);
1595 if (ret != 0) {
1596 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1597 ldb_dn_get_linearized(msg->dn),
1598 ldb_errstring(ctx)));
1599 return NT_STATUS_TRANSACTION_ABORTED;
1601 return NT_STATUS_OK;
1604 /****************************************************************************
1605 Create the SID list for this user.
1606 ****************************************************************************/
1607 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1608 struct dom_sid *user_sid,
1609 struct dom_sid *group_sid,
1610 int n_groupSIDs,
1611 struct dom_sid **groupSIDs,
1612 BOOL is_authenticated,
1613 struct security_token **token)
1615 struct security_token *ptoken;
1616 int i;
1617 NTSTATUS status;
1619 ptoken = security_token_initialise(mem_ctx);
1620 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1622 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1623 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1625 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1626 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1627 ptoken->privilege_mask = 0;
1629 ptoken->sids[0] = ptoken->user_sid;
1630 ptoken->sids[1] = ptoken->group_sid;
1633 * Finally add the "standard" SIDs.
1634 * The only difference between guest and "anonymous"
1635 * is the addition of Authenticated_Users.
1637 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1638 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1639 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1640 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1641 ptoken->num_sids = 4;
1643 if (is_authenticated) {
1644 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1645 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1646 ptoken->num_sids++;
1649 for (i = 0; i < n_groupSIDs; i++) {
1650 size_t check_sid_idx;
1651 for (check_sid_idx = 1;
1652 check_sid_idx < ptoken->num_sids;
1653 check_sid_idx++) {
1654 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1655 break;
1659 if (check_sid_idx == ptoken->num_sids) {
1660 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1664 /* setup the privilege mask for this token */
1665 status = samdb_privilege_setup(ptoken);
1666 if (!NT_STATUS_IS_OK(status)) {
1667 talloc_free(ptoken);
1668 return status;
1671 security_token_debug(10, ptoken);
1673 *token = ptoken;
1675 return NT_STATUS_OK;
1679 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1680 struct dom_sid *sid, struct ldb_dn **ret_dn)
1682 struct ldb_message *msg;
1683 struct ldb_dn *basedn;
1684 const char *sidstr;
1685 int ret;
1687 sidstr = dom_sid_string(mem_ctx, sid);
1688 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1690 /* We might have to create a ForeignSecurityPrincipal, even if this user
1691 * is in our own domain */
1693 msg = ldb_msg_new(mem_ctx);
1694 if (msg == NULL) {
1695 return NT_STATUS_NO_MEMORY;
1698 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1699 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1700 * not work, this is wrong for the Builtin domain, there's no
1701 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1704 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1705 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1707 if (basedn == NULL) {
1708 DEBUG(0, ("Failed to find DN for "
1709 "ForeignSecurityPrincipal container\n"));
1710 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1713 /* add core elements to the ldb_message for the alias */
1714 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1715 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1716 return NT_STATUS_NO_MEMORY;
1718 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1719 "objectClass",
1720 "foreignSecurityPrincipal");
1722 /* create the alias */
1723 ret = samdb_add(sam_ctx, mem_ctx, msg);
1724 if (ret != 0) {
1725 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1726 "record %s: %s\n",
1727 ldb_dn_get_linearized(msg->dn),
1728 ldb_errstring(sam_ctx)));
1729 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1731 *ret_dn = msg->dn;
1732 return NT_STATUS_OK;
1737 Find the DN of a domain, assuming it to be a dotted.dns name
1740 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1742 int i;
1743 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1744 const char *binary_encoded;
1745 const char **split_realm;
1746 struct ldb_dn *dn;
1748 if (!tmp_ctx) {
1749 return NULL;
1752 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1753 if (!split_realm) {
1754 talloc_free(tmp_ctx);
1755 return NULL;
1757 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1758 for (i=0; split_realm[i]; i++) {
1759 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1760 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1761 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1762 binary_encoded, ldb_dn_get_linearized(dn)));
1763 talloc_free(tmp_ctx);
1764 return NULL;
1767 if (!ldb_dn_validate(dn)) {
1768 DEBUG(2, ("Failed to validated DN %s\n",
1769 ldb_dn_get_linearized(dn)));
1770 return NULL;
1772 return dn;
1775 Find the DN of a domain, be it the netbios or DNS name
1778 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1779 const char *domain_name)
1781 const char * const domain_ref_attrs[] = {
1782 "ncName", NULL
1784 const char * const domain_ref2_attrs[] = {
1785 NULL
1787 struct ldb_result *res_domain_ref;
1788 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1789 /* find the domain's DN */
1790 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1791 &res_domain_ref,
1792 samdb_partitions_dn(ldb, mem_ctx),
1793 LDB_SCOPE_ONELEVEL,
1794 domain_ref_attrs,
1795 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1796 escaped_domain);
1797 if (ret_domain != 0) {
1798 return NULL;
1801 if (res_domain_ref->count == 0) {
1802 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1803 &res_domain_ref,
1804 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1805 LDB_SCOPE_BASE,
1806 domain_ref2_attrs,
1807 "(objectclass=domain)");
1808 if (ret_domain != 0) {
1809 return NULL;
1812 if (res_domain_ref->count == 1) {
1813 return res_domain_ref->msgs[0]->dn;
1815 return NULL;
1818 if (res_domain_ref->count > 1) {
1819 DEBUG(0,("Found %d records matching domain [%s]\n",
1820 ret_domain, domain_name));
1821 return NULL;
1824 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);