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.
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"
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,
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,
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)
72 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73 res, attrs, format, ap);
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];
88 talloc_free(entry_sid);
91 talloc_free(entry_sid);
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,
103 struct ldb_dn *basedn,
104 const char *attr_name,
105 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
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);
115 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
116 attr_name, format, count));
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,
132 struct ldb_dn *basedn,
133 const char *attr_name,
134 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
139 va_start(ap, format);
140 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
148 struct ldb_dn *basedn,
149 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
153 struct ldb_message **res = NULL;
156 va_start(ap, format);
157 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
160 if (count != 1) return NULL;
162 ret = talloc_steal(mem_ctx, res[0]->dn);
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,
173 struct ldb_dn *basedn,
174 const char *attr_name,
175 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
179 struct ldb_message **res;
180 const char *attrs[2] = { NULL, NULL };
183 attrs[0] = attr_name;
185 va_start(ap, format);
186 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
189 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
190 attr_name, format, count));
196 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
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,
206 struct ldb_dn *basedn,
207 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
210 struct ldb_message **res;
211 const char * const attrs[] = { NULL };
214 va_start(ap, format);
215 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
223 search the sam for a single integer attribute in exactly 1 record
225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
227 uint_t default_value,
228 struct ldb_dn *basedn,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
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);
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,
255 int64_t default_value,
256 struct ldb_dn *basedn,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
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);
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,
284 struct ldb_dn *basedn,
286 const char *attr_name,
287 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
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);
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",
314 *strs = talloc_array(mem_ctx, const char *, count+1);
320 for (i=0;i<count;i++) {
321 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
323 (*strs)[count] = NULL;
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);
358 return default_value;
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)
372 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
374 return default_value;
376 rid = sid->sub_auths[sid->num_auths-1];
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,
387 const struct ldb_val *v;
390 v = ldb_msg_find_ldb_val(msg, attr);
394 sid = talloc(mem_ctx, struct dom_sid);
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)) {
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;
419 v = ldb_msg_find_ldb_val(msg, attr);
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)) {
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,
441 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
442 if (!sid || sid->num_auths < 1) return NULL;
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,
472 struct ldb_dn *domain_dn,
473 struct ldb_message *msg,
476 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
479 if (attr_time == 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;
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,
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);
505 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
506 return 0x7FFFFFFFFFFFFFFFULL;
509 if (attr_time == 0) {
513 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
514 if (maxPwdAge == 0) {
517 attr_time -= maxPwdAge;
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)));
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)
544 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
551 count = val->length / 16;
556 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
561 for (i=0;i<count;i++) {
562 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
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;
574 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
577 } else if (num_nt > 1) {
578 return NT_STATUS_INTERNAL_DB_CORRUPTION;
580 *nt_pwd = &ntPwdHash[0];
585 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
588 } else if (num_lm > 1) {
589 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591 *lm_pwd = &lmPwdHash[0];
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);
606 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
610 hours.units_per_week = units_per_week;
611 memset(hours.bits, 0xFF, units_per_week);
613 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
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 */
629 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
630 const struct ldb_message *msg,
631 const char *name, const char *value)
634 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
637 v.data = discard_const_p(uint8_t, value);
638 v.length = strlen(value);
644 for (i=0;i<el->num_values;i++) {
645 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
653 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
655 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
656 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
661 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
663 struct ldb_message_element *el;
665 el = ldb_msg_find_element(msg, name);
670 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
675 copy from a template record to a message
677 int samdb_copy_template(struct ldb_context *ldb,
678 struct ldb_message *msg, const char *filter,
679 const char **errstring)
681 struct ldb_result *res;
682 struct ldb_message *t;
684 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
688 /* pull the template record */
689 ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
691 if (ret != LDB_SUCCESS) {
692 *errstring = talloc_steal(msg, ldb_errstring(ldb));
695 if (res->count != 1) {
696 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
699 return LDB_ERR_OPERATIONS_ERROR;
703 for (i = 0; i < t->num_elements; i++) {
704 struct ldb_message_element *el = &t->elements[i];
705 /* some elements should not be copied from the template */
706 if (strcasecmp(el->name, "cn") == 0 ||
707 strcasecmp(el->name, "name") == 0 ||
708 strcasecmp(el->name, "sAMAccountName") == 0 ||
709 strcasecmp(el->name, "sAMAccountName") == 0 ||
710 strcasecmp(el->name, "distinguishedName") == 0 ||
711 strcasecmp(el->name, "objectGUID") == 0) {
714 for (j = 0; j < el->num_values; j++) {
715 if (strcasecmp(el->name, "objectClass") == 0) {
716 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
717 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
718 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
719 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
720 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
721 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
722 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
725 ret = samdb_find_or_add_value(ldb, msg, el->name,
726 (char *)el->values[j].data);
728 *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
733 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
734 (char *)el->values[j].data);
736 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
751 add a string element to a message
753 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
754 const char *attr_name, const char *str)
756 char *s = talloc_strdup(mem_ctx, str);
757 char *a = talloc_strdup(mem_ctx, attr_name);
758 if (s == NULL || a == NULL) {
759 return LDB_ERR_OPERATIONS_ERROR;
761 return ldb_msg_add_string(msg, a, s);
765 add a dom_sid element to a message
767 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
768 const char *attr_name, struct dom_sid *sid)
772 status = ndr_push_struct_blob(&v, mem_ctx, sid,
773 (ndr_push_flags_fn_t)ndr_push_dom_sid);
774 if (!NT_STATUS_IS_OK(status)) {
777 return ldb_msg_add_value(msg, attr_name, &v, NULL);
782 add a delete element operation to a message
784 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name)
787 /* we use an empty replace rather than a delete, as it allows for
788 samdb_replace() to be used everywhere */
789 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
793 add a add attribute value to a message
795 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
796 const char *attr_name, const char *value)
798 struct ldb_message_element *el;
801 a = talloc_strdup(mem_ctx, attr_name);
804 v = talloc_strdup(mem_ctx, value);
807 ret = ldb_msg_add_string(msg, a, v);
810 el = ldb_msg_find_element(msg, a);
813 el->flags = LDB_FLAG_MOD_ADD;
818 add a delete attribute value to a message
820 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
821 const char *attr_name, const char *value)
823 struct ldb_message_element *el;
826 a = talloc_strdup(mem_ctx, attr_name);
829 v = talloc_strdup(mem_ctx, value);
832 ret = ldb_msg_add_string(msg, a, v);
835 el = ldb_msg_find_element(msg, a);
838 el->flags = LDB_FLAG_MOD_DELETE;
843 add a int element to a message
845 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846 const char *attr_name, int v)
848 const char *s = talloc_asprintf(mem_ctx, "%d", v);
849 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
853 add a uint_t element to a message
855 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
856 const char *attr_name, uint_t v)
858 const char *s = talloc_asprintf(mem_ctx, "%u", v);
859 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
863 add a (signed) int64_t element to a message
865 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866 const char *attr_name, int64_t v)
868 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
869 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
873 add a uint64_t element to a message
875 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876 const char *attr_name, uint64_t v)
878 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
879 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
883 add a samr_Password element to a message
885 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
886 const char *attr_name, struct samr_Password *hash)
889 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
894 return ldb_msg_add_value(msg, attr_name, &val, NULL);
898 add a samr_Password array to a message
900 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
901 const char *attr_name, struct samr_Password *hashes, uint_t count)
905 val.data = talloc_array_size(mem_ctx, 16, count);
906 val.length = count*16;
910 for (i=0;i<count;i++) {
911 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
913 return ldb_msg_add_value(msg, attr_name, &val, NULL);
917 add a acct_flags element to a message
919 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
920 const char *attr_name, uint32_t v)
922 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
926 add a logon_hours element to a message
928 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
929 const char *attr_name, struct samr_LogonHours *hours)
932 val.length = hours->units_per_week / 8;
933 val.data = hours->bits;
934 return ldb_msg_add_value(msg, attr_name, &val, NULL);
938 add a general value element to a message
940 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
941 const char *attr_name, const struct ldb_val *val)
943 return ldb_msg_add_value(msg, attr_name, val, NULL);
947 sets a general value element to a message
949 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
950 const char *attr_name, const struct ldb_val *val)
952 struct ldb_message_element *el;
954 el = ldb_msg_find_element(msg, attr_name);
958 return ldb_msg_add_value(msg, attr_name, val, NULL);
962 set a string element in a message
964 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
965 const char *attr_name, const char *str)
967 struct ldb_message_element *el;
969 el = ldb_msg_find_element(msg, attr_name);
973 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
979 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
981 return ldb_add(sam_ldb, msg);
987 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
989 return ldb_delete(sam_ldb, dn);
995 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
997 return ldb_modify(sam_ldb, msg);
1001 replace elements in a record
1003 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1007 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1008 for (i=0;i<msg->num_elements;i++) {
1009 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1012 /* modify the samdb record */
1013 return samdb_modify(sam_ldb, mem_ctx, msg);
1017 return a default security descriptor
1019 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1021 struct security_descriptor *sd;
1023 sd = security_descriptor_initialise(mem_ctx);
1028 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1030 return ldb_get_default_basedn(sam_ctx);
1033 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1035 return ldb_get_config_basedn(sam_ctx);
1038 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1040 return ldb_get_schema_basedn(sam_ctx);
1043 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1045 return ldb_get_root_basedn(sam_ctx);
1048 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1050 struct ldb_dn *new_dn;
1052 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1053 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1054 talloc_free(new_dn);
1060 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1062 struct ldb_dn *new_dn;
1064 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1065 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1066 talloc_free(new_dn);
1073 work out the domain sid for the current open ldb
1075 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1077 TALLOC_CTX *tmp_ctx;
1078 struct dom_sid *domain_sid;
1080 /* see if we have a cached copy */
1081 domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1086 tmp_ctx = talloc_new(ldb);
1087 if (tmp_ctx == NULL) {
1091 /* find the domain_sid */
1092 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb),
1093 "objectSid", "objectClass=domainDNS");
1094 if (domain_sid == NULL) {
1098 /* cache the domain_sid in the ldb */
1099 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1103 talloc_steal(ldb, domain_sid);
1104 talloc_free(tmp_ctx);
1109 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1110 talloc_free(tmp_ctx);
1114 /* Obtain the short name of the flexible single master operator
1115 * (FSMO), such as the PDC Emulator */
1116 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1119 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1120 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1121 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1122 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1124 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1125 /* Ensure this matches the format. This gives us a
1126 * bit more confidence that a 'cn' value will be a
1131 return (char *)val->data;
1137 work out the ntds settings dn for the current open ldb
1139 const struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1141 TALLOC_CTX *tmp_ctx;
1142 const char *root_attrs[] = { "dsServiceName", NULL };
1144 struct ldb_result *root_res;
1145 struct ldb_dn *settings_dn;
1147 /* see if we have a cached copy */
1148 settings_dn = ldb_get_opaque(ldb, "cache.settings_dn");
1153 tmp_ctx = talloc_new(ldb);
1154 if (tmp_ctx == NULL) {
1159 ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res);
1164 if (root_res->count != 1) {
1168 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1170 /* cache the domain_sid in the ldb */
1171 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1175 talloc_steal(ldb, settings_dn);
1176 talloc_free(tmp_ctx);
1181 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1182 talloc_free(tmp_ctx);
1187 work out the server dn for the current open ldb
1189 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1191 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1195 work out if we are the PDC for the domain of the current open ldb
1197 BOOL samdb_is_pdc(struct ldb_context *ldb)
1199 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1201 struct ldb_result *dom_res;
1202 TALLOC_CTX *tmp_ctx;
1206 tmp_ctx = talloc_new(ldb);
1207 if (tmp_ctx == NULL) {
1211 ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res);
1215 talloc_steal(tmp_ctx, dom_res);
1216 if (dom_res->count != 1) {
1220 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1222 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1228 talloc_free(tmp_ctx);
1233 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1234 talloc_free(tmp_ctx);
1239 /* Find a domain object in the parents of a particular DN. */
1240 struct ldb_dn *samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
1242 TALLOC_CTX *local_ctx;
1243 struct ldb_dn *sdn = dn;
1244 struct ldb_result *res = NULL;
1246 const char *attrs[] = { NULL };
1248 local_ctx = talloc_new(mem_ctx);
1249 if (local_ctx == NULL) return NULL;
1251 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1252 ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE,
1253 "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res);
1254 if (ret == LDB_SUCCESS) {
1255 talloc_steal(local_ctx, res);
1256 if (res->count == 1) {
1262 if (ret != LDB_SUCCESS || res->count != 1) {
1263 talloc_free(local_ctx);
1267 talloc_steal(mem_ctx, sdn);
1268 talloc_free(local_ctx);
1274 check that a password is sufficiently complex
1276 static BOOL samdb_password_complexity_ok(const char *pass)
1278 return check_password_quality(pass);
1284 set the user password using plaintext, obeying any user or domain
1285 password restrictions
1287 note that this function doesn't actually store the result in the
1288 database, it just fills in the "mod" structure with ldb modify
1289 elements to setup the correct change when samdb_replace() is
1290 called. This allows the caller to combine the change with other
1291 changes (as is needed by some of the set user info levels)
1293 The caller should probably have a transaction wrapping this
1295 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1296 struct ldb_dn *user_dn,
1297 struct ldb_dn *domain_dn,
1298 struct ldb_message *mod,
1299 const char *new_pass,
1300 struct samr_Password *lmNewHash,
1301 struct samr_Password *ntNewHash,
1304 enum samr_RejectReason *reject_reason,
1305 struct samr_DomInfo1 **_dominfo)
1307 const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory",
1308 "sambaNTPwdHistory",
1309 "lmPwdHash", "ntPwdHash",
1311 "pwdLastSet", NULL };
1312 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1313 "maxPwdAge", "minPwdAge",
1314 "minPwdLength", NULL };
1317 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1318 uint_t userAccountControl;
1319 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1320 struct samr_Password local_lmNewHash, local_ntNewHash;
1321 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1322 struct dom_sid *domain_sid;
1323 struct ldb_message **res;
1325 time_t now = time(NULL);
1329 /* we need to know the time to compute password age */
1330 unix_to_nt_time(&now_nt, now);
1332 /* pull all the user parameters */
1333 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1335 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1337 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1338 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1339 "sambaLMPwdHistory", &sambaLMPwdHistory);
1340 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1341 "sambaNTPwdHistory", &sambaNTPwdHistory);
1342 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "lmPwdHash");
1343 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "ntPwdHash");
1344 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1347 /* pull the domain parameters */
1348 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1350 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1351 ldb_dn_get_linearized(domain_dn),
1352 ldb_dn_get_linearized(user_dn)));
1353 return NT_STATUS_NO_SUCH_DOMAIN;
1356 /* work out the domain sid, and pull the domain from there */
1357 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1358 if (domain_sid == NULL) {
1359 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1362 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1364 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1366 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1367 dom_sid_string(mem_ctx, domain_sid),
1368 ldb_dn_get_linearized(user_dn)));
1369 return NT_STATUS_NO_SUCH_DOMAIN;
1373 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1374 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1375 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1376 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1379 struct samr_DomInfo1 *dominfo;
1380 /* on failure we need to fill in the reject reasons */
1381 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1382 if (dominfo == NULL) {
1383 return NT_STATUS_NO_MEMORY;
1385 dominfo->min_password_length = minPwdLength;
1386 dominfo->password_properties = pwdProperties;
1387 dominfo->password_history_length = pwdHistoryLength;
1388 dominfo->max_password_age = minPwdAge;
1389 dominfo->min_password_age = minPwdAge;
1390 *_dominfo = dominfo;
1394 /* check the various password restrictions */
1395 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1396 if (reject_reason) {
1397 *reject_reason = SAMR_REJECT_TOO_SHORT;
1399 return NT_STATUS_PASSWORD_RESTRICTION;
1402 /* possibly check password complexity */
1403 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1404 !samdb_password_complexity_ok(new_pass)) {
1405 if (reject_reason) {
1406 *reject_reason = SAMR_REJECT_COMPLEXITY;
1408 return NT_STATUS_PASSWORD_RESTRICTION;
1411 /* compute the new nt and lm hashes */
1412 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1413 lmNewHash = &local_lmNewHash;
1415 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1416 /* If we can't convert this password to UCS2, then we should not accept it */
1417 if (reject_reason) {
1418 *reject_reason = SAMR_REJECT_OTHER;
1420 return NT_STATUS_PASSWORD_RESTRICTION;
1422 ntNewHash = &local_ntNewHash;
1425 if (restrictions && user_change) {
1426 /* are all password changes disallowed? */
1427 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1428 if (reject_reason) {
1429 *reject_reason = SAMR_REJECT_OTHER;
1431 return NT_STATUS_PASSWORD_RESTRICTION;
1434 /* can this user change password? */
1435 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1436 if (reject_reason) {
1437 *reject_reason = SAMR_REJECT_OTHER;
1439 return NT_STATUS_PASSWORD_RESTRICTION;
1442 /* yes, this is a minus. The ages are in negative 100nsec units! */
1443 if (pwdLastSet - minPwdAge > now_nt) {
1444 if (reject_reason) {
1445 *reject_reason = SAMR_REJECT_OTHER;
1447 return NT_STATUS_PASSWORD_RESTRICTION;
1450 /* check the immediately past password */
1451 if (pwdHistoryLength > 0) {
1452 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1453 if (reject_reason) {
1454 *reject_reason = SAMR_REJECT_IN_HISTORY;
1456 return NT_STATUS_PASSWORD_RESTRICTION;
1458 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1459 if (reject_reason) {
1460 *reject_reason = SAMR_REJECT_IN_HISTORY;
1462 return NT_STATUS_PASSWORD_RESTRICTION;
1466 /* check the password history */
1467 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1468 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1470 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1471 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1472 if (reject_reason) {
1473 *reject_reason = SAMR_REJECT_IN_HISTORY;
1475 return NT_STATUS_PASSWORD_RESTRICTION;
1478 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1479 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1480 if (reject_reason) {
1481 *reject_reason = SAMR_REJECT_IN_HISTORY;
1483 return NT_STATUS_PASSWORD_RESTRICTION;
1488 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1490 /* the password is acceptable. Start forming the new fields */
1492 /* if we know the cleartext, then only set it.
1493 * Modules in ldb will set all the appropriate
1495 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1496 "sambaPassword", new_pass));
1498 /* We don't have the cleartext, so delete the old one
1499 * and set what we have of the hashes */
1500 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1503 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1505 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1509 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1511 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1515 return NT_STATUS_OK;
1520 set the user password using plaintext, obeying any user or domain
1521 password restrictions
1523 This wrapper function takes a SID as input, rather than a user DN,
1524 and actually performs the password change
1527 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1528 const struct dom_sid *user_sid,
1529 const char *new_pass,
1530 struct samr_Password *lmNewHash,
1531 struct samr_Password *ntNewHash,
1534 enum samr_RejectReason *reject_reason,
1535 struct samr_DomInfo1 **_dominfo)
1538 struct ldb_dn *user_dn;
1539 struct ldb_message *msg;
1542 ret = ldb_transaction_start(ctx);
1544 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1545 return NT_STATUS_TRANSACTION_ABORTED;
1548 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1549 "(&(objectSid=%s)(objectClass=user))",
1550 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1552 ldb_transaction_cancel(ctx);
1553 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1554 dom_sid_string(mem_ctx, user_sid)));
1555 return NT_STATUS_NO_SUCH_USER;
1558 msg = ldb_msg_new(mem_ctx);
1560 ldb_transaction_cancel(ctx);
1561 return NT_STATUS_NO_MEMORY;
1564 msg->dn = ldb_dn_copy(msg, user_dn);
1566 ldb_transaction_cancel(ctx);
1567 return NT_STATUS_NO_MEMORY;
1570 nt_status = samdb_set_password(ctx, mem_ctx,
1573 lmNewHash, ntNewHash,
1574 user_change, /* This is a password set, not change */
1575 restrictions, /* run restriction tests */
1576 reject_reason, _dominfo);
1577 if (!NT_STATUS_IS_OK(nt_status)) {
1578 ldb_transaction_cancel(ctx);
1582 /* modify the samdb record */
1583 ret = samdb_replace(ctx, mem_ctx, msg);
1585 ldb_transaction_cancel(ctx);
1586 return NT_STATUS_ACCESS_DENIED;
1589 ret = ldb_transaction_commit(ctx);
1591 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1592 ldb_dn_get_linearized(msg->dn),
1593 ldb_errstring(ctx)));
1594 return NT_STATUS_TRANSACTION_ABORTED;
1596 return NT_STATUS_OK;
1599 /****************************************************************************
1600 Create the SID list for this user.
1601 ****************************************************************************/
1602 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1603 struct dom_sid *user_sid,
1604 struct dom_sid *group_sid,
1606 struct dom_sid **groupSIDs,
1607 BOOL is_authenticated,
1608 struct security_token **token)
1610 struct security_token *ptoken;
1614 ptoken = security_token_initialise(mem_ctx);
1615 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1617 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1618 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1620 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1621 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1622 ptoken->privilege_mask = 0;
1624 ptoken->sids[0] = ptoken->user_sid;
1625 ptoken->sids[1] = ptoken->group_sid;
1628 * Finally add the "standard" SIDs.
1629 * The only difference between guest and "anonymous"
1630 * is the addition of Authenticated_Users.
1632 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1633 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1634 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1635 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1636 ptoken->num_sids = 4;
1638 if (is_authenticated) {
1639 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1640 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1644 for (i = 0; i < n_groupSIDs; i++) {
1645 size_t check_sid_idx;
1646 for (check_sid_idx = 1;
1647 check_sid_idx < ptoken->num_sids;
1649 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1654 if (check_sid_idx == ptoken->num_sids) {
1655 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1659 /* setup the privilege mask for this token */
1660 status = samdb_privilege_setup(ptoken);
1661 if (!NT_STATUS_IS_OK(status)) {
1662 talloc_free(ptoken);
1666 security_token_debug(10, ptoken);
1670 return NT_STATUS_OK;
1674 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1675 struct dom_sid *sid, struct ldb_dn **ret_dn)
1677 struct ldb_message *msg;
1678 struct ldb_dn *basedn;
1682 sidstr = dom_sid_string(mem_ctx, sid);
1683 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1685 /* We might have to create a ForeignSecurityPrincipal, even if this user
1686 * is in our own domain */
1688 msg = ldb_msg_new(mem_ctx);
1690 return NT_STATUS_NO_MEMORY;
1693 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1694 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1695 * not work, this is wrong for the Builtin domain, there's no
1696 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1699 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1700 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1702 if (basedn == NULL) {
1703 DEBUG(0, ("Failed to find DN for "
1704 "ForeignSecurityPrincipal container\n"));
1705 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1708 /* add core elements to the ldb_message for the alias */
1709 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1710 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1711 return NT_STATUS_NO_MEMORY;
1713 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1715 "foreignSecurityPrincipal");
1717 /* create the alias */
1718 ret = samdb_add(sam_ctx, mem_ctx, msg);
1720 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1722 ldb_dn_get_linearized(msg->dn),
1723 ldb_errstring(sam_ctx)));
1724 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1727 return NT_STATUS_OK;
1732 Find the DN of a domain, assuming it to be a dotted.dns name
1735 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
1738 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1739 const char *binary_encoded;
1740 const char **split_realm;
1747 split_realm = str_list_make(tmp_ctx, dns_domain, ".");
1749 talloc_free(tmp_ctx);
1752 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1753 for (i=0; split_realm[i]; i++) {
1754 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1755 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1756 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1757 binary_encoded, ldb_dn_get_linearized(dn)));
1758 talloc_free(tmp_ctx);
1762 if (!ldb_dn_validate(dn)) {
1763 DEBUG(2, ("Failed to validated DN %s\n",
1764 ldb_dn_get_linearized(dn)));
1770 Find the DN of a domain, be it the netbios or DNS name
1773 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1774 const char *domain_name)
1776 const char * const domain_ref_attrs[] = {
1779 const char * const domain_ref2_attrs[] = {
1782 struct ldb_result *res_domain_ref;
1783 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1784 /* find the domain's DN */
1785 int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1787 samdb_partitions_dn(ldb, mem_ctx),
1790 "(&(nETBIOSName=%s)(objectclass=crossRef))",
1792 if (ret_domain != 0) {
1796 if (res_domain_ref->count == 0) {
1797 ret_domain = ldb_search_exp_fmt(ldb, mem_ctx,
1799 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
1802 "(objectclass=domain)");
1803 if (ret_domain != 0) {
1807 if (res_domain_ref->count == 1) {
1808 return res_domain_ref->msgs[0]->dn;
1813 if (res_domain_ref->count > 1) {
1814 DEBUG(0,("Found %d records matching domain [%s]\n",
1815 ret_domain, domain_name));
1819 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);