• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/dsdb/common/
1/*
2   Unix SMB/CIFS implementation.
3   Samba utility functions
4
5   Copyright (C) Andrew Tridgell 2004
6   Copyright (C) Volker Lendecke 2004
7   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8   Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
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.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "includes.h"
25#include "events/events.h"
26#include "ldb.h"
27#include "ldb_errors.h"
28#include "../lib/util/util_ldb.h"
29#include "../lib/crypto/crypto.h"
30#include "dsdb/samdb/samdb.h"
31#include "libcli/security/security.h"
32#include "librpc/gen_ndr/ndr_security.h"
33#include "librpc/gen_ndr/ndr_misc.h"
34#include "../libds/common/flags.h"
35#include "dsdb/common/proto.h"
36#include "libcli/ldap/ldap_ndr.h"
37#include "param/param.h"
38#include "libcli/auth/libcli_auth.h"
39#include "librpc/gen_ndr/ndr_drsblobs.h"
40
41/*
42  search the sam for the specified attributes in a specific domain, filter on
43  objectSid being in domain_sid.
44*/
45int samdb_search_domain(struct ldb_context *sam_ldb,
46			TALLOC_CTX *mem_ctx,
47			struct ldb_dn *basedn,
48			struct ldb_message ***res,
49			const char * const *attrs,
50			const struct dom_sid *domain_sid,
51			const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
52{
53	va_list ap;
54	int i, count;
55
56	va_start(ap, format);
57	count = gendb_search_v(sam_ldb, mem_ctx, basedn,
58			       res, attrs, format, ap);
59	va_end(ap);
60
61	i=0;
62
63	while (i<count) {
64		struct dom_sid *entry_sid;
65
66		entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
67
68		if ((entry_sid == NULL) ||
69		    (!dom_sid_in_domain(domain_sid, entry_sid))) {
70			/* Delete that entry from the result set */
71			(*res)[i] = (*res)[count-1];
72			count -= 1;
73			talloc_free(entry_sid);
74			continue;
75		}
76		talloc_free(entry_sid);
77		i += 1;
78	}
79
80	return count;
81}
82
83/*
84  search the sam for a single string attribute in exactly 1 record
85*/
86const char *samdb_search_string_v(struct ldb_context *sam_ldb,
87				  TALLOC_CTX *mem_ctx,
88				  struct ldb_dn *basedn,
89				  const char *attr_name,
90				  const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
91{
92	int count;
93	const char *attrs[2] = { NULL, NULL };
94	struct ldb_message **res = NULL;
95
96	attrs[0] = attr_name;
97
98	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
99	if (count > 1) {
100		DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
101			 attr_name, format, count));
102	}
103	if (count != 1) {
104		talloc_free(res);
105		return NULL;
106	}
107
108	return samdb_result_string(res[0], attr_name, NULL);
109}
110
111/*
112  search the sam for a single string attribute in exactly 1 record
113*/
114const char *samdb_search_string(struct ldb_context *sam_ldb,
115				TALLOC_CTX *mem_ctx,
116				struct ldb_dn *basedn,
117				const char *attr_name,
118				const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
119{
120	va_list ap;
121	const char *str;
122
123	va_start(ap, format);
124	str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
125	va_end(ap);
126
127	return str;
128}
129
130struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
131			       TALLOC_CTX *mem_ctx,
132			       struct ldb_dn *basedn,
133			       const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
134{
135	va_list ap;
136	struct ldb_dn *ret;
137	struct ldb_message **res = NULL;
138	int count;
139
140	va_start(ap, format);
141	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
142	va_end(ap);
143
144	if (count != 1) return NULL;
145
146	ret = talloc_steal(mem_ctx, res[0]->dn);
147	talloc_free(res);
148
149	return ret;
150}
151
152/*
153  search the sam for a dom_sid attribute in exactly 1 record
154*/
155struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
156				     TALLOC_CTX *mem_ctx,
157				     struct ldb_dn *basedn,
158				     const char *attr_name,
159				     const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
160{
161	va_list ap;
162	int count;
163	struct ldb_message **res;
164	const char *attrs[2] = { NULL, NULL };
165	struct dom_sid *sid;
166
167	attrs[0] = attr_name;
168
169	va_start(ap, format);
170	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
171	va_end(ap);
172	if (count > 1) {
173		DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174			 attr_name, format, count));
175	}
176	if (count != 1) {
177		talloc_free(res);
178		return NULL;
179	}
180	sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
181	talloc_free(res);
182	return sid;
183}
184
185/*
186  return the count of the number of records in the sam matching the query
187*/
188int samdb_search_count(struct ldb_context *sam_ldb,
189		       TALLOC_CTX *mem_ctx,
190		       struct ldb_dn *basedn,
191		       const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
192{
193	va_list ap;
194	struct ldb_message **res;
195	const char * const attrs[] = { NULL };
196	int ret;
197
198	va_start(ap, format);
199	ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
200	va_end(ap);
201
202	return ret;
203}
204
205
206/*
207  search the sam for a single integer attribute in exactly 1 record
208*/
209uint_t samdb_search_uint(struct ldb_context *sam_ldb,
210			 TALLOC_CTX *mem_ctx,
211			 uint_t default_value,
212			 struct ldb_dn *basedn,
213			 const char *attr_name,
214			 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215{
216	va_list ap;
217	int count;
218	struct ldb_message **res;
219	const char *attrs[2] = { NULL, NULL };
220
221	attrs[0] = attr_name;
222
223	va_start(ap, format);
224	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
225	va_end(ap);
226
227	if (count != 1) {
228		return default_value;
229	}
230
231	return samdb_result_uint(res[0], attr_name, default_value);
232}
233
234/*
235  search the sam for a single signed 64 bit integer attribute in exactly 1 record
236*/
237int64_t samdb_search_int64(struct ldb_context *sam_ldb,
238			   TALLOC_CTX *mem_ctx,
239			   int64_t default_value,
240			   struct ldb_dn *basedn,
241			   const char *attr_name,
242			   const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243{
244	va_list ap;
245	int count;
246	struct ldb_message **res;
247	const char *attrs[2] = { NULL, NULL };
248
249	attrs[0] = attr_name;
250
251	va_start(ap, format);
252	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
253	va_end(ap);
254
255	if (count != 1) {
256		return default_value;
257	}
258
259	return samdb_result_int64(res[0], attr_name, default_value);
260}
261
262/*
263  search the sam for multipe records each giving a single string attribute
264  return the number of matches, or -1 on error
265*/
266int samdb_search_string_multiple(struct ldb_context *sam_ldb,
267				 TALLOC_CTX *mem_ctx,
268				 struct ldb_dn *basedn,
269				 const char ***strs,
270				 const char *attr_name,
271				 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
272{
273	va_list ap;
274	int count, i;
275	const char *attrs[2] = { NULL, NULL };
276	struct ldb_message **res = NULL;
277
278	attrs[0] = attr_name;
279
280	va_start(ap, format);
281	count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
282	va_end(ap);
283
284	if (count <= 0) {
285		return count;
286	}
287
288	/* make sure its single valued */
289	for (i=0;i<count;i++) {
290		if (res[i]->num_elements != 1) {
291			DEBUG(1,("samdb: search for %s %s not single valued\n",
292				 attr_name, format));
293			talloc_free(res);
294			return -1;
295		}
296	}
297
298	*strs = talloc_array(mem_ctx, const char *, count+1);
299	if (! *strs) {
300		talloc_free(res);
301		return -1;
302	}
303
304	for (i=0;i<count;i++) {
305		(*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
306	}
307	(*strs)[count] = NULL;
308
309	return count;
310}
311
312/*
313  pull a uint from a result set.
314*/
315uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
316{
317	return ldb_msg_find_attr_as_uint(msg, attr, default_value);
318}
319
320/*
321  pull a (signed) int64 from a result set.
322*/
323int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
324{
325	return ldb_msg_find_attr_as_int64(msg, attr, default_value);
326}
327
328/*
329  pull a string from a result set.
330*/
331const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
332				const char *default_value)
333{
334	return ldb_msg_find_attr_as_string(msg, attr, default_value);
335}
336
337struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
338			       const char *attr, struct ldb_dn *default_value)
339{
340	struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
341	if (!ret_dn) {
342		return default_value;
343	}
344	return ret_dn;
345}
346
347/*
348  pull a rid from a objectSid in a result set.
349*/
350uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
351				   const char *attr, uint32_t default_value)
352{
353	struct dom_sid *sid;
354	uint32_t rid;
355
356	sid = samdb_result_dom_sid(mem_ctx, msg, attr);
357	if (sid == NULL) {
358		return default_value;
359	}
360	rid = sid->sub_auths[sid->num_auths-1];
361	talloc_free(sid);
362	return rid;
363}
364
365/*
366  pull a dom_sid structure from a objectSid in a result set.
367*/
368struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
369				     const char *attr)
370{
371	const struct ldb_val *v;
372	struct dom_sid *sid;
373	enum ndr_err_code ndr_err;
374	v = ldb_msg_find_ldb_val(msg, attr);
375	if (v == NULL) {
376		return NULL;
377	}
378	sid = talloc(mem_ctx, struct dom_sid);
379	if (sid == NULL) {
380		return NULL;
381	}
382	ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
383				       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
384	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385		talloc_free(sid);
386		return NULL;
387	}
388	return sid;
389}
390
391/*
392  pull a guid structure from a objectGUID in a result set.
393*/
394struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
395{
396	const struct ldb_val *v;
397	enum ndr_err_code ndr_err;
398	struct GUID guid;
399	TALLOC_CTX *mem_ctx;
400
401	ZERO_STRUCT(guid);
402
403	v = ldb_msg_find_ldb_val(msg, attr);
404	if (!v) return guid;
405
406	mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
407	if (!mem_ctx) return guid;
408	ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
409				       (ndr_pull_flags_fn_t)ndr_pull_GUID);
410	talloc_free(mem_ctx);
411	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412		return guid;
413	}
414
415	return guid;
416}
417
418/*
419  pull a sid prefix from a objectSid in a result set.
420  this is used to find the domain sid for a user
421*/
422struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
423					const char *attr)
424{
425	struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426	if (!sid || sid->num_auths < 1) return NULL;
427	sid->num_auths--;
428	return sid;
429}
430
431/*
432  pull a NTTIME in a result set.
433*/
434NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
435{
436	return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
437}
438
439/*
440 * Windows stores 0 for lastLogoff.
441 * But when a MS DC return the lastLogoff (as Logoff Time)
442 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
443 * cause windows 2008 and newer version to fail for SMB requests
444 */
445NTTIME samdb_result_last_logoff(struct ldb_message *msg)
446{
447	NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
448
449	if (ret == 0)
450		ret = 0x7FFFFFFFFFFFFFFFULL;
451
452	return ret;
453}
454
455/*
456 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
457 * indicate an account doesn't expire.
458 *
459 * When Windows initially creates an account, it sets
460 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
461 * when changing from an account having a specific expiration date to
462 * that account never expiring, it sets accountExpires = 0.
463 *
464 * Consolidate that logic here to allow clearer logic for account expiry in
465 * the rest of the code.
466 */
467NTTIME samdb_result_account_expires(struct ldb_message *msg)
468{
469	NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
470						 0);
471
472	if (ret == 0)
473		ret = 0x7FFFFFFFFFFFFFFFULL;
474
475	return ret;
476}
477
478/*
479  pull a uint64_t from a result set.
480*/
481uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
482{
483	return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
484}
485
486
487/*
488  construct the allow_password_change field from the PwdLastSet attribute and the
489  domain password settings
490*/
491NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
492					  TALLOC_CTX *mem_ctx,
493					  struct ldb_dn *domain_dn,
494					  struct ldb_message *msg,
495					  const char *attr)
496{
497	uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
498	int64_t minPwdAge;
499
500	if (attr_time == 0) {
501		return 0;
502	}
503
504	minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
505
506	/* yes, this is a -= not a += as minPwdAge is stored as the negative
507	   of the number of 100-nano-seconds */
508	attr_time -= minPwdAge;
509
510	return attr_time;
511}
512
513/*
514  construct the force_password_change field from the PwdLastSet
515  attribute, the userAccountControl and the domain password settings
516*/
517NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
518					  TALLOC_CTX *mem_ctx,
519					  struct ldb_dn *domain_dn,
520					  struct ldb_message *msg)
521{
522	uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
523	uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
524	int64_t maxPwdAge;
525
526	/* Machine accounts don't expire, and there is a flag for 'no expiry' */
527	if (!(userAccountControl & UF_NORMAL_ACCOUNT)
528	    || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
529		return 0x7FFFFFFFFFFFFFFFULL;
530	}
531
532	if (attr_time == 0) {
533		return 0;
534	}
535
536	maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
537	if (maxPwdAge == 0) {
538		return 0x7FFFFFFFFFFFFFFFULL;
539	} else {
540		attr_time -= maxPwdAge;
541	}
542
543	return attr_time;
544}
545
546/*
547  pull a samr_Password structutre from a result set.
548*/
549struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
550{
551	struct samr_Password *hash = NULL;
552	const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
553	if (val && (val->length >= sizeof(hash->hash))) {
554		hash = talloc(mem_ctx, struct samr_Password);
555		memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
556	}
557	return hash;
558}
559
560/*
561  pull an array of samr_Password structutres from a result set.
562*/
563uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
564			   const char *attr, struct samr_Password **hashes)
565{
566	uint_t count = 0;
567	const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
568	int i;
569
570	*hashes = NULL;
571	if (!val) {
572		return 0;
573	}
574	count = val->length / 16;
575	if (count == 0) {
576		return 0;
577	}
578
579	*hashes = talloc_array(mem_ctx, struct samr_Password, count);
580	if (! *hashes) {
581		return 0;
582	}
583
584	for (i=0;i<count;i++) {
585		memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
586	}
587
588	return count;
589}
590
591NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
592				struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
593{
594	struct samr_Password *lmPwdHash, *ntPwdHash;
595	if (nt_pwd) {
596		int num_nt;
597		num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
598		if (num_nt == 0) {
599			*nt_pwd = NULL;
600		} else if (num_nt > 1) {
601			return NT_STATUS_INTERNAL_DB_CORRUPTION;
602		} else {
603			*nt_pwd = &ntPwdHash[0];
604		}
605	}
606	if (lm_pwd) {
607		/* Ensure that if we have turned off LM
608		 * authentication, that we never use the LM hash, even
609		 * if we store it */
610		if (lp_lanman_auth(lp_ctx)) {
611			int num_lm;
612			num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
613			if (num_lm == 0) {
614				*lm_pwd = NULL;
615			} else if (num_lm > 1) {
616				return NT_STATUS_INTERNAL_DB_CORRUPTION;
617			} else {
618				*lm_pwd = &lmPwdHash[0];
619			}
620		} else {
621			*lm_pwd = NULL;
622		}
623	}
624	return NT_STATUS_OK;
625}
626
627/*
628  pull a samr_LogonHours structutre from a result set.
629*/
630struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
631{
632	struct samr_LogonHours hours;
633	const int units_per_week = 168;
634	const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
635	ZERO_STRUCT(hours);
636	hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
637	if (!hours.bits) {
638		return hours;
639	}
640	hours.units_per_week = units_per_week;
641	memset(hours.bits, 0xFF, units_per_week);
642	if (val) {
643		memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
644	}
645	return hours;
646}
647
648/*
649  pull a set of account_flags from a result set.
650
651  This requires that the attributes:
652   pwdLastSet
653   userAccountControl
654  be included in 'msg'
655*/
656uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
657				 struct ldb_message *msg, struct ldb_dn *domain_dn)
658{
659	uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
660	uint32_t acct_flags = ds_uf2acb(userAccountControl);
661	NTTIME must_change_time;
662	NTTIME now;
663
664	must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
665							      domain_dn, msg);
666
667	/* Test account expire time */
668	unix_to_nt_time(&now, time(NULL));
669	/* check for expired password */
670	if (must_change_time < now) {
671		acct_flags |= ACB_PW_EXPIRED;
672	}
673	return acct_flags;
674}
675
676struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
677						struct ldb_message *msg,
678						const char *attr)
679{
680	struct lsa_BinaryString s;
681	const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
682
683	ZERO_STRUCT(s);
684
685	if (!val) {
686		return s;
687	}
688
689	s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
690	if (!s.array) {
691		return s;
692	}
693	s.length = s.size = val->length/2;
694	memcpy(s.array, val->data, val->length);
695
696	return s;
697}
698
699/* Find an attribute, with a particular value */
700
701/* The current callers of this function expect a very specific
702 * behaviour: In particular, objectClass subclass equivilance is not
703 * wanted.  This means that we should not lookup the schema for the
704 * comparison function */
705struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
706						 const struct ldb_message *msg,
707						 const char *name, const char *value)
708{
709	int i;
710	struct ldb_message_element *el = ldb_msg_find_element(msg, name);
711
712	if (!el) {
713		return NULL;
714	}
715
716	for (i=0;i<el->num_values;i++) {
717		if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
718			return el;
719		}
720	}
721
722	return NULL;
723}
724
725int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
726{
727	if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
728		return samdb_msg_add_string(ldb, msg, msg, name, set_value);
729	}
730	return LDB_SUCCESS;
731}
732
733int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
734{
735	struct ldb_message_element *el;
736
737       	el = ldb_msg_find_element(msg, name);
738	if (el) {
739		return LDB_SUCCESS;
740	}
741
742	return samdb_msg_add_string(ldb, msg, msg, name, set_value);
743}
744
745
746
747/*
748  add a string element to a message
749*/
750int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
751			 const char *attr_name, const char *str)
752{
753	char *s = talloc_strdup(mem_ctx, str);
754	char *a = talloc_strdup(mem_ctx, attr_name);
755	if (s == NULL || a == NULL) {
756		return LDB_ERR_OPERATIONS_ERROR;
757	}
758	return ldb_msg_add_string(msg, a, s);
759}
760
761/*
762  add a dom_sid element to a message
763*/
764int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
765			 const char *attr_name, struct dom_sid *sid)
766{
767	struct ldb_val v;
768	enum ndr_err_code ndr_err;
769
770	ndr_err = ndr_push_struct_blob(&v, mem_ctx,
771				       lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
772				       sid,
773				       (ndr_push_flags_fn_t)ndr_push_dom_sid);
774	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
775		return -1;
776	}
777	return ldb_msg_add_value(msg, attr_name, &v, NULL);
778}
779
780
781/*
782  add a delete element operation to a message
783*/
784int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785			 const char *attr_name)
786{
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);
790}
791
792/*
793  add a add attribute value to a message
794*/
795int 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)
797{
798	struct ldb_message_element *el;
799	char *a, *v;
800	int ret;
801	a = talloc_strdup(mem_ctx, attr_name);
802	if (a == NULL)
803		return -1;
804	v = talloc_strdup(mem_ctx, value);
805	if (v == NULL)
806		return -1;
807	ret = ldb_msg_add_string(msg, a, v);
808	if (ret != 0)
809		return ret;
810	el = ldb_msg_find_element(msg, a);
811	if (el == NULL)
812		return -1;
813	el->flags = LDB_FLAG_MOD_ADD;
814	return 0;
815}
816
817/*
818  add a delete attribute value to a message
819*/
820int 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)
822{
823	struct ldb_message_element *el;
824	char *a, *v;
825	int ret;
826	a = talloc_strdup(mem_ctx, attr_name);
827	if (a == NULL)
828		return -1;
829	v = talloc_strdup(mem_ctx, value);
830	if (v == NULL)
831		return -1;
832	ret = ldb_msg_add_string(msg, a, v);
833	if (ret != 0)
834		return ret;
835	el = ldb_msg_find_element(msg, a);
836	if (el == NULL)
837		return -1;
838	el->flags = LDB_FLAG_MOD_DELETE;
839	return 0;
840}
841
842/*
843  add a int element to a message
844*/
845int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846		       const char *attr_name, int v)
847{
848	const char *s = talloc_asprintf(mem_ctx, "%d", v);
849	return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
850}
851
852/*
853  add a uint_t element to a message
854*/
855int 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)
857{
858	const char *s = talloc_asprintf(mem_ctx, "%u", v);
859	return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
860}
861
862/*
863  add a (signed) int64_t element to a message
864*/
865int 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)
867{
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);
870}
871
872/*
873  add a uint64_t element to a message
874*/
875int 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)
877{
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);
880}
881
882/*
883  add a samr_Password element to a message
884*/
885int 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)
887{
888	struct ldb_val val;
889	val.data = talloc_memdup(mem_ctx, hash->hash, 16);
890	if (!val.data) {
891		return -1;
892	}
893	val.length = 16;
894	return ldb_msg_add_value(msg, attr_name, &val, NULL);
895}
896
897/*
898  add a samr_Password array to a message
899*/
900int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
901			 const char *attr_name, struct samr_Password *hashes, uint_t count)
902{
903	struct ldb_val val;
904	int i;
905	val.data = talloc_array_size(mem_ctx, 16, count);
906	val.length = count*16;
907	if (!val.data) {
908		return -1;
909	}
910	for (i=0;i<count;i++) {
911		memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
912	}
913	return ldb_msg_add_value(msg, attr_name, &val, NULL);
914}
915
916/*
917  add a acct_flags element to a message
918*/
919int 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)
921{
922	return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
923}
924
925/*
926  add a logon_hours element to a message
927*/
928int 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)
930{
931	struct ldb_val val;
932	val.length = hours->units_per_week / 8;
933	val.data = hours->bits;
934	return ldb_msg_add_value(msg, attr_name, &val, NULL);
935}
936
937/*
938  add a parameters element to a message
939*/
940int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
941			     const char *attr_name, struct lsa_BinaryString *parameters)
942{
943	struct ldb_val val;
944	val.length = parameters->length * 2;
945	val.data = (uint8_t *)parameters->array;
946	return ldb_msg_add_value(msg, attr_name, &val, NULL);
947}
948/*
949  add a general value element to a message
950*/
951int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
952			      const char *attr_name, const struct ldb_val *val)
953{
954	return ldb_msg_add_value(msg, attr_name, val, NULL);
955}
956
957/*
958  sets a general value element to a message
959*/
960int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961			const char *attr_name, const struct ldb_val *val)
962{
963	struct ldb_message_element *el;
964
965	el = ldb_msg_find_element(msg, attr_name);
966	if (el) {
967		el->num_values = 0;
968	}
969	return ldb_msg_add_value(msg, attr_name, val, NULL);
970}
971
972/*
973  set a string element in a message
974*/
975int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
976			 const char *attr_name, const char *str)
977{
978	struct ldb_message_element *el;
979
980	el = ldb_msg_find_element(msg, attr_name);
981	if (el) {
982		el->num_values = 0;
983	}
984	return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
985}
986
987/*
988  replace elements in a record
989*/
990int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
991{
992	int i;
993
994	/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
995	for (i=0;i<msg->num_elements;i++) {
996		msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
997	}
998
999	/* modify the samdb record */
1000	return ldb_modify(sam_ldb, msg);
1001}
1002
1003/*
1004  return a default security descriptor
1005*/
1006struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1007{
1008	struct security_descriptor *sd;
1009
1010	sd = security_descriptor_initialise(mem_ctx);
1011
1012	return sd;
1013}
1014
1015struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1016{
1017	return ldb_get_default_basedn(sam_ctx);
1018}
1019
1020struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
1021{
1022	return ldb_get_config_basedn(sam_ctx);
1023}
1024
1025struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
1026{
1027	return ldb_get_schema_basedn(sam_ctx);
1028}
1029
1030struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
1031{
1032	return ldb_get_root_basedn(sam_ctx);
1033}
1034
1035struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1036{
1037	struct ldb_dn *new_dn;
1038
1039	new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1040	if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1041		talloc_free(new_dn);
1042		return NULL;
1043	}
1044	return new_dn;
1045}
1046
1047struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1048{
1049	struct ldb_dn *new_dn;
1050
1051	new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1052	if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1053		talloc_free(new_dn);
1054		return NULL;
1055	}
1056	return new_dn;
1057}
1058
1059/*
1060  work out the domain sid for the current open ldb
1061*/
1062const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1063{
1064	TALLOC_CTX *tmp_ctx;
1065	const struct dom_sid *domain_sid;
1066	const char *attrs[] = {
1067		"objectSid",
1068		NULL
1069	};
1070	struct ldb_result *res;
1071	int ret;
1072
1073	/* see if we have a cached copy */
1074	domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1075	if (domain_sid) {
1076		return domain_sid;
1077	}
1078
1079	tmp_ctx = talloc_new(ldb);
1080	if (tmp_ctx == NULL) {
1081		goto failed;
1082	}
1083
1084	ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1085
1086	if (ret != LDB_SUCCESS) {
1087		goto failed;
1088	}
1089
1090	if (res->count != 1) {
1091		goto failed;
1092	}
1093
1094	domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1095	if (domain_sid == NULL) {
1096		goto failed;
1097	}
1098
1099	/* cache the domain_sid in the ldb */
1100	if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1101		goto failed;
1102	}
1103
1104	talloc_steal(ldb, domain_sid);
1105	talloc_free(tmp_ctx);
1106
1107	return domain_sid;
1108
1109failed:
1110	DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1111	talloc_free(tmp_ctx);
1112	return NULL;
1113}
1114
1115bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1116{
1117	TALLOC_CTX *tmp_ctx;
1118	struct dom_sid *dom_sid_new;
1119	struct dom_sid *dom_sid_old;
1120
1121	/* see if we have a cached copy */
1122	dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1123						     "cache.domain_sid"), struct dom_sid);
1124
1125	tmp_ctx = talloc_new(ldb);
1126	if (tmp_ctx == NULL) {
1127		goto failed;
1128	}
1129
1130	dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1131	if (!dom_sid_new) {
1132		goto failed;
1133	}
1134
1135	/* cache the domain_sid in the ldb */
1136	if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1137		goto failed;
1138	}
1139
1140	talloc_steal(ldb, dom_sid_new);
1141	talloc_free(tmp_ctx);
1142	talloc_free(dom_sid_old);
1143
1144	return true;
1145
1146failed:
1147	DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1148	talloc_free(tmp_ctx);
1149	return false;
1150}
1151
1152/* Obtain the short name of the flexible single master operator
1153 * (FSMO), such as the PDC Emulator */
1154const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
1155			     const char *attr)
1156{
1157	/* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1158	struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1159	const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1160	const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1161
1162	if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1163		/* Ensure this matches the format.  This gives us a
1164		 * bit more confidence that a 'cn' value will be a
1165		 * ascii string */
1166		return NULL;
1167	}
1168	if (val) {
1169		return (char *)val->data;
1170	}
1171	return NULL;
1172}
1173
1174/*
1175  work out the ntds settings dn for the current open ldb
1176*/
1177struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
1178{
1179	TALLOC_CTX *tmp_ctx;
1180	const char *root_attrs[] = { "dsServiceName", NULL };
1181	int ret;
1182	struct ldb_result *root_res;
1183	struct ldb_dn *settings_dn;
1184
1185	/* see if we have a cached copy */
1186	settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1187	if (settings_dn) {
1188		return settings_dn;
1189	}
1190
1191	tmp_ctx = talloc_new(ldb);
1192	if (tmp_ctx == NULL) {
1193		goto failed;
1194	}
1195
1196	ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1197	if (ret) {
1198		DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1199			 ldb_errstring(ldb)));
1200		goto failed;
1201	}
1202
1203	if (root_res->count != 1) {
1204		goto failed;
1205	}
1206
1207	settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1208
1209	/* cache the domain_sid in the ldb */
1210	if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1211		goto failed;
1212	}
1213
1214	talloc_steal(ldb, settings_dn);
1215	talloc_free(tmp_ctx);
1216
1217	return settings_dn;
1218
1219failed:
1220	DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1221	talloc_free(tmp_ctx);
1222	return NULL;
1223}
1224
1225/*
1226  work out the ntds settings invocationId for the current open ldb
1227*/
1228const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1229{
1230	TALLOC_CTX *tmp_ctx;
1231	const char *attrs[] = { "invocationId", NULL };
1232	int ret;
1233	struct ldb_result *res;
1234	struct GUID *invocation_id;
1235
1236	/* see if we have a cached copy */
1237	invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1238	if (invocation_id) {
1239		return invocation_id;
1240	}
1241
1242	tmp_ctx = talloc_new(ldb);
1243	if (tmp_ctx == NULL) {
1244		goto failed;
1245	}
1246
1247	ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1248	if (ret) {
1249		goto failed;
1250	}
1251
1252	if (res->count != 1) {
1253		goto failed;
1254	}
1255
1256	invocation_id = talloc(tmp_ctx, struct GUID);
1257	if (!invocation_id) {
1258		goto failed;
1259	}
1260
1261	*invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1262
1263	/* cache the domain_sid in the ldb */
1264	if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1265		goto failed;
1266	}
1267
1268	talloc_steal(ldb, invocation_id);
1269	talloc_free(tmp_ctx);
1270
1271	return invocation_id;
1272
1273failed:
1274	DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1275	talloc_free(tmp_ctx);
1276	return NULL;
1277}
1278
1279bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1280{
1281	TALLOC_CTX *tmp_ctx;
1282	struct GUID *invocation_id_new;
1283	struct GUID *invocation_id_old;
1284
1285	/* see if we have a cached copy */
1286	invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1287							 "cache.invocation_id");
1288
1289	tmp_ctx = talloc_new(ldb);
1290	if (tmp_ctx == NULL) {
1291		goto failed;
1292	}
1293
1294	invocation_id_new = talloc(tmp_ctx, struct GUID);
1295	if (!invocation_id_new) {
1296		goto failed;
1297	}
1298
1299	*invocation_id_new = *invocation_id_in;
1300
1301	/* cache the domain_sid in the ldb */
1302	if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1303		goto failed;
1304	}
1305
1306	talloc_steal(ldb, invocation_id_new);
1307	talloc_free(tmp_ctx);
1308	talloc_free(invocation_id_old);
1309
1310	return true;
1311
1312failed:
1313	DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1314	talloc_free(tmp_ctx);
1315	return false;
1316}
1317
1318/*
1319  work out the ntds settings objectGUID for the current open ldb
1320*/
1321const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1322{
1323	TALLOC_CTX *tmp_ctx;
1324	const char *attrs[] = { "objectGUID", NULL };
1325	int ret;
1326	struct ldb_result *res;
1327	struct GUID *ntds_guid;
1328
1329	/* see if we have a cached copy */
1330	ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1331	if (ntds_guid) {
1332		return ntds_guid;
1333	}
1334
1335	tmp_ctx = talloc_new(ldb);
1336	if (tmp_ctx == NULL) {
1337		goto failed;
1338	}
1339
1340	ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1341	if (ret) {
1342		goto failed;
1343	}
1344
1345	if (res->count != 1) {
1346		goto failed;
1347	}
1348
1349	ntds_guid = talloc(tmp_ctx, struct GUID);
1350	if (!ntds_guid) {
1351		goto failed;
1352	}
1353
1354	*ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1355
1356	/* cache the domain_sid in the ldb */
1357	if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1358		goto failed;
1359	}
1360
1361	talloc_steal(ldb, ntds_guid);
1362	talloc_free(tmp_ctx);
1363
1364	return ntds_guid;
1365
1366failed:
1367	DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1368	talloc_free(tmp_ctx);
1369	return NULL;
1370}
1371
1372bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1373{
1374	TALLOC_CTX *tmp_ctx;
1375	struct GUID *ntds_guid_new;
1376	struct GUID *ntds_guid_old;
1377
1378	/* see if we have a cached copy */
1379	ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1380
1381	tmp_ctx = talloc_new(ldb);
1382	if (tmp_ctx == NULL) {
1383		goto failed;
1384	}
1385
1386	ntds_guid_new = talloc(tmp_ctx, struct GUID);
1387	if (!ntds_guid_new) {
1388		goto failed;
1389	}
1390
1391	*ntds_guid_new = *ntds_guid_in;
1392
1393	/* cache the domain_sid in the ldb */
1394	if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1395		goto failed;
1396	}
1397
1398	talloc_steal(ldb, ntds_guid_new);
1399	talloc_free(tmp_ctx);
1400	talloc_free(ntds_guid_old);
1401
1402	return true;
1403
1404failed:
1405	DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1406	talloc_free(tmp_ctx);
1407	return false;
1408}
1409
1410/*
1411  work out the server dn for the current open ldb
1412*/
1413struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1414{
1415	return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1416}
1417
1418/*
1419  work out the server dn for the current open ldb
1420*/
1421struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1422{
1423	struct ldb_dn *server_dn;
1424	struct ldb_dn *server_site_dn;
1425
1426	server_dn = samdb_server_dn(ldb, mem_ctx);
1427	if (!server_dn) return NULL;
1428
1429	server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1430
1431	talloc_free(server_dn);
1432	return server_site_dn;
1433}
1434
1435/*
1436 * This works out if we are running on a supported forest/domain function
1437 * level. Basically this means that we don't support mixed/interim (NT 4 DC
1438 * support) levels.
1439 * If errmsg isn't NULL we write in an adequate error message for printing out
1440 * to the screen.
1441 */
1442bool samdb_is_capable_dc(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1443	char **errmsg)
1444{
1445	int32_t level_forest, level_domain, level_domain_mixed;
1446	bool ret = true;
1447
1448	level_forest = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1449		samdb_partitions_dn(ldb, mem_ctx), "msDS-Behavior-Version",
1450		NULL);
1451	level_domain = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1452		samdb_base_dn(ldb), "msDS-Behavior-Version", NULL);
1453	level_domain_mixed = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
1454		samdb_base_dn(ldb), "nTMixedDomain", NULL);
1455
1456	if (errmsg != NULL)
1457		*errmsg = talloc_strdup(mem_ctx, "");
1458
1459	if (level_forest == -1 || level_domain == -1 || level_domain_mixed == -1) {
1460		ret = false;
1461		if (errmsg != NULL)
1462			*errmsg = talloc_strdup_append(*errmsg,
1463				"\nATTENTION: Invalid values for forest and/or domain function level!"
1464			);
1465	}
1466
1467	if (level_forest == DS_DOMAIN_FUNCTION_2003_MIXED) {
1468		ret = false;
1469		if (errmsg != NULL)
1470			*errmsg = talloc_strdup_append(*errmsg,
1471				"\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported!"
1472			);
1473	}
1474	if ((level_domain == DS_DOMAIN_FUNCTION_2000 && level_domain_mixed != 0)
1475		|| level_domain == DS_DOMAIN_FUNCTION_2003_MIXED) {
1476		ret = false;
1477		if (errmsg != NULL)
1478			*errmsg = talloc_strdup_append(*errmsg,
1479				"\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported!"
1480			);
1481	}
1482
1483	if ((!ret) && (errmsg != NULL)) {
1484		*errmsg = talloc_strdup_append(*errmsg,
1485			"\nPlease raise the domain and/or forest level to an adequate value. Use for this the 'domainlevel' tool, the MS AD MMC tools or manipulate the needed attributes directly."
1486		);
1487	}
1488
1489	return ret;
1490}
1491
1492/*
1493  work out if we are the PDC for the domain of the current open ldb
1494*/
1495bool samdb_is_pdc(struct ldb_context *ldb)
1496{
1497	const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1498	int ret;
1499	struct ldb_result *dom_res;
1500	TALLOC_CTX *tmp_ctx;
1501	bool is_pdc;
1502	struct ldb_dn *pdc;
1503
1504	tmp_ctx = talloc_new(ldb);
1505	if (tmp_ctx == NULL) {
1506		DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1507		return false;
1508	}
1509
1510	ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1511	if (ret) {
1512		DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1513			 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1514			 ldb_errstring(ldb)));
1515		goto failed;
1516	}
1517	if (dom_res->count != 1) {
1518		goto failed;
1519	}
1520
1521	pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1522
1523	if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1524		is_pdc = true;
1525	} else {
1526		is_pdc = false;
1527	}
1528
1529	talloc_free(tmp_ctx);
1530
1531	return is_pdc;
1532
1533failed:
1534	DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1535	talloc_free(tmp_ctx);
1536	return false;
1537}
1538
1539/*
1540  work out if we are a Global Catalog server for the domain of the current open ldb
1541*/
1542bool samdb_is_gc(struct ldb_context *ldb)
1543{
1544	const char *attrs[] = { "options", NULL };
1545	int ret, options;
1546	struct ldb_result *res;
1547	TALLOC_CTX *tmp_ctx;
1548
1549	tmp_ctx = talloc_new(ldb);
1550	if (tmp_ctx == NULL) {
1551		DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1552		return false;
1553	}
1554
1555	/* Query cn=ntds settings,.... */
1556	ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1557	if (ret) {
1558		talloc_free(tmp_ctx);
1559		return false;
1560	}
1561	if (res->count != 1) {
1562		talloc_free(tmp_ctx);
1563		return false;
1564	}
1565
1566	options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1567	talloc_free(tmp_ctx);
1568
1569	/* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1570	if (options & 0x000000001) {
1571		return true;
1572	}
1573	return false;
1574}
1575
1576/* Find a domain object in the parents of a particular DN.  */
1577int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
1578				   struct ldb_dn **parent_dn, const char **errstring)
1579{
1580	TALLOC_CTX *local_ctx;
1581	struct ldb_dn *sdn = dn;
1582	struct ldb_result *res = NULL;
1583	int ret = 0;
1584	const char *attrs[] = { NULL };
1585
1586	local_ctx = talloc_new(mem_ctx);
1587	if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1588
1589	while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1590		ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1591				 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1592		if (ret == LDB_SUCCESS) {
1593			if (res->count == 1) {
1594				break;
1595			}
1596		} else {
1597			break;
1598		}
1599	}
1600
1601	if (ret != LDB_SUCCESS) {
1602		*errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1603					     ldb_dn_get_linearized(dn),
1604					     ldb_dn_get_linearized(sdn),
1605					     ldb_errstring(ldb));
1606		talloc_free(local_ctx);
1607		return ret;
1608	}
1609	if (res->count != 1) {
1610		*errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1611					     ldb_dn_get_linearized(dn));
1612		DEBUG(0,(__location__ ": %s\n", *errstring));
1613		talloc_free(local_ctx);
1614		return LDB_ERR_CONSTRAINT_VIOLATION;
1615	}
1616
1617	*parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1618	talloc_free(local_ctx);
1619	return ret;
1620}
1621
1622
1623/*
1624  set the user password using plaintext, obeying any user or domain
1625  password restrictions
1626
1627  note that this function doesn't actually store the result in the
1628  database, it just fills in the "mod" structure with ldb modify
1629  elements to setup the correct change when samdb_replace() is
1630  called. This allows the caller to combine the change with other
1631  changes (as is needed by some of the set user info levels)
1632
1633  The caller should probably have a transaction wrapping this
1634*/
1635NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1636			    struct ldb_dn *user_dn,
1637			    struct ldb_dn *domain_dn,
1638			    struct ldb_message *mod,
1639			    const DATA_BLOB *new_password,
1640			    struct samr_Password *param_lmNewHash,
1641			    struct samr_Password *param_ntNewHash,
1642			    bool user_change,
1643			    enum samr_RejectReason *reject_reason,
1644			    struct samr_DomInfo1 **_dominfo)
1645{
1646	const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1647					    "ntPwdHistory",
1648					    "dBCSPwd", "unicodePwd",
1649					    "objectSid",
1650					    "pwdLastSet", NULL };
1651	const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1652					      "maxPwdAge", "minPwdAge",
1653					      "minPwdLength", NULL };
1654	NTTIME pwdLastSet;
1655	int64_t minPwdAge;
1656	uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1657	uint_t userAccountControl;
1658	struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
1659		*lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
1660	struct samr_Password local_lmNewHash, local_ntNewHash;
1661	int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1662	struct dom_sid *domain_sid;
1663	struct ldb_message **res;
1664	bool restrictions;
1665	int count;
1666	time_t now = time(NULL);
1667	NTTIME now_nt;
1668	int i;
1669
1670	/* we need to know the time to compute password age */
1671	unix_to_nt_time(&now_nt, now);
1672
1673	/* pull all the user parameters */
1674	count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1675	if (count != 1) {
1676		return NT_STATUS_INTERNAL_DB_CORRUPTION;
1677	}
1678	userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1679	sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0],
1680						 "lmPwdHistory", &sambaLMPwdHistory);
1681	sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0],
1682						 "ntPwdHistory", &sambaNTPwdHistory);
1683	lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1684	ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1685	pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1686
1687	/* Copy parameters */
1688	lmNewHash = param_lmNewHash;
1689	ntNewHash = param_ntNewHash;
1690
1691	/* Only non-trust accounts have restrictions (possibly this
1692	 * test is the wrong way around, but I like to be restrictive
1693	 * if possible */
1694	restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1695					       |UF_WORKSTATION_TRUST_ACCOUNT
1696					       |UF_SERVER_TRUST_ACCOUNT));
1697
1698	if (domain_dn) {
1699		/* pull the domain parameters */
1700		count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1701		if (count != 1) {
1702			DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1703				  ldb_dn_get_linearized(domain_dn),
1704				  ldb_dn_get_linearized(user_dn)));
1705			return NT_STATUS_NO_SUCH_DOMAIN;
1706		}
1707	} else {
1708		/* work out the domain sid, and pull the domain from there */
1709		domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1710		if (domain_sid == NULL) {
1711			return NT_STATUS_INTERNAL_DB_CORRUPTION;
1712		}
1713
1714		count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1715				     "(objectSid=%s)",
1716				     ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1717		if (count != 1) {
1718			DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1719				  dom_sid_string(mem_ctx, domain_sid),
1720				  ldb_dn_get_linearized(user_dn)));
1721			return NT_STATUS_NO_SUCH_DOMAIN;
1722		}
1723	}
1724
1725	pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1726	pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1727	minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1728	minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1729
1730	if (userAccountControl & UF_PASSWD_NOTREQD) {
1731		/* see [MS-ADTS] 2.2.15 */
1732		minPwdLength = 0;
1733	}
1734
1735	if (_dominfo) {
1736		struct samr_DomInfo1 *dominfo;
1737		/* on failure we need to fill in the reject reasons */
1738		dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1739		if (dominfo == NULL) {
1740			return NT_STATUS_NO_MEMORY;
1741		}
1742		dominfo->min_password_length     = minPwdLength;
1743		dominfo->password_properties     = pwdProperties;
1744		dominfo->password_history_length = pwdHistoryLength;
1745		dominfo->max_password_age        = minPwdAge;
1746		dominfo->min_password_age        = minPwdAge;
1747		*_dominfo = dominfo;
1748	}
1749
1750	if (restrictions && new_password) {
1751		char *new_pass;
1752
1753		/* check the various password restrictions */
1754		if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1755			if (reject_reason) {
1756				*reject_reason = SAMR_REJECT_TOO_SHORT;
1757			}
1758			return NT_STATUS_PASSWORD_RESTRICTION;
1759		}
1760
1761		/* Create the NT hash */
1762		mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1763
1764		ntNewHash = &local_ntNewHash;
1765
1766		/* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
1767		if (convert_string_talloc_convenience(mem_ctx,
1768			  lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1769			  CH_UTF16, CH_UNIX,
1770			  new_password->data, new_password->length,
1771			  (void **)&new_pass, NULL, false)) {
1772
1773			/* possibly check password complexity */
1774			if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
1775			    !check_password_quality(new_pass)) {
1776				if (reject_reason) {
1777					*reject_reason = SAMR_REJECT_COMPLEXITY;
1778				}
1779				return NT_STATUS_PASSWORD_RESTRICTION;
1780			}
1781
1782			/* compute the new lm hashes (for checking history - case insenitivly!) */
1783			if (E_deshash(new_pass, local_lmNewHash.hash)) {
1784				lmNewHash = &local_lmNewHash;
1785			}
1786		}
1787	}
1788
1789	if (restrictions && user_change) {
1790		/* are all password changes disallowed? */
1791		if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1792			if (reject_reason) {
1793				*reject_reason = SAMR_REJECT_OTHER;
1794			}
1795			return NT_STATUS_PASSWORD_RESTRICTION;
1796		}
1797
1798		/* can this user change password? */
1799		if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1800			if (reject_reason) {
1801				*reject_reason = SAMR_REJECT_OTHER;
1802			}
1803			return NT_STATUS_PASSWORD_RESTRICTION;
1804		}
1805
1806		/* yes, this is a minus. The ages are in negative 100nsec units! */
1807		if (pwdLastSet - minPwdAge > now_nt) {
1808			if (reject_reason) {
1809				*reject_reason = SAMR_REJECT_OTHER;
1810			}
1811			return NT_STATUS_PASSWORD_RESTRICTION;
1812		}
1813
1814		/* check the immediately past password */
1815		if (pwdHistoryLength > 0) {
1816			if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1817				if (reject_reason) {
1818					*reject_reason = SAMR_REJECT_IN_HISTORY;
1819				}
1820				return NT_STATUS_PASSWORD_RESTRICTION;
1821			}
1822			if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1823				if (reject_reason) {
1824					*reject_reason = SAMR_REJECT_IN_HISTORY;
1825				}
1826				return NT_STATUS_PASSWORD_RESTRICTION;
1827			}
1828		}
1829
1830		/* check the password history */
1831		sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1832		sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1833
1834		for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1835			if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1836				if (reject_reason) {
1837					*reject_reason = SAMR_REJECT_IN_HISTORY;
1838				}
1839				return NT_STATUS_PASSWORD_RESTRICTION;
1840			}
1841		}
1842		for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1843			if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1844				if (reject_reason) {
1845					*reject_reason = SAMR_REJECT_IN_HISTORY;
1846				}
1847				return NT_STATUS_PASSWORD_RESTRICTION;
1848			}
1849		}
1850	}
1851
1852#define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1853
1854	/* the password is acceptable. Start forming the new fields */
1855	if (new_password) {
1856		/* if we know the cleartext UTF16 password, then set it.
1857		 * Modules in ldb will set all the appropriate
1858		 * hashes */
1859		CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1860	} else {
1861		/* We don't have the cleartext, so delete the old one
1862		 * and set what we have of the hashes */
1863		CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1864
1865		if (lmNewHash) {
1866			CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1867		} else {
1868			CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1869		}
1870
1871		if (ntNewHash) {
1872			CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1873		} else {
1874			CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1875		}
1876	}
1877
1878	return NT_STATUS_OK;
1879}
1880
1881
1882/*
1883  set the user password using plaintext, obeying any user or domain
1884  password restrictions
1885
1886  This wrapper function takes a SID as input, rather than a user DN,
1887  and actually performs the password change
1888
1889*/
1890NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1891				const struct dom_sid *user_sid,
1892				const DATA_BLOB *new_pass,
1893				struct samr_Password *lmNewHash,
1894				struct samr_Password *ntNewHash,
1895				bool user_change,
1896				enum samr_RejectReason *reject_reason,
1897				struct samr_DomInfo1 **_dominfo)
1898{
1899	NTSTATUS nt_status;
1900	struct ldb_dn *user_dn;
1901	struct ldb_message *msg;
1902	int ret;
1903
1904	ret = ldb_transaction_start(ctx);
1905	if (ret) {
1906		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1907		return NT_STATUS_TRANSACTION_ABORTED;
1908	}
1909
1910	user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1911				  "(&(objectSid=%s)(objectClass=user))",
1912				  ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1913	if (!user_dn) {
1914		ldb_transaction_cancel(ctx);
1915		DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1916			  dom_sid_string(mem_ctx, user_sid)));
1917		return NT_STATUS_NO_SUCH_USER;
1918	}
1919
1920	msg = ldb_msg_new(mem_ctx);
1921	if (msg == NULL) {
1922		ldb_transaction_cancel(ctx);
1923		return NT_STATUS_NO_MEMORY;
1924	}
1925
1926	msg->dn = ldb_dn_copy(msg, user_dn);
1927	if (!msg->dn) {
1928		ldb_transaction_cancel(ctx);
1929		return NT_STATUS_NO_MEMORY;
1930	}
1931
1932	nt_status = samdb_set_password(ctx, mem_ctx,
1933				       user_dn, NULL,
1934				       msg, new_pass,
1935				       lmNewHash, ntNewHash,
1936				       user_change, /* This is a password set, not change */
1937				       reject_reason, _dominfo);
1938	if (!NT_STATUS_IS_OK(nt_status)) {
1939		ldb_transaction_cancel(ctx);
1940		return nt_status;
1941	}
1942
1943	/* modify the samdb record */
1944	ret = samdb_replace(ctx, mem_ctx, msg);
1945	if (ret != 0) {
1946		ldb_transaction_cancel(ctx);
1947		return NT_STATUS_ACCESS_DENIED;
1948	}
1949
1950	ret = ldb_transaction_commit(ctx);
1951	if (ret != 0) {
1952		DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1953			 ldb_dn_get_linearized(msg->dn),
1954			 ldb_errstring(ctx)));
1955		return NT_STATUS_TRANSACTION_ABORTED;
1956	}
1957	return NT_STATUS_OK;
1958}
1959
1960
1961
1962NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1963						 struct dom_sid *sid, struct ldb_dn **ret_dn)
1964{
1965	struct ldb_message *msg;
1966	struct ldb_dn *basedn;
1967	const char *sidstr;
1968	int ret;
1969
1970	sidstr = dom_sid_string(mem_ctx, sid);
1971	NT_STATUS_HAVE_NO_MEMORY(sidstr);
1972
1973	/* We might have to create a ForeignSecurityPrincipal, even if this user
1974	 * is in our own domain */
1975
1976	msg = ldb_msg_new(mem_ctx);
1977	if (msg == NULL) {
1978		return NT_STATUS_NO_MEMORY;
1979	}
1980
1981	/* TODO: Hmmm. This feels wrong. How do I find the base dn to
1982	 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1983	 * not work, this is wrong for the Builtin domain, there's no
1984	 * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1985	 */
1986
1987	basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1988				 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1989
1990	if (basedn == NULL) {
1991		DEBUG(0, ("Failed to find DN for "
1992			  "ForeignSecurityPrincipal container\n"));
1993		return NT_STATUS_INTERNAL_DB_CORRUPTION;
1994	}
1995
1996	/* add core elements to the ldb_message for the alias */
1997	msg->dn = ldb_dn_copy(mem_ctx, basedn);
1998	if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1999		return NT_STATUS_NO_MEMORY;
2000
2001	samdb_msg_add_string(sam_ctx, mem_ctx, msg,
2002			     "objectClass",
2003			     "foreignSecurityPrincipal");
2004
2005	/* create the alias */
2006	ret = ldb_add(sam_ctx, msg);
2007	if (ret != 0) {
2008		DEBUG(0,("Failed to create foreignSecurityPrincipal "
2009			 "record %s: %s\n",
2010			 ldb_dn_get_linearized(msg->dn),
2011			 ldb_errstring(sam_ctx)));
2012		return NT_STATUS_INTERNAL_DB_CORRUPTION;
2013	}
2014	*ret_dn = msg->dn;
2015	return NT_STATUS_OK;
2016}
2017
2018
2019/*
2020  Find the DN of a domain, assuming it to be a dotted.dns name
2021*/
2022
2023struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
2024{
2025	int i;
2026	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2027	const char *binary_encoded;
2028	const char **split_realm;
2029	struct ldb_dn *dn;
2030
2031	if (!tmp_ctx) {
2032		return NULL;
2033	}
2034
2035	split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
2036	if (!split_realm) {
2037		talloc_free(tmp_ctx);
2038		return NULL;
2039	}
2040	dn = ldb_dn_new(mem_ctx, ldb, NULL);
2041	for (i=0; split_realm[i]; i++) {
2042		binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2043		if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2044			DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2045				  binary_encoded, ldb_dn_get_linearized(dn)));
2046			talloc_free(tmp_ctx);
2047			return NULL;
2048		}
2049	}
2050	if (!ldb_dn_validate(dn)) {
2051		DEBUG(2, ("Failed to validated DN %s\n",
2052			  ldb_dn_get_linearized(dn)));
2053		return NULL;
2054	}
2055	return dn;
2056}
2057/*
2058  Find the DN of a domain, be it the netbios or DNS name
2059*/
2060
2061struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2062				  const char *domain_name)
2063{
2064	const char * const domain_ref_attrs[] = {
2065		"ncName", NULL
2066	};
2067	const char * const domain_ref2_attrs[] = {
2068		NULL
2069	};
2070	struct ldb_result *res_domain_ref;
2071	char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
2072	/* find the domain's DN */
2073	int ret_domain = ldb_search(ldb, mem_ctx,
2074					    &res_domain_ref,
2075					    samdb_partitions_dn(ldb, mem_ctx),
2076					    LDB_SCOPE_ONELEVEL,
2077					    domain_ref_attrs,
2078					    "(&(nETBIOSName=%s)(objectclass=crossRef))",
2079					    escaped_domain);
2080	if (ret_domain != 0) {
2081		return NULL;
2082	}
2083
2084	if (res_domain_ref->count == 0) {
2085		ret_domain = ldb_search(ldb, mem_ctx,
2086						&res_domain_ref,
2087						samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2088						LDB_SCOPE_BASE,
2089						domain_ref2_attrs,
2090						"(objectclass=domain)");
2091		if (ret_domain != 0) {
2092			return NULL;
2093		}
2094
2095		if (res_domain_ref->count == 1) {
2096			return res_domain_ref->msgs[0]->dn;
2097		}
2098		return NULL;
2099	}
2100
2101	if (res_domain_ref->count > 1) {
2102		DEBUG(0,("Found %d records matching domain [%s]\n",
2103			 ret_domain, domain_name));
2104		return NULL;
2105	}
2106
2107	return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2108
2109}
2110
2111
2112/*
2113  use a GUID to find a DN
2114 */
2115int dsdb_find_dn_by_guid(struct ldb_context *ldb,
2116			 TALLOC_CTX *mem_ctx,
2117			 const char *guid_str, struct ldb_dn **dn)
2118{
2119	int ret;
2120	struct ldb_result *res;
2121	const char *attrs[] = { NULL };
2122	struct ldb_request *search_req;
2123	char *expression;
2124	struct ldb_search_options_control *options;
2125
2126	expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
2127	if (!expression) {
2128		DEBUG(0, (__location__ ": out of memory\n"));
2129		return LDB_ERR_OPERATIONS_ERROR;
2130	}
2131
2132	res = talloc_zero(mem_ctx, struct ldb_result);
2133	if (!res) {
2134		DEBUG(0, (__location__ ": out of memory\n"));
2135		return LDB_ERR_OPERATIONS_ERROR;
2136	}
2137
2138	ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
2139				   ldb_get_default_basedn(ldb),
2140				   LDB_SCOPE_SUBTREE,
2141				   expression, attrs,
2142				   NULL,
2143				   res, ldb_search_default_callback,
2144				   NULL);
2145	if (ret != LDB_SUCCESS) {
2146		return ret;
2147	}
2148
2149	/* we need to cope with cross-partition links, so search for
2150	   the GUID over all partitions */
2151	options = talloc(search_req, struct ldb_search_options_control);
2152	if (options == NULL) {
2153		DEBUG(0, (__location__ ": out of memory\n"));
2154		return LDB_ERR_OPERATIONS_ERROR;
2155	}
2156	options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2157
2158	ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
2159	if (ret != LDB_SUCCESS) {
2160		return ret;
2161	}
2162
2163	ret = ldb_request_add_control(search_req,
2164				      LDB_CONTROL_SEARCH_OPTIONS_OID,
2165				      true, options);
2166	if (ret != LDB_SUCCESS) {
2167		return ret;
2168	}
2169
2170	ret = ldb_request(ldb, search_req);
2171	if (ret != LDB_SUCCESS) {
2172		return ret;
2173	}
2174
2175	ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
2176	if (ret != LDB_SUCCESS) {
2177		return ret;
2178	}
2179
2180	/* this really should be exactly 1, but there is a bug in the
2181	   partitions module that can return two here with the
2182	   search_options control set */
2183	if (res->count < 1) {
2184		return LDB_ERR_NO_SUCH_OBJECT;
2185	}
2186
2187	*dn = res->msgs[0]->dn;
2188
2189	return LDB_SUCCESS;
2190}
2191
2192/*
2193  search for attrs on one DN, allowing for deleted objects
2194 */
2195int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
2196				TALLOC_CTX *mem_ctx,
2197				struct ldb_result **_res,
2198				struct ldb_dn *basedn,
2199				const char * const *attrs)
2200{
2201	int ret;
2202	struct ldb_request *req;
2203	TALLOC_CTX *tmp_ctx;
2204	struct ldb_result *res;
2205
2206	tmp_ctx = talloc_new(mem_ctx);
2207
2208	res = talloc_zero(tmp_ctx, struct ldb_result);
2209	if (!res) {
2210		return LDB_ERR_OPERATIONS_ERROR;
2211	}
2212
2213	ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2214				   basedn,
2215				   LDB_SCOPE_BASE,
2216				   NULL,
2217				   attrs,
2218				   NULL,
2219				   res,
2220				   ldb_search_default_callback,
2221				   NULL);
2222	if (ret != LDB_SUCCESS) {
2223		talloc_free(tmp_ctx);
2224		return ret;
2225	}
2226
2227	ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2228	if (ret != LDB_SUCCESS) {
2229		return ret;
2230	}
2231
2232	ret = ldb_request(ldb, req);
2233	if (ret == LDB_SUCCESS) {
2234		ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2235	}
2236
2237	talloc_free(req);
2238	*_res = talloc_steal(mem_ctx, res);
2239	return ret;
2240}
2241
2242
2243/*
2244  use a DN to find a GUID
2245 */
2246int dsdb_find_guid_by_dn(struct ldb_context *ldb,
2247			 struct ldb_dn *dn, struct GUID *guid)
2248{
2249	int ret;
2250	struct ldb_result *res;
2251	const char *attrs[] = { "objectGUID", NULL };
2252	TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2253
2254	ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2255	if (ret != LDB_SUCCESS) {
2256		talloc_free(tmp_ctx);
2257		return ret;
2258	}
2259	if (res->count < 1) {
2260		talloc_free(tmp_ctx);
2261		return LDB_ERR_NO_SUCH_OBJECT;
2262	}
2263	*guid = samdb_result_guid(res->msgs[0], "objectGUID");
2264	talloc_free(tmp_ctx);
2265	return LDB_SUCCESS;
2266}
2267
2268/*
2269  use a DN to find a SID
2270 */
2271int dsdb_find_sid_by_dn(struct ldb_context *ldb,
2272			struct ldb_dn *dn, struct dom_sid *sid)
2273{
2274	int ret;
2275	struct ldb_result *res;
2276	const char *attrs[] = { "objectSID", NULL };
2277	TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2278	struct dom_sid *s;
2279
2280	ZERO_STRUCTP(sid);
2281
2282	ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
2283	if (ret != LDB_SUCCESS) {
2284		talloc_free(tmp_ctx);
2285		return ret;
2286	}
2287	if (res->count < 1) {
2288		talloc_free(tmp_ctx);
2289		return LDB_ERR_NO_SUCH_OBJECT;
2290	}
2291	s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
2292	if (s == NULL) {
2293		talloc_free(tmp_ctx);
2294		return LDB_ERR_NO_SUCH_OBJECT;
2295	}
2296	*sid = *s;
2297	talloc_free(tmp_ctx);
2298	return LDB_SUCCESS;
2299}
2300
2301
2302
2303/*
2304  load a repsFromTo blob list for a given partition GUID
2305  attr must be "repsFrom" or "repsTo"
2306 */
2307WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2308		     const char *attr, struct repsFromToBlob **r, uint32_t *count)
2309{
2310	const char *attrs[] = { attr, NULL };
2311	struct ldb_result *res = NULL;
2312	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2313	int i;
2314	struct ldb_message_element *el;
2315
2316	*r = NULL;
2317	*count = 0;
2318
2319	if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
2320	    res->count < 1) {
2321		DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
2322		talloc_free(tmp_ctx);
2323		return WERR_DS_DRA_INTERNAL_ERROR;
2324	}
2325
2326	el = ldb_msg_find_element(res->msgs[0], attr);
2327	if (el == NULL) {
2328		/* it's OK to be empty */
2329		talloc_free(tmp_ctx);
2330		return WERR_OK;
2331	}
2332
2333	*count = el->num_values;
2334	*r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
2335	if (*r == NULL) {
2336		talloc_free(tmp_ctx);
2337		return WERR_DS_DRA_INTERNAL_ERROR;
2338	}
2339
2340	for (i=0; i<(*count); i++) {
2341		enum ndr_err_code ndr_err;
2342		ndr_err = ndr_pull_struct_blob(&el->values[i],
2343					       mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2344					       &(*r)[i],
2345					       (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2346		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2347			talloc_free(tmp_ctx);
2348			return WERR_DS_DRA_INTERNAL_ERROR;
2349		}
2350	}
2351
2352	talloc_free(tmp_ctx);
2353
2354	return WERR_OK;
2355}
2356
2357/*
2358  save the repsFromTo blob list for a given partition GUID
2359  attr must be "repsFrom" or "repsTo"
2360 */
2361WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2362		     const char *attr, struct repsFromToBlob *r, uint32_t count)
2363{
2364	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2365	struct ldb_message *msg;
2366	struct ldb_message_element *el;
2367	int i;
2368
2369	msg = ldb_msg_new(tmp_ctx);
2370	msg->dn = dn;
2371	if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
2372		goto failed;
2373	}
2374
2375	el->values = talloc_array(msg, struct ldb_val, count);
2376	if (!el->values) {
2377		goto failed;
2378	}
2379
2380	for (i=0; i<count; i++) {
2381		struct ldb_val v;
2382		enum ndr_err_code ndr_err;
2383
2384		ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
2385					       &r[i],
2386					       (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2387		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2388			goto failed;
2389		}
2390
2391		el->num_values++;
2392		el->values[i] = v;
2393	}
2394
2395	if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
2396		DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
2397		goto failed;
2398	}
2399
2400	talloc_free(tmp_ctx);
2401
2402	return WERR_OK;
2403
2404failed:
2405	talloc_free(tmp_ctx);
2406	return WERR_DS_DRA_INTERNAL_ERROR;
2407}
2408
2409
2410/*
2411  load the uSNHighest attribute from the @REPLCHANGED object for a
2412  partition
2413 */
2414int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
2415{
2416	struct ldb_request *req;
2417	int ret;
2418	TALLOC_CTX *tmp_ctx = talloc_new(ldb);
2419	struct dsdb_control_current_partition *p_ctrl;
2420	struct ldb_result *res;
2421
2422	res = talloc_zero(tmp_ctx, struct ldb_result);
2423	if (!res) {
2424		talloc_free(tmp_ctx);
2425		return LDB_ERR_OPERATIONS_ERROR;
2426	}
2427
2428	ret = ldb_build_search_req(&req, ldb, tmp_ctx,
2429				   ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
2430				   LDB_SCOPE_BASE,
2431				   NULL, NULL,
2432				   NULL,
2433				   res, ldb_search_default_callback,
2434				   NULL);
2435	if (ret != LDB_SUCCESS) {
2436		talloc_free(tmp_ctx);
2437		return ret;
2438	}
2439
2440	p_ctrl = talloc(req, struct dsdb_control_current_partition);
2441	if (p_ctrl == NULL) {
2442		talloc_free(res);
2443		return LDB_ERR_OPERATIONS_ERROR;
2444	}
2445	p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2446	p_ctrl->dn = dn;
2447
2448
2449	ret = ldb_request_add_control(req,
2450				      DSDB_CONTROL_CURRENT_PARTITION_OID,
2451				      false, p_ctrl);
2452	if (ret != LDB_SUCCESS) {
2453		talloc_free(tmp_ctx);
2454		return ret;
2455	}
2456
2457	/* Run the new request */
2458	ret = ldb_request(ldb, req);
2459
2460	if (ret == LDB_SUCCESS) {
2461		ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2462	}
2463
2464	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2465		/* it hasn't been created yet, which means
2466		   an implicit value of zero */
2467		*uSN = 0;
2468		talloc_free(tmp_ctx);
2469		return LDB_SUCCESS;
2470	}
2471
2472	if (ret != LDB_SUCCESS) {
2473		talloc_free(tmp_ctx);
2474		return ret;
2475	}
2476
2477	if (res->count < 1) {
2478		*uSN = 0;
2479	} else {
2480		*uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
2481	}
2482
2483	talloc_free(tmp_ctx);
2484
2485	return LDB_SUCCESS;
2486}
2487
2488/*
2489  save the uSNHighest attribute in the @REPLCHANGED object for a
2490  partition
2491 */
2492int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
2493{
2494	struct ldb_request *req;
2495	struct ldb_message *msg;
2496	struct dsdb_control_current_partition *p_ctrl;
2497	int ret;
2498
2499	msg = ldb_msg_new(ldb);
2500	if (msg == NULL) {
2501		return LDB_ERR_OPERATIONS_ERROR;
2502	}
2503
2504	msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
2505	if (msg->dn == NULL) {
2506		talloc_free(msg);
2507		return LDB_ERR_OPERATIONS_ERROR;
2508	}
2509
2510	ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
2511	if (ret != LDB_SUCCESS) {
2512		talloc_free(msg);
2513		return ret;
2514	}
2515	msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
2516
2517
2518	p_ctrl = talloc(msg, struct dsdb_control_current_partition);
2519	if (p_ctrl == NULL) {
2520		talloc_free(msg);
2521		return LDB_ERR_OPERATIONS_ERROR;
2522	}
2523	p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
2524	p_ctrl->dn = dn;
2525
2526	ret = ldb_build_mod_req(&req, ldb, msg,
2527				msg,
2528				NULL,
2529				NULL, ldb_op_default_callback,
2530				NULL);
2531again:
2532	if (ret != LDB_SUCCESS) {
2533		talloc_free(msg);
2534		return ret;
2535	}
2536
2537	ret = ldb_request_add_control(req,
2538				      DSDB_CONTROL_CURRENT_PARTITION_OID,
2539				      false, p_ctrl);
2540	if (ret != LDB_SUCCESS) {
2541		talloc_free(msg);
2542		return ret;
2543	}
2544
2545	/* Run the new request */
2546	ret = ldb_request(ldb, req);
2547
2548	if (ret == LDB_SUCCESS) {
2549		ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2550	}
2551	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2552		ret = ldb_build_add_req(&req, ldb, msg,
2553					msg,
2554					NULL,
2555					NULL, ldb_op_default_callback,
2556					NULL);
2557		goto again;
2558	}
2559
2560	talloc_free(msg);
2561
2562	return ret;
2563}
2564
2565int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
2566						   const struct drsuapi_DsReplicaCursor2 *c2)
2567{
2568	return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
2569}
2570