r19598: Ahead of a merge to current lorikeet-heimdal:
[Samba.git] / source / dsdb / samdb / samdb.c
blobf9ef3bc907885a711a5a3e4309a0ba1d691f3b37
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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354 const char *attr, struct ldb_dn *default_value)
356 const char *string = samdb_result_string(msg, attr, NULL);
357 if (string == NULL) return default_value;
358 return ldb_dn_explode(mem_ctx, string);
362 pull a rid from a objectSid in a result set.
364 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
365 const char *attr, uint32_t default_value)
367 struct dom_sid *sid;
368 uint32_t rid;
370 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
371 if (sid == NULL) {
372 return default_value;
374 rid = sid->sub_auths[sid->num_auths-1];
375 talloc_free(sid);
376 return rid;
380 pull a dom_sid structure from a objectSid in a result set.
382 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
383 const char *attr)
385 const struct ldb_val *v;
386 struct dom_sid *sid;
387 NTSTATUS status;
388 v = ldb_msg_find_ldb_val(msg, attr);
389 if (v == NULL) {
390 return NULL;
392 sid = talloc(mem_ctx, struct dom_sid);
393 if (sid == NULL) {
394 return NULL;
396 status = ndr_pull_struct_blob(v, sid, sid,
397 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
398 if (!NT_STATUS_IS_OK(status)) {
399 talloc_free(sid);
400 return NULL;
402 return sid;
406 pull a guid structure from a objectGUID in a result set.
408 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
410 const struct ldb_val *v;
411 NTSTATUS status;
412 struct GUID guid;
413 TALLOC_CTX *mem_ctx;
415 ZERO_STRUCT(guid);
417 v = ldb_msg_find_ldb_val(msg, attr);
418 if (!v) return guid;
420 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
421 if (!mem_ctx) return guid;
422 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
423 (ndr_pull_flags_fn_t)ndr_pull_GUID);
424 talloc_free(mem_ctx);
425 if (!NT_STATUS_IS_OK(status)) {
426 return guid;
429 return guid;
433 pull a sid prefix from a objectSid in a result set.
434 this is used to find the domain sid for a user
436 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
437 const char *attr)
439 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
440 if (!sid || sid->num_auths < 1) return NULL;
441 sid->num_auths--;
442 return sid;
446 pull a NTTIME in a result set.
448 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
450 const char *str = ldb_msg_find_attr_as_string(msg, attr, NULL);
451 if (!str) return default_value;
452 return nttime_from_string(str);
456 pull a uint64_t from a result set.
458 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
460 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
465 construct the allow_password_change field from the PwdLastSet attribute and the
466 domain password settings
468 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
469 TALLOC_CTX *mem_ctx,
470 const struct ldb_dn *domain_dn,
471 struct ldb_message *msg,
472 const char *attr)
474 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
475 int64_t minPwdAge;
477 if (attr_time == 0) {
478 return 0;
481 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
483 /* yes, this is a -= not a += as minPwdAge is stored as the negative
484 of the number of 100-nano-seconds */
485 attr_time -= minPwdAge;
487 return attr_time;
491 construct the force_password_change field from the PwdLastSet attribute and the
492 domain password settings
494 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
495 TALLOC_CTX *mem_ctx,
496 const struct ldb_dn *domain_dn,
497 struct ldb_message *msg)
499 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
500 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
501 int64_t maxPwdAge;
503 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
504 return 0x7FFFFFFFFFFFFFFFULL;
507 if (attr_time == 0) {
508 return 0;
511 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
512 if (maxPwdAge == 0) {
513 return 0;
514 } else {
515 attr_time -= maxPwdAge;
518 return attr_time;
522 pull a samr_Password structutre from a result set.
524 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
526 struct samr_Password *hash = NULL;
527 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
528 if (val && (val->length >= sizeof(hash->hash))) {
529 hash = talloc(mem_ctx, struct samr_Password);
530 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
532 return hash;
536 pull an array of samr_Password structutres from a result set.
538 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
539 const char *attr, struct samr_Password **hashes)
541 uint_t count = 0;
542 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
543 int i;
545 *hashes = NULL;
546 if (!val) {
547 return 0;
549 count = val->length / 16;
550 if (count == 0) {
551 return 0;
554 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
555 if (! *hashes) {
556 return 0;
559 for (i=0;i<count;i++) {
560 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
563 return count;
566 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
567 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
569 struct samr_Password *lmPwdHash, *ntPwdHash;
570 if (nt_pwd) {
571 int num_nt;
572 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
573 if (num_nt == 0) {
574 *nt_pwd = NULL;
575 } else if (num_nt > 1) {
576 return NT_STATUS_INTERNAL_DB_CORRUPTION;
577 } else {
578 *nt_pwd = &ntPwdHash[0];
581 if (lm_pwd) {
582 int num_lm;
583 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
584 if (num_lm == 0) {
585 *lm_pwd = NULL;
586 } else if (num_lm > 1) {
587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
588 } else {
589 *lm_pwd = &lmPwdHash[0];
592 return NT_STATUS_OK;
596 pull a samr_LogonHours structutre from a result set.
598 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
600 struct samr_LogonHours hours;
601 const int units_per_week = 168;
602 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
603 ZERO_STRUCT(hours);
604 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
605 if (!hours.bits) {
606 return hours;
608 hours.units_per_week = units_per_week;
609 memset(hours.bits, 0xFF, units_per_week);
610 if (val) {
611 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
613 return hours;
617 pull a set of account_flags from a result set.
619 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
621 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
622 return samdb_uf2acb(userAccountControl);
626 /* Find an attribute, with a particular value */
627 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
628 const struct ldb_message *msg,
629 const char *name, const char *value)
631 int i;
632 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
633 struct ldb_val v;
635 v.data = discard_const_p(uint8_t, value);
636 v.length = strlen(value);
638 if (!el) {
639 return NULL;
642 for (i=0;i<el->num_values;i++) {
643 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
644 return el;
648 return NULL;
651 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
653 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
654 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
656 return LDB_SUCCESS;
659 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
661 struct ldb_message_element *el;
663 el = ldb_msg_find_element(msg, name);
664 if (el) {
665 return LDB_SUCCESS;
668 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
673 copy from a template record to a message
675 int samdb_copy_template(struct ldb_context *ldb,
676 struct ldb_message *msg, const char *filter,
677 const char **errstring)
679 struct ldb_result *res;
680 struct ldb_message *t;
681 int ret, i, j;
682 struct ldb_dn *basedn = ldb_dn_explode(ldb, "cn=Templates");
684 *errstring = NULL;
686 /* pull the template record */
687 ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
688 talloc_free(basedn);
689 if (ret != LDB_SUCCESS) {
690 *errstring = talloc_steal(msg, ldb_errstring(ldb));
691 return ret;
693 if (res->count != 1) {
694 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
695 res->count);
696 talloc_free(res);
697 return LDB_ERR_OPERATIONS_ERROR;
699 t = res->msgs[0];
701 for (i = 0; i < t->num_elements; i++) {
702 struct ldb_message_element *el = &t->elements[i];
703 /* some elements should not be copied from the template */
704 if (strcasecmp(el->name, "cn") == 0 ||
705 strcasecmp(el->name, "name") == 0 ||
706 strcasecmp(el->name, "sAMAccountName") == 0 ||
707 strcasecmp(el->name, "sAMAccountName") == 0 ||
708 strcasecmp(el->name, "distinguishedName") == 0 ||
709 strcasecmp(el->name, "objectGUID") == 0) {
710 continue;
712 for (j = 0; j < el->num_values; j++) {
713 if (strcasecmp(el->name, "objectClass") == 0) {
714 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
715 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
716 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
717 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
718 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
719 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
720 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
721 continue;
723 ret = samdb_find_or_add_value(ldb, msg, el->name,
724 (char *)el->values[j].data);
725 if (ret) {
726 *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
727 talloc_free(res);
728 return ret;
730 } else {
731 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
732 (char *)el->values[j].data);
733 if (ret) {
734 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
735 talloc_free(res);
736 return ret;
742 talloc_free(res);
744 return LDB_SUCCESS;
749 add a string element to a message
751 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
752 const char *attr_name, const char *str)
754 char *s = talloc_strdup(mem_ctx, str);
755 char *a = talloc_strdup(mem_ctx, attr_name);
756 if (s == NULL || a == NULL) {
757 return LDB_ERR_OPERATIONS_ERROR;
759 return ldb_msg_add_string(msg, a, s);
763 add a dom_sid element to a message
765 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
766 const char *attr_name, struct dom_sid *sid)
768 struct ldb_val v;
769 NTSTATUS status;
770 status = ndr_push_struct_blob(&v, mem_ctx, sid,
771 (ndr_push_flags_fn_t)ndr_push_dom_sid);
772 if (!NT_STATUS_IS_OK(status)) {
773 return -1;
775 return ldb_msg_add_value(msg, attr_name, &v, NULL);
780 add a delete element operation to a message
782 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
783 const char *attr_name)
785 /* we use an empty replace rather than a delete, as it allows for
786 samdb_replace() to be used everywhere */
787 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
791 add a add attribute value to a message
793 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794 const char *attr_name, const char *value)
796 struct ldb_message_element *el;
797 char *a, *v;
798 int ret;
799 a = talloc_strdup(mem_ctx, attr_name);
800 if (a == NULL)
801 return -1;
802 v = talloc_strdup(mem_ctx, value);
803 if (v == NULL)
804 return -1;
805 ret = ldb_msg_add_string(msg, a, v);
806 if (ret != 0)
807 return ret;
808 el = ldb_msg_find_element(msg, a);
809 if (el == NULL)
810 return -1;
811 el->flags = LDB_FLAG_MOD_ADD;
812 return 0;
816 add a delete attribute value to a message
818 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
819 const char *attr_name, const char *value)
821 struct ldb_message_element *el;
822 char *a, *v;
823 int ret;
824 a = talloc_strdup(mem_ctx, attr_name);
825 if (a == NULL)
826 return -1;
827 v = talloc_strdup(mem_ctx, value);
828 if (v == NULL)
829 return -1;
830 ret = ldb_msg_add_string(msg, a, v);
831 if (ret != 0)
832 return ret;
833 el = ldb_msg_find_element(msg, a);
834 if (el == NULL)
835 return -1;
836 el->flags = LDB_FLAG_MOD_DELETE;
837 return 0;
841 add a int element to a message
843 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
844 const char *attr_name, int v)
846 const char *s = talloc_asprintf(mem_ctx, "%d", v);
847 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
851 add a uint_t element to a message
853 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
854 const char *attr_name, uint_t v)
856 const char *s = talloc_asprintf(mem_ctx, "%u", v);
857 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
861 add a (signed) int64_t element to a message
863 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
864 const char *attr_name, int64_t v)
866 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
867 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
871 add a uint64_t element to a message
873 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
874 const char *attr_name, uint64_t v)
876 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
877 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
881 add a samr_Password element to a message
883 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
884 const char *attr_name, struct samr_Password *hash)
886 struct ldb_val val;
887 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
888 if (!val.data) {
889 return -1;
891 val.length = 16;
892 return ldb_msg_add_value(msg, attr_name, &val, NULL);
896 add a samr_Password array to a message
898 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
899 const char *attr_name, struct samr_Password *hashes, uint_t count)
901 struct ldb_val val;
902 int i;
903 val.data = talloc_array_size(mem_ctx, 16, count);
904 val.length = count*16;
905 if (!val.data) {
906 return -1;
908 for (i=0;i<count;i++) {
909 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
911 return ldb_msg_add_value(msg, attr_name, &val, NULL);
915 add a acct_flags element to a message
917 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
918 const char *attr_name, uint32_t v)
920 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
924 add a logon_hours element to a message
926 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927 const char *attr_name, struct samr_LogonHours *hours)
929 struct ldb_val val;
930 val.length = hours->units_per_week / 8;
931 val.data = hours->bits;
932 return ldb_msg_add_value(msg, attr_name, &val, NULL);
936 add a general value element to a message
938 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939 const char *attr_name, const struct ldb_val *val)
941 return ldb_msg_add_value(msg, attr_name, val, NULL);
945 sets a general value element to a message
947 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
948 const char *attr_name, const struct ldb_val *val)
950 struct ldb_message_element *el;
952 el = ldb_msg_find_element(msg, attr_name);
953 if (el) {
954 el->num_values = 0;
956 return ldb_msg_add_value(msg, attr_name, val, NULL);
960 set a string element in a message
962 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
963 const char *attr_name, const char *str)
965 struct ldb_message_element *el;
967 el = ldb_msg_find_element(msg, attr_name);
968 if (el) {
969 el->num_values = 0;
971 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
975 add a record
977 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
979 return ldb_add(sam_ldb, msg);
983 delete a record
985 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
987 return ldb_delete(sam_ldb, dn);
991 modify a record
993 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
995 return ldb_modify(sam_ldb, msg);
999 replace elements in a record
1001 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1003 int i;
1005 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1006 for (i=0;i<msg->num_elements;i++) {
1007 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1010 /* modify the samdb record */
1011 return samdb_modify(sam_ldb, mem_ctx, msg);
1015 return a default security descriptor
1017 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1019 struct security_descriptor *sd;
1021 sd = security_descriptor_initialise(mem_ctx);
1023 return sd;
1026 const struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1028 return ldb_get_default_basedn(sam_ctx);
1032 const struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx,
1033 TALLOC_CTX *mem_ctx)
1035 return ldb_dn_string_compose(mem_ctx, samdb_base_dn(sam_ctx),
1036 "CN=Partitions,CN=Configuration");
1041 work out the domain sid for the current open ldb
1043 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1045 const char *attrs[] = { "rootDomainNamingContext", NULL };
1046 int ret;
1047 struct ldb_result *res = NULL;
1048 TALLOC_CTX *tmp_ctx;
1049 struct dom_sid *domain_sid;
1050 const char *basedn_s;
1051 struct ldb_dn *basedn;
1053 /* see if we have a cached copy */
1054 domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1055 if (domain_sid) {
1056 return domain_sid;
1059 tmp_ctx = talloc_new(ldb);
1060 if (tmp_ctx == NULL) {
1061 goto failed;
1064 basedn = ldb_dn_explode(tmp_ctx, "");
1065 if (basedn == NULL) {
1066 goto failed;
1069 /* find the basedn of the domain from the rootdse */
1070 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1071 talloc_steal(tmp_ctx, res);
1072 if (ret != LDB_SUCCESS || res->count != 1) {
1073 goto failed;
1076 basedn_s = ldb_msg_find_attr_as_string(res->msgs[0], "rootDomainNamingContext", NULL);
1077 if (basedn_s == NULL) {
1078 goto failed;
1081 basedn = ldb_dn_explode(tmp_ctx, basedn_s);
1082 if (basedn == NULL) {
1083 goto failed;
1086 /* find the domain_sid */
1087 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn,
1088 "objectSid", "objectClass=domainDNS");
1089 if (domain_sid == NULL) {
1090 goto failed;
1093 /* cache the domain_sid in the ldb */
1094 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1095 goto failed;
1098 talloc_steal(ldb, domain_sid);
1099 talloc_free(tmp_ctx);
1101 return domain_sid;
1103 failed:
1104 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1105 talloc_free(tmp_ctx);
1106 return NULL;
1110 check that a password is sufficiently complex
1112 static BOOL samdb_password_complexity_ok(const char *pass)
1114 return check_password_quality(pass);
1120 set the user password using plaintext, obeying any user or domain
1121 password restrictions
1123 note that this function doesn't actually store the result in the
1124 database, it just fills in the "mod" structure with ldb modify
1125 elements to setup the correct change when samdb_replace() is
1126 called. This allows the caller to combine the change with other
1127 changes (as is needed by some of the set user info levels)
1129 The caller should probably have a transaction wrapping this
1131 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1132 const struct ldb_dn *user_dn,
1133 const struct ldb_dn *domain_dn,
1134 struct ldb_message *mod,
1135 const char *new_pass,
1136 struct samr_Password *lmNewHash,
1137 struct samr_Password *ntNewHash,
1138 BOOL user_change,
1139 BOOL restrictions,
1140 enum samr_RejectReason *reject_reason,
1141 struct samr_DomInfo1 **_dominfo)
1143 const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory",
1144 "sambaNTPwdHistory",
1145 "lmPwdHash", "ntPwdHash",
1146 "objectSid",
1147 "pwdLastSet", NULL };
1148 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1149 "maxPwdAge", "minPwdAge",
1150 "minPwdLength", NULL };
1151 NTTIME pwdLastSet;
1152 int64_t minPwdAge;
1153 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1154 uint_t userAccountControl;
1155 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1156 struct samr_Password local_lmNewHash, local_ntNewHash;
1157 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1158 struct dom_sid *domain_sid;
1159 struct ldb_message **res;
1160 int count;
1161 time_t now = time(NULL);
1162 NTTIME now_nt;
1163 int i;
1165 /* we need to know the time to compute password age */
1166 unix_to_nt_time(&now_nt, now);
1168 /* pull all the user parameters */
1169 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1170 if (count != 1) {
1171 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1173 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1174 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1175 "sambaLMPwdHistory", &sambaLMPwdHistory);
1176 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1177 "sambaNTPwdHistory", &sambaNTPwdHistory);
1178 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "lmPwdHash");
1179 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "ntPwdHash");
1180 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1182 if (domain_dn) {
1183 /* pull the domain parameters */
1184 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1185 if (count != 1) {
1186 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1187 ldb_dn_linearize(mem_ctx, domain_dn),
1188 ldb_dn_linearize(mem_ctx, user_dn)));
1189 return NT_STATUS_NO_SUCH_DOMAIN;
1191 } else {
1192 /* work out the domain sid, and pull the domain from there */
1193 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1194 if (domain_sid == NULL) {
1195 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1198 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1199 "(objectSid=%s)",
1200 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1201 if (count != 1) {
1202 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1203 dom_sid_string(mem_ctx, domain_sid),
1204 ldb_dn_linearize(mem_ctx, user_dn)));
1205 return NT_STATUS_NO_SUCH_DOMAIN;
1209 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1210 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1211 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1212 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1214 if (_dominfo) {
1215 struct samr_DomInfo1 *dominfo;
1216 /* on failure we need to fill in the reject reasons */
1217 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1218 if (dominfo == NULL) {
1219 return NT_STATUS_NO_MEMORY;
1221 dominfo->min_password_length = minPwdLength;
1222 dominfo->password_properties = pwdProperties;
1223 dominfo->password_history_length = pwdHistoryLength;
1224 dominfo->max_password_age = minPwdAge;
1225 dominfo->min_password_age = minPwdAge;
1226 *_dominfo = dominfo;
1229 if (new_pass) {
1230 /* check the various password restrictions */
1231 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1232 if (reject_reason) {
1233 *reject_reason = SAMR_REJECT_TOO_SHORT;
1235 return NT_STATUS_PASSWORD_RESTRICTION;
1238 /* possibly check password complexity */
1239 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1240 !samdb_password_complexity_ok(new_pass)) {
1241 if (reject_reason) {
1242 *reject_reason = SAMR_REJECT_COMPLEXITY;
1244 return NT_STATUS_PASSWORD_RESTRICTION;
1247 /* compute the new nt and lm hashes */
1248 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1249 lmNewHash = &local_lmNewHash;
1251 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1252 /* If we can't convert this password to UCS2, then we should not accept it */
1253 if (reject_reason) {
1254 *reject_reason = SAMR_REJECT_OTHER;
1256 return NT_STATUS_PASSWORD_RESTRICTION;
1258 ntNewHash = &local_ntNewHash;
1261 if (restrictions && user_change) {
1262 /* are all password changes disallowed? */
1263 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1264 if (reject_reason) {
1265 *reject_reason = SAMR_REJECT_OTHER;
1267 return NT_STATUS_PASSWORD_RESTRICTION;
1270 /* can this user change password? */
1271 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1272 if (reject_reason) {
1273 *reject_reason = SAMR_REJECT_OTHER;
1275 return NT_STATUS_PASSWORD_RESTRICTION;
1278 /* yes, this is a minus. The ages are in negative 100nsec units! */
1279 if (pwdLastSet - minPwdAge > now_nt) {
1280 if (reject_reason) {
1281 *reject_reason = SAMR_REJECT_OTHER;
1283 return NT_STATUS_PASSWORD_RESTRICTION;
1286 /* check the immediately past password */
1287 if (pwdHistoryLength > 0) {
1288 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1289 if (reject_reason) {
1290 *reject_reason = SAMR_REJECT_IN_HISTORY;
1292 return NT_STATUS_PASSWORD_RESTRICTION;
1294 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1295 if (reject_reason) {
1296 *reject_reason = SAMR_REJECT_IN_HISTORY;
1298 return NT_STATUS_PASSWORD_RESTRICTION;
1302 /* check the password history */
1303 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1304 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1306 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1307 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1308 if (reject_reason) {
1309 *reject_reason = SAMR_REJECT_IN_HISTORY;
1311 return NT_STATUS_PASSWORD_RESTRICTION;
1314 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1315 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1316 if (reject_reason) {
1317 *reject_reason = SAMR_REJECT_IN_HISTORY;
1319 return NT_STATUS_PASSWORD_RESTRICTION;
1324 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1326 /* the password is acceptable. Start forming the new fields */
1327 if (new_pass) {
1328 /* if we know the cleartext, then only set it.
1329 * Modules in ldb will set all the appropriate
1330 * hashes */
1331 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1332 "sambaPassword", new_pass));
1333 } else {
1334 /* We don't have the cleartext, so delete the old one
1335 * and set what we have of the hashes */
1336 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1338 if (lmNewHash) {
1339 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1340 } else {
1341 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1344 if (ntNewHash) {
1345 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1346 } else {
1347 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1351 return NT_STATUS_OK;
1356 set the user password using plaintext, obeying any user or domain
1357 password restrictions
1359 This wrapper function takes a SID as input, rather than a user DN,
1360 and actually performs the password change
1363 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1364 const struct dom_sid *user_sid,
1365 const char *new_pass,
1366 struct samr_Password *lmNewHash,
1367 struct samr_Password *ntNewHash,
1368 BOOL user_change,
1369 BOOL restrictions,
1370 enum samr_RejectReason *reject_reason,
1371 struct samr_DomInfo1 **_dominfo)
1373 NTSTATUS nt_status;
1374 struct ldb_dn *user_dn;
1375 struct ldb_message *msg;
1376 int ret;
1378 ret = ldb_transaction_start(ctx);
1379 if (ret) {
1380 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1381 return NT_STATUS_TRANSACTION_ABORTED;
1384 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1385 "(&(objectSid=%s)(objectClass=user))",
1386 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1387 if (!user_dn) {
1388 ldb_transaction_cancel(ctx);
1389 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1390 dom_sid_string(mem_ctx, user_sid)));
1391 return NT_STATUS_NO_SUCH_USER;
1394 msg = ldb_msg_new(mem_ctx);
1395 if (msg == NULL) {
1396 ldb_transaction_cancel(ctx);
1397 return NT_STATUS_NO_MEMORY;
1400 msg->dn = ldb_dn_copy(msg, user_dn);
1401 if (!msg->dn) {
1402 ldb_transaction_cancel(ctx);
1403 return NT_STATUS_NO_MEMORY;
1406 nt_status = samdb_set_password(ctx, mem_ctx,
1407 user_dn, NULL,
1408 msg, new_pass,
1409 lmNewHash, ntNewHash,
1410 user_change, /* This is a password set, not change */
1411 restrictions, /* run restriction tests */
1412 reject_reason, _dominfo);
1413 if (!NT_STATUS_IS_OK(nt_status)) {
1414 ldb_transaction_cancel(ctx);
1415 return nt_status;
1418 /* modify the samdb record */
1419 ret = samdb_replace(ctx, mem_ctx, msg);
1420 if (ret != 0) {
1421 ldb_transaction_cancel(ctx);
1422 return NT_STATUS_ACCESS_DENIED;
1425 ret = ldb_transaction_commit(ctx);
1426 if (ret != 0) {
1427 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1428 ldb_dn_linearize(mem_ctx, msg->dn),
1429 ldb_errstring(ctx)));
1430 return NT_STATUS_TRANSACTION_ABORTED;
1432 return NT_STATUS_OK;
1435 /****************************************************************************
1436 Create the SID list for this user.
1437 ****************************************************************************/
1438 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1439 struct dom_sid *user_sid,
1440 struct dom_sid *group_sid,
1441 int n_groupSIDs,
1442 struct dom_sid **groupSIDs,
1443 BOOL is_authenticated,
1444 struct security_token **token)
1446 struct security_token *ptoken;
1447 int i;
1448 NTSTATUS status;
1450 ptoken = security_token_initialise(mem_ctx);
1451 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1453 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1454 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1456 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1457 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1458 ptoken->privilege_mask = 0;
1460 ptoken->sids[0] = ptoken->user_sid;
1461 ptoken->sids[1] = ptoken->group_sid;
1464 * Finally add the "standard" SIDs.
1465 * The only difference between guest and "anonymous"
1466 * is the addition of Authenticated_Users.
1468 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1469 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1470 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1471 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1472 ptoken->num_sids = 4;
1474 if (is_authenticated) {
1475 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1476 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1477 ptoken->num_sids++;
1480 for (i = 0; i < n_groupSIDs; i++) {
1481 size_t check_sid_idx;
1482 for (check_sid_idx = 1;
1483 check_sid_idx < ptoken->num_sids;
1484 check_sid_idx++) {
1485 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1486 break;
1490 if (check_sid_idx == ptoken->num_sids) {
1491 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1495 /* setup the privilege mask for this token */
1496 status = samdb_privilege_setup(ptoken);
1497 if (!NT_STATUS_IS_OK(status)) {
1498 talloc_free(ptoken);
1499 return status;
1502 security_token_debug(10, ptoken);
1504 *token = ptoken;
1506 return NT_STATUS_OK;
1510 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1511 struct dom_sid *sid, struct ldb_dn **ret_dn)
1513 struct ldb_message *msg;
1514 struct ldb_dn *basedn;
1515 const char *sidstr;
1516 int ret;
1518 sidstr = dom_sid_string(mem_ctx, sid);
1519 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1521 /* We might have to create a ForeignSecurityPrincipal, even if this user
1522 * is in our own domain */
1524 msg = ldb_msg_new(mem_ctx);
1525 if (msg == NULL) {
1526 return NT_STATUS_NO_MEMORY;
1529 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1530 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1531 * not work, this is wrong for the Builtin domain, there's no
1532 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1535 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1536 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1538 if (basedn == NULL) {
1539 DEBUG(0, ("Failed to find DN for "
1540 "ForeignSecurityPrincipal container\n"));
1541 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1544 /* add core elements to the ldb_message for the alias */
1545 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
1546 if (msg->dn == NULL)
1547 return NT_STATUS_NO_MEMORY;
1549 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1550 "objectClass",
1551 "foreignSecurityPrincipal");
1553 /* create the alias */
1554 ret = samdb_add(sam_ctx, mem_ctx, msg);
1555 if (ret != 0) {
1556 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1557 "record %s: %s\n",
1558 ldb_dn_linearize(mem_ctx, msg->dn),
1559 ldb_errstring(sam_ctx)));
1560 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1562 *ret_dn = msg->dn;
1563 return NT_STATUS_OK;