CVE-2018-16857 dsdb/util: Correctly treat lockOutObservationWindow as 64-bit int
[samba.git] / source4 / dsdb / common / util.c
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_module.h"
28 #include "ldb_errors.h"
29 #include "../lib/util/util_ldb.h"
30 #include "../lib/crypto/crypto.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "../libds/common/flags.h"
36 #include "dsdb/common/proto.h"
37 #include "libcli/ldap/ldap_ndr.h"
38 #include "param/param.h"
39 #include "libcli/auth/libcli_auth.h"
40 #include "librpc/gen_ndr/ndr_drsblobs.h"
41 #include "system/locale.h"
42 #include "system/filesys.h"
43 #include "lib/util/tsort.h"
44 #include "dsdb/common/util.h"
45 #include "lib/socket/socket.h"
46 #include "librpc/gen_ndr/irpc.h"
47 #include "libds/common/flag_mapping.h"
48 #include "../lib/util/util_runcmd.h"
49 #include "lib/util/access.h"
50 #include "lib/util/util_str_hex.h"
51 #include "libcli/util/ntstatus.h"
52
53 /*
54  * This included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
55  * dsdb_request_add_controls()
56  */
57 #include "dsdb/samdb/ldb_modules/util.h"
58
59 /*
60   search the sam for the specified attributes in a specific domain, filter on
61   objectSid being in domain_sid.
62 */
63 int samdb_search_domain(struct ldb_context *sam_ldb,
64                         TALLOC_CTX *mem_ctx, 
65                         struct ldb_dn *basedn,
66                         struct ldb_message ***res,
67                         const char * const *attrs,
68                         const struct dom_sid *domain_sid,
69                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
70 {
71         va_list ap;
72         int i, count;
73
74         va_start(ap, format);
75         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
76                                res, attrs, format, ap);
77         va_end(ap);
78
79         i=0;
80
81         while (i<count) {
82                 struct dom_sid *entry_sid;
83
84                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
85
86                 if ((entry_sid == NULL) ||
87                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
88                         /* Delete that entry from the result set */
89                         (*res)[i] = (*res)[count-1];
90                         count -= 1;
91                         talloc_free(entry_sid);
92                         continue;
93                 }
94                 talloc_free(entry_sid);
95                 i += 1;
96         }
97
98         return count;
99 }
100
101 /*
102   search the sam for a single string attribute in exactly 1 record
103 */
104 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
105                                   TALLOC_CTX *mem_ctx,
106                                   struct ldb_dn *basedn,
107                                   const char *attr_name,
108                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
109 {
110         int count;
111         const char *attrs[2] = { NULL, NULL };
112         struct ldb_message **res = NULL;
113
114         attrs[0] = attr_name;
115
116         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
117         if (count > 1) {                
118                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
119                          attr_name, format, count));
120         }
121         if (count != 1) {
122                 talloc_free(res);
123                 return NULL;
124         }
125
126         return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
127 }
128
129 /*
130   search the sam for a single string attribute in exactly 1 record
131 */
132 const char *samdb_search_string(struct ldb_context *sam_ldb,
133                                 TALLOC_CTX *mem_ctx,
134                                 struct ldb_dn *basedn,
135                                 const char *attr_name,
136                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
137 {
138         va_list ap;
139         const char *str;
140
141         va_start(ap, format);
142         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
143         va_end(ap);
144
145         return str;
146 }
147
148 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
149                                TALLOC_CTX *mem_ctx,
150                                struct ldb_dn *basedn,
151                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
152 {
153         va_list ap;
154         struct ldb_dn *ret;
155         struct ldb_message **res = NULL;
156         int count;
157
158         va_start(ap, format);
159         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
160         va_end(ap);
161
162         if (count != 1) return NULL;
163
164         ret = talloc_steal(mem_ctx, res[0]->dn);
165         talloc_free(res);
166
167         return ret;
168 }
169
170 /*
171   search the sam for a dom_sid attribute in exactly 1 record
172 */
173 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
174                                      TALLOC_CTX *mem_ctx,
175                                      struct ldb_dn *basedn,
176                                      const char *attr_name,
177                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
178 {
179         va_list ap;
180         int count;
181         struct ldb_message **res;
182         const char *attrs[2] = { NULL, NULL };
183         struct dom_sid *sid;
184
185         attrs[0] = attr_name;
186
187         va_start(ap, format);
188         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
189         va_end(ap);
190         if (count > 1) {                
191                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
192                          attr_name, format, count));
193         }
194         if (count != 1) {
195                 talloc_free(res);
196                 return NULL;
197         }
198         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
199         talloc_free(res);
200         return sid;     
201 }
202
203 /*
204   return the count of the number of records in the sam matching the query
205 */
206 int samdb_search_count(struct ldb_context *sam_ldb,
207                        TALLOC_CTX *mem_ctx,
208                        struct ldb_dn *basedn,
209                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
210 {
211         va_list ap;
212         const char *attrs[] = { NULL };
213         int ret;
214
215         va_start(ap, format);
216         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
217         va_end(ap);
218
219         return ret;
220 }
221
222
223 /*
224   search the sam for a single integer attribute in exactly 1 record
225 */
226 unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
227                          TALLOC_CTX *mem_ctx,
228                          unsigned int default_value,
229                          struct ldb_dn *basedn,
230                          const char *attr_name,
231                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
232 {
233         va_list ap;
234         int count;
235         struct ldb_message **res;
236         const char *attrs[2] = { NULL, NULL };
237
238         attrs[0] = attr_name;
239
240         va_start(ap, format);
241         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
242         va_end(ap);
243
244         if (count != 1) {
245                 return default_value;
246         }
247
248         return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
249 }
250
251 /*
252   search the sam for a single signed 64 bit integer attribute in exactly 1 record
253 */
254 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
255                            TALLOC_CTX *mem_ctx,
256                            int64_t default_value,
257                            struct ldb_dn *basedn,
258                            const char *attr_name,
259                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
260 {
261         va_list ap;
262         int count;
263         struct ldb_message **res;
264         const char *attrs[2] = { NULL, NULL };
265
266         attrs[0] = attr_name;
267
268         va_start(ap, format);
269         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
270         va_end(ap);
271
272         if (count != 1) {
273                 return default_value;
274         }
275
276         return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
277 }
278
279 /*
280   search the sam for multipe records each giving a single string attribute
281   return the number of matches, or -1 on error
282 */
283 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
284                                  TALLOC_CTX *mem_ctx,
285                                  struct ldb_dn *basedn,
286                                  const char ***strs,
287                                  const char *attr_name,
288                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
289 {
290         va_list ap;
291         int count, i;
292         const char *attrs[2] = { NULL, NULL };
293         struct ldb_message **res = NULL;
294
295         attrs[0] = attr_name;
296
297         va_start(ap, format);
298         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
299         va_end(ap);
300
301         if (count <= 0) {
302                 return count;
303         }
304
305         /* make sure its single valued */
306         for (i=0;i<count;i++) {
307                 if (res[i]->num_elements != 1) {
308                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
309                                  attr_name, format));
310                         talloc_free(res);
311                         return -1;
312                 }
313         }
314
315         *strs = talloc_array(mem_ctx, const char *, count+1);
316         if (! *strs) {
317                 talloc_free(res);
318                 return -1;
319         }
320
321         for (i=0;i<count;i++) {
322                 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
323         }
324         (*strs)[count] = NULL;
325
326         return count;
327 }
328
329 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
330                                const char *attr, struct ldb_dn *default_value)
331 {
332         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
333         if (!ret_dn) {
334                 return default_value;
335         }
336         return ret_dn;
337 }
338
339 /*
340   pull a rid from a objectSid in a result set. 
341 */
342 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
343                                    const char *attr, uint32_t default_value)
344 {
345         struct dom_sid *sid;
346         uint32_t rid;
347
348         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
349         if (sid == NULL) {
350                 return default_value;
351         }
352         rid = sid->sub_auths[sid->num_auths-1];
353         talloc_free(sid);
354         return rid;
355 }
356
357 /*
358   pull a dom_sid structure from a objectSid in a result set. 
359 */
360 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
361                                      const char *attr)
362 {
363         bool ok;
364         const struct ldb_val *v;
365         struct dom_sid *sid;
366         v = ldb_msg_find_ldb_val(msg, attr);
367         if (v == NULL) {
368                 return NULL;
369         }
370         sid = talloc(mem_ctx, struct dom_sid);
371         if (sid == NULL) {
372                 return NULL;
373         }
374         ok = sid_parse(v->data, v->length, sid);
375         if (!ok) {
376                 talloc_free(sid);
377                 return NULL;
378         }
379         return sid;
380 }
381
382 /*
383   pull a guid structure from a objectGUID in a result set. 
384 */
385 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
386 {
387         const struct ldb_val *v;
388         struct GUID guid;
389         NTSTATUS status;
390
391         v = ldb_msg_find_ldb_val(msg, attr);
392         if (!v) return GUID_zero();
393
394         status = GUID_from_ndr_blob(v, &guid);
395         if (!NT_STATUS_IS_OK(status)) {
396                 return GUID_zero();
397         }
398
399         return guid;
400 }
401
402 /*
403   pull a sid prefix from a objectSid in a result set. 
404   this is used to find the domain sid for a user
405 */
406 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
407                                         const char *attr)
408 {
409         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
410         if (!sid || sid->num_auths < 1) return NULL;
411         sid->num_auths--;
412         return sid;
413 }
414
415 /*
416   pull a NTTIME in a result set. 
417 */
418 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
419                            NTTIME default_value)
420 {
421         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
422 }
423
424 /*
425  * Windows stores 0 for lastLogoff.
426  * But when a MS DC return the lastLogoff (as Logoff Time)
427  * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case
428  * cause windows 2008 and newer version to fail for SMB requests
429  */
430 NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
431 {
432         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
433
434         if (ret == 0)
435                 ret = 0x7FFFFFFFFFFFFFFFULL;
436
437         return ret;
438 }
439
440 /*
441  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
442  * indicate an account doesn't expire.
443  *
444  * When Windows initially creates an account, it sets
445  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
446  * when changing from an account having a specific expiration date to
447  * that account never expiring, it sets accountExpires = 0.
448  *
449  * Consolidate that logic here to allow clearer logic for account expiry in
450  * the rest of the code.
451  */
452 NTTIME samdb_result_account_expires(const struct ldb_message *msg)
453 {
454         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
455                                                  0);
456
457         if (ret == 0)
458                 ret = 0x7FFFFFFFFFFFFFFFULL;
459
460         return ret;
461 }
462
463 /*
464   construct the allow_password_change field from the PwdLastSet attribute and the 
465   domain password settings
466 */
467 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
468                                           TALLOC_CTX *mem_ctx, 
469                                           struct ldb_dn *domain_dn, 
470                                           struct ldb_message *msg, 
471                                           const char *attr)
472 {
473         uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
474         int64_t minPwdAge;
475
476         if (attr_time == 0) {
477                 return 0;
478         }
479
480         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
481
482         /* yes, this is a -= not a += as minPwdAge is stored as the negative
483            of the number of 100-nano-seconds */
484         attr_time -= minPwdAge;
485
486         return attr_time;
487 }
488
489 /*
490   pull a samr_Password structutre from a result set. 
491 */
492 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
493 {
494         struct samr_Password *hash = NULL;
495         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
496         if (val && (val->length >= sizeof(hash->hash))) {
497                 hash = talloc(mem_ctx, struct samr_Password);
498                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
499         }
500         return hash;
501 }
502
503 /*
504   pull an array of samr_Password structures from a result set.
505 */
506 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
507                            const char *attr, struct samr_Password **hashes)
508 {
509         unsigned int count, i;
510         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
511
512         *hashes = NULL;
513         if (!val) {
514                 return 0;
515         }
516         count = val->length / 16;
517         if (count == 0) {
518                 return 0;
519         }
520
521         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
522         if (! *hashes) {
523                 return 0;
524         }
525
526         for (i=0;i<count;i++) {
527                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
528         }
529
530         return count;
531 }
532
533 NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
534                                              struct loadparm_context *lp_ctx,
535                                              struct ldb_message *msg,
536                                              unsigned int idx,
537                                              struct samr_Password **lm_pwd,
538                                              struct samr_Password **nt_pwd)
539 {
540         struct samr_Password *lmPwdHash, *ntPwdHash;
541
542         if (nt_pwd) {
543                 unsigned int num_nt;
544                 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
545                 if (num_nt <= idx) {
546                         *nt_pwd = NULL;
547                 } else {
548                         *nt_pwd = &ntPwdHash[idx];
549                 }
550         }
551         if (lm_pwd) {
552                 /* Ensure that if we have turned off LM
553                  * authentication, that we never use the LM hash, even
554                  * if we store it */
555                 if (lpcfg_lanman_auth(lp_ctx)) {
556                         unsigned int num_lm;
557                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
558                         if (num_lm <= idx) {
559                                 *lm_pwd = NULL;
560                         } else {
561                                 *lm_pwd = &lmPwdHash[idx];
562                         }
563                 } else {
564                         *lm_pwd = NULL;
565                 }
566         }
567         return NT_STATUS_OK;
568 }
569
570 NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
571                                            struct loadparm_context *lp_ctx,
572                                            const struct ldb_message *msg,
573                                            struct samr_Password **lm_pwd,
574                                            struct samr_Password **nt_pwd)
575 {
576         struct samr_Password *lmPwdHash, *ntPwdHash;
577
578         if (nt_pwd) {
579                 unsigned int num_nt;
580                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
581                 if (num_nt == 0) {
582                         *nt_pwd = NULL;
583                 } else if (num_nt > 1) {
584                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
585                 } else {
586                         *nt_pwd = &ntPwdHash[0];
587                 }
588         }
589         if (lm_pwd) {
590                 /* Ensure that if we have turned off LM
591                  * authentication, that we never use the LM hash, even
592                  * if we store it */
593                 if (lpcfg_lanman_auth(lp_ctx)) {
594                         unsigned int num_lm;
595                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
596                         if (num_lm == 0) {
597                                 *lm_pwd = NULL;
598                         } else if (num_lm > 1) {
599                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
600                         } else {
601                                 *lm_pwd = &lmPwdHash[0];
602                         }
603                 } else {
604                         *lm_pwd = NULL;
605                 }
606         }
607         return NT_STATUS_OK;
608 }
609
610 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
611                                 struct loadparm_context *lp_ctx,
612                                 const struct ldb_message *msg,
613                                 struct samr_Password **lm_pwd,
614                                 struct samr_Password **nt_pwd)
615 {
616         uint16_t acct_flags;
617
618         acct_flags = samdb_result_acct_flags(msg,
619                                              "msDS-User-Account-Control-Computed");
620         /* Quit if the account was locked out. */
621         if (acct_flags & ACB_AUTOLOCK) {
622                 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
623                          ldb_dn_get_linearized(msg->dn)));
624                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
625         }
626
627         return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
628                                                  lm_pwd, nt_pwd);
629 }
630
631 /*
632   pull a samr_LogonHours structutre from a result set. 
633 */
634 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
635 {
636         struct samr_LogonHours hours;
637         size_t units_per_week = 168;
638         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
639
640         ZERO_STRUCT(hours);
641
642         if (val) {
643                 units_per_week = val->length * 8;
644         }
645
646         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
647         if (!hours.bits) {
648                 return hours;
649         }
650         hours.units_per_week = units_per_week;
651         memset(hours.bits, 0xFF, units_per_week/8);
652         if (val) {
653                 memcpy(hours.bits, val->data, val->length);
654         }
655
656         return hours;
657 }
658
659 /*
660   pull a set of account_flags from a result set. 
661
662   Naturally, this requires that userAccountControl and
663   (if not null) the attributes 'attr' be already
664   included in msg
665 */
666 uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
667 {
668         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
669         uint32_t attr_flags = 0;
670         uint32_t acct_flags = ds_uf2acb(userAccountControl);
671         if (attr) {
672                 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
673                 if (attr_flags == UF_ACCOUNTDISABLE) {
674                         DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
675                                   ldb_dn_get_linearized(msg->dn)));
676                 }
677                 acct_flags |= ds_uf2acb(attr_flags);
678         }
679
680         return acct_flags;
681 }
682
683 NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
684                                  struct ldb_message *msg,
685                                  const char *attr,
686                                  struct lsa_BinaryString *s)
687 {
688         int i;
689         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
690
691         ZERO_STRUCTP(s);
692
693         if (!val) {
694                 return NT_STATUS_OK;
695         }
696
697         if ((val->length % 2) != 0) {
698                 /*
699                  * If the on-disk data is not even in length, we know
700                  * it is corrupt, and can not be safely pushed.  We
701                  * would either truncate, send either a un-initilaised
702                  * byte or send a forced zero byte
703                  */
704                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
705         }
706
707         s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
708         if (!s->array) {
709                 return NT_STATUS_NO_MEMORY;
710         }
711         s->length = s->size = val->length;
712
713         /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
714         for (i = 0; i < s->length / 2; i++) {
715                 s->array[i] = SVAL(val->data, i * 2);
716         }
717
718         return NT_STATUS_OK;
719 }
720
721 /* Find an attribute, with a particular value */
722
723 /* The current callers of this function expect a very specific
724  * behaviour: In particular, objectClass subclass equivilance is not
725  * wanted.  This means that we should not lookup the schema for the
726  * comparison function */
727 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
728                                                  const struct ldb_message *msg, 
729                                                  const char *name, const char *value)
730 {
731         unsigned int i;
732         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
733
734         if (!el) {
735                 return NULL;
736         }
737
738         for (i=0;i<el->num_values;i++) {
739                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
740                         return el;
741                 }
742         }
743
744         return NULL;
745 }
746
747 static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
748                                           struct ldb_message *msg,
749                                           const char *name,
750                                           const char *set_value,
751                                           unsigned attr_flags,
752                                           bool *added)
753 {
754         int ret;
755         struct ldb_message_element *el;
756
757         SMB_ASSERT(attr_flags != 0);
758
759         el = ldb_msg_find_element(msg, name);
760         if (el) {
761                 if (added != NULL) {
762                         *added = false;
763                 }
764
765                 return LDB_SUCCESS;
766         }
767
768         ret = ldb_msg_add_empty(msg, name,
769                                 attr_flags,
770                                 &el);
771         if (ret != LDB_SUCCESS) {
772                 return ret;
773         }
774
775         if (set_value != NULL) {
776                 ret = ldb_msg_add_string(msg, name, set_value);
777                 if (ret != LDB_SUCCESS) {
778                         return ret;
779                 }
780         }
781
782         if (added != NULL) {
783                 *added = true;
784         }
785         return LDB_SUCCESS;
786 }
787
788 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
789 {
790         return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
791 }
792
793 /*
794   add a dom_sid element to a message
795 */
796 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
797                           const char *attr_name, const struct dom_sid *sid)
798 {
799         struct ldb_val v;
800         enum ndr_err_code ndr_err;
801
802         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
803                                        sid,
804                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
805         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
806                 return ldb_operr(sam_ldb);
807         }
808         return ldb_msg_add_value(msg, attr_name, &v, NULL);
809 }
810
811
812 /*
813   add a delete element operation to a message
814 */
815 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
816                          const char *attr_name)
817 {
818         /* we use an empty replace rather than a delete, as it allows for 
819            dsdb_replace() to be used everywhere */
820         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
821 }
822
823 /*
824   add an add attribute value to a message or enhance an existing attribute
825   which has the same name and the add flag set.
826 */
827 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
828                          struct ldb_message *msg, const char *attr_name,
829                          const char *value)
830 {
831         struct ldb_message_element *el;
832         struct ldb_val val, *vals;
833         char *v;
834         unsigned int i;
835         bool found = false;
836         int ret;
837
838         v = talloc_strdup(mem_ctx, value);
839         if (v == NULL) {
840                 return ldb_oom(sam_ldb);
841         }
842
843         val.data = (uint8_t *) v;
844         val.length = strlen(v);
845
846         if (val.length == 0) {
847                 /* allow empty strings as non-existent attributes */
848                 return LDB_SUCCESS;
849         }
850
851         for (i = 0; i < msg->num_elements; i++) {
852                 el = &msg->elements[i];
853                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
854                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
855                         found = true;
856                         break;
857                 }
858         }
859         if (!found) {
860                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
861                                         &el);
862                 if (ret != LDB_SUCCESS) {
863                         return ret;
864                 }
865         }
866
867         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
868                               el->num_values + 1);
869         if (vals == NULL) {
870                 return ldb_oom(sam_ldb);
871         }
872         el->values = vals;
873         el->values[el->num_values] = val;
874         ++(el->num_values);
875
876         return LDB_SUCCESS;
877 }
878
879 /*
880   add a delete attribute value to a message or enhance an existing attribute
881   which has the same name and the delete flag set.
882 */
883 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
884                          struct ldb_message *msg, const char *attr_name,
885                          const char *value)
886 {
887         struct ldb_message_element *el;
888         struct ldb_val val, *vals;
889         char *v;
890         unsigned int i;
891         bool found = false;
892         int ret;
893
894         v = talloc_strdup(mem_ctx, value);
895         if (v == NULL) {
896                 return ldb_oom(sam_ldb);
897         }
898
899         val.data = (uint8_t *) v;
900         val.length = strlen(v);
901
902         if (val.length == 0) {
903                 /* allow empty strings as non-existent attributes */
904                 return LDB_SUCCESS;
905         }
906
907         for (i = 0; i < msg->num_elements; i++) {
908                 el = &msg->elements[i];
909                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
910                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
911                         found = true;
912                         break;
913                 }
914         }
915         if (!found) {
916                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
917                                         &el);
918                 if (ret != LDB_SUCCESS) {
919                         return ret;
920                 }
921         }
922
923         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
924                               el->num_values + 1);
925         if (vals == NULL) {
926                 return ldb_oom(sam_ldb);
927         }
928         el->values = vals;
929         el->values[el->num_values] = val;
930         ++(el->num_values);
931
932         return LDB_SUCCESS;
933 }
934
935 /*
936   add a int element to a message
937 */
938 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
939                        const char *attr_name, int v)
940 {
941         const char *s = talloc_asprintf(mem_ctx, "%d", v);
942         if (s == NULL) {
943                 return ldb_oom(sam_ldb);
944         }
945         return ldb_msg_add_string(msg, attr_name, s);
946 }
947
948 /*
949  * Add an unsigned int element to a message
950  *
951  * The issue here is that we have not yet first cast to int32_t explicitly,
952  * before we cast to an signed int to printf() into the %d or cast to a
953  * int64_t before we then cast to a long long to printf into a %lld.
954  *
955  * There are *no* unsigned integers in Active Directory LDAP, even the RID
956  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
957  * (See the schema, and the syntax definitions in schema_syntax.c).
958  *
959  */
960 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961                        const char *attr_name, unsigned int v)
962 {
963         return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
964 }
965
966 /*
967   add a (signed) int64_t element to a message
968 */
969 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
970                         const char *attr_name, int64_t v)
971 {
972         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
973         if (s == NULL) {
974                 return ldb_oom(sam_ldb);
975         }
976         return ldb_msg_add_string(msg, attr_name, s);
977 }
978
979 /*
980  * Add an unsigned int64_t (uint64_t) element to a message
981  *
982  * The issue here is that we have not yet first cast to int32_t explicitly,
983  * before we cast to an signed int to printf() into the %d or cast to a
984  * int64_t before we then cast to a long long to printf into a %lld.
985  *
986  * There are *no* unsigned integers in Active Directory LDAP, even the RID
987  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
988  * (See the schema, and the syntax definitions in schema_syntax.c).
989  *
990  */
991 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
992                         const char *attr_name, uint64_t v)
993 {
994         return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
995 }
996
997 /*
998   add a samr_Password element to a message
999 */
1000 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1001                        const char *attr_name, const struct samr_Password *hash)
1002 {
1003         struct ldb_val val;
1004         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1005         if (!val.data) {
1006                 return ldb_oom(sam_ldb);
1007         }
1008         val.length = 16;
1009         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1010 }
1011
1012 /*
1013   add a samr_Password array to a message
1014 */
1015 int samdb_msg_add_hashes(struct ldb_context *ldb,
1016                          TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1017                          const char *attr_name, struct samr_Password *hashes,
1018                          unsigned int count)
1019 {
1020         struct ldb_val val;
1021         unsigned int i;
1022         val.data = talloc_array_size(mem_ctx, 16, count);
1023         val.length = count*16;
1024         if (!val.data) {
1025                 return ldb_oom(ldb);
1026         }
1027         for (i=0;i<count;i++) {
1028                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1029         }
1030         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1031 }
1032
1033 /*
1034   add a acct_flags element to a message
1035 */
1036 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1037                              const char *attr_name, uint32_t v)
1038 {
1039         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1040 }
1041
1042 /*
1043   add a logon_hours element to a message
1044 */
1045 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1046                               const char *attr_name, struct samr_LogonHours *hours)
1047 {
1048         struct ldb_val val;
1049         val.length = hours->units_per_week / 8;
1050         val.data = hours->bits;
1051         return ldb_msg_add_value(msg, attr_name, &val, NULL);
1052 }
1053
1054 /*
1055   add a parameters element to a message
1056 */
1057 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1058                              const char *attr_name, struct lsa_BinaryString *parameters)
1059 {
1060         int i;
1061         struct ldb_val val;
1062         if ((parameters->length % 2) != 0) {
1063                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1064         }
1065
1066         val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1067         if (val.data == NULL) {
1068                 return LDB_ERR_OPERATIONS_ERROR;
1069         }
1070         val.length = parameters->length;
1071         for (i = 0; i < parameters->length / 2; i++) {
1072                 /*
1073                  * The on-disk format needs to be in the 'network'
1074                  * format, parmeters->array is a uint16_t array of
1075                  * length parameters->length / 2
1076                  */
1077                 SSVAL(val.data, i * 2, parameters->array[i]);
1078         }
1079         return ldb_msg_add_steal_value(msg, attr_name, &val);
1080 }
1081
1082 /*
1083  * Sets an unsigned int element in a message
1084  *
1085  * The issue here is that we have not yet first cast to int32_t explicitly,
1086  * before we cast to an signed int to printf() into the %d or cast to a
1087  * int64_t before we then cast to a long long to printf into a %lld.
1088  *
1089  * There are *no* unsigned integers in Active Directory LDAP, even the RID
1090  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1091  * (See the schema, and the syntax definitions in schema_syntax.c).
1092  *
1093  */
1094 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1095                        struct ldb_message *msg, const char *attr_name,
1096                        unsigned int v)
1097 {
1098         struct ldb_message_element *el;
1099
1100         el = ldb_msg_find_element(msg, attr_name);
1101         if (el) {
1102                 el->num_values = 0;
1103         }
1104         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1105 }
1106
1107 /*
1108  * Handle ldb_request in transaction
1109  */
1110 int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1111                                  struct ldb_request *req)
1112 {
1113         int ret;
1114
1115         ret = ldb_transaction_start(sam_ldb);
1116         if (ret != LDB_SUCCESS) {
1117                 return ret;
1118         }
1119
1120         ret = ldb_request(sam_ldb, req);
1121         if (ret == LDB_SUCCESS) {
1122                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1123         }
1124
1125         if (ret == LDB_SUCCESS) {
1126                 return ldb_transaction_commit(sam_ldb);
1127         }
1128         ldb_transaction_cancel(sam_ldb);
1129
1130         return ret;
1131 }
1132
1133 /*
1134   return a default security descriptor
1135 */
1136 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1137 {
1138         struct security_descriptor *sd;
1139
1140         sd = security_descriptor_initialise(mem_ctx);
1141
1142         return sd;
1143 }
1144
1145 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 
1146 {
1147         struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1148         struct ldb_dn *aggregate_dn;
1149         if (!schema_dn) {
1150                 return NULL;
1151         }
1152
1153         aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1154         if (!aggregate_dn) {
1155                 return NULL;
1156         }
1157         if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1158                 return NULL;
1159         }
1160         return aggregate_dn;
1161 }
1162
1163 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1164 {
1165         struct ldb_dn *new_dn;
1166
1167         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1168         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1169                 talloc_free(new_dn);
1170                 return NULL;
1171         }
1172         return new_dn;
1173 }
1174
1175 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1176 {
1177        struct ldb_dn *new_dn;
1178
1179        new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1180        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1181                talloc_free(new_dn);
1182                return NULL;
1183        }
1184        return new_dn;
1185 }
1186
1187 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1188 {
1189         struct ldb_dn *new_dn;
1190
1191         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1192         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1193                 talloc_free(new_dn);
1194                 return NULL;
1195         }
1196         return new_dn;
1197 }
1198
1199 /*
1200   work out the domain sid for the current open ldb
1201 */
1202 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1203 {
1204         TALLOC_CTX *tmp_ctx;
1205         const struct dom_sid *domain_sid;
1206         const char *attrs[] = {
1207                 "objectSid",
1208                 NULL
1209         };
1210         struct ldb_result *res;
1211         int ret;
1212
1213         /* see if we have a cached copy */
1214         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1215         if (domain_sid) {
1216                 return domain_sid;
1217         }
1218
1219         tmp_ctx = talloc_new(ldb);
1220         if (tmp_ctx == NULL) {
1221                 goto failed;
1222         }
1223
1224         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1225
1226         if (ret != LDB_SUCCESS) {
1227                 goto failed;
1228         }
1229
1230         if (res->count != 1) {
1231                 goto failed;
1232         }
1233
1234         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1235         if (domain_sid == NULL) {
1236                 goto failed;
1237         }
1238
1239         /* cache the domain_sid in the ldb */
1240         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1241                 goto failed;
1242         }
1243
1244         talloc_steal(ldb, domain_sid);
1245         talloc_free(tmp_ctx);
1246
1247         return domain_sid;
1248
1249 failed:
1250         talloc_free(tmp_ctx);
1251         return NULL;
1252 }
1253
1254 /*
1255   get domain sid from cache
1256 */
1257 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1258 {
1259         return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1260 }
1261
1262 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1263 {
1264         TALLOC_CTX *tmp_ctx;
1265         struct dom_sid *dom_sid_new;
1266         struct dom_sid *dom_sid_old;
1267
1268         /* see if we have a cached copy */
1269         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1270                                                      "cache.domain_sid"), struct dom_sid);
1271
1272         tmp_ctx = talloc_new(ldb);
1273         if (tmp_ctx == NULL) {
1274                 goto failed;
1275         }
1276
1277         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1278         if (!dom_sid_new) {
1279                 goto failed;
1280         }
1281
1282         /* cache the domain_sid in the ldb */
1283         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1284                 goto failed;
1285         }
1286
1287         talloc_steal(ldb, dom_sid_new);
1288         talloc_free(tmp_ctx);
1289         talloc_free(dom_sid_old);
1290
1291         return true;
1292
1293 failed:
1294         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1295         talloc_free(tmp_ctx);
1296         return false;
1297 }
1298
1299 /*
1300   work out the domain guid for the current open ldb
1301 */
1302 const struct GUID *samdb_domain_guid(struct ldb_context *ldb)
1303 {
1304         TALLOC_CTX *tmp_ctx = NULL;
1305         struct GUID *domain_guid = NULL;
1306         const char *attrs[] = {
1307                 "objectGUID",
1308                 NULL
1309         };
1310         struct ldb_result *res = NULL;
1311         int ret;
1312
1313         /* see if we have a cached copy */
1314         domain_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.domain_guid");
1315         if (domain_guid) {
1316                 return domain_guid;
1317         }
1318
1319         tmp_ctx = talloc_new(ldb);
1320         if (tmp_ctx == NULL) {
1321                 goto failed;
1322         }
1323
1324         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectGUID=*");
1325         if (ret != LDB_SUCCESS) {
1326                 goto failed;
1327         }
1328
1329         if (res->count != 1) {
1330                 goto failed;
1331         }
1332
1333         domain_guid = talloc(tmp_ctx, struct GUID);
1334         if (domain_guid == NULL) {
1335                 goto failed;
1336         }
1337         *domain_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1338
1339         /* cache the domain_sid in the ldb */
1340         if (ldb_set_opaque(ldb, "cache.domain_guid", domain_guid) != LDB_SUCCESS) {
1341                 goto failed;
1342         }
1343
1344         talloc_steal(ldb, domain_guid);
1345         talloc_free(tmp_ctx);
1346
1347         return domain_guid;
1348
1349 failed:
1350         talloc_free(tmp_ctx);
1351         return NULL;
1352 }
1353
1354 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1355 {
1356         TALLOC_CTX *tmp_ctx;
1357         struct ldb_dn *ntds_settings_dn_new;
1358         struct ldb_dn *ntds_settings_dn_old;
1359
1360         /* see if we have a forced copy from provision */
1361         ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb, 
1362                                                               "forced.ntds_settings_dn"), struct ldb_dn);
1363
1364         tmp_ctx = talloc_new(ldb);
1365         if (tmp_ctx == NULL) {
1366                 goto failed;
1367         }
1368
1369         ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1370         if (!ntds_settings_dn_new) {
1371                 goto failed;
1372         }
1373
1374         /* set the DN in the ldb to avoid lookups during provision */
1375         if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1376                 goto failed;
1377         }
1378
1379         talloc_steal(ldb, ntds_settings_dn_new);
1380         talloc_free(tmp_ctx);
1381         talloc_free(ntds_settings_dn_old);
1382
1383         return true;
1384
1385 failed:
1386         DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1387         talloc_free(tmp_ctx);
1388         return false;
1389 }
1390
1391 /*
1392   work out the ntds settings dn for the current open ldb
1393 */
1394 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1395 {
1396         TALLOC_CTX *tmp_ctx;
1397         const char *root_attrs[] = { "dsServiceName", NULL };
1398         int ret;
1399         struct ldb_result *root_res;
1400         struct ldb_dn *settings_dn;
1401
1402         /* see if we have a cached copy */
1403         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1404         if (settings_dn) {
1405                 return ldb_dn_copy(mem_ctx, settings_dn);
1406         }
1407
1408         tmp_ctx = talloc_new(mem_ctx);
1409         if (tmp_ctx == NULL) {
1410                 goto failed;
1411         }
1412
1413         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1414         if (ret != LDB_SUCCESS) {
1415                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1416                          ldb_errstring(ldb)));
1417                 goto failed;
1418         }
1419
1420         if (root_res->count != 1) {
1421                 goto failed;
1422         }
1423
1424         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1425
1426         /* note that we do not cache the DN here, as that would mean
1427          * we could not handle server renames at runtime. Only
1428          * provision sets up forced.ntds_settings_dn */
1429
1430         talloc_steal(mem_ctx, settings_dn);
1431         talloc_free(tmp_ctx);
1432
1433         return settings_dn;
1434
1435 failed:
1436         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1437         talloc_free(tmp_ctx);
1438         return NULL;
1439 }
1440
1441 /*
1442   work out the ntds settings invocationId for the current open ldb
1443 */
1444 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1445 {
1446         TALLOC_CTX *tmp_ctx;
1447         const char *attrs[] = { "invocationId", NULL };
1448         int ret;
1449         struct ldb_result *res;
1450         struct GUID *invocation_id;
1451
1452         /* see if we have a cached copy */
1453         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1454         if (invocation_id) {
1455                 SMB_ASSERT(!GUID_all_zero(invocation_id));
1456                 return invocation_id;
1457         }
1458
1459         tmp_ctx = talloc_new(ldb);
1460         if (tmp_ctx == NULL) {
1461                 goto failed;
1462         }
1463
1464         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1465         if (ret) {
1466                 goto failed;
1467         }
1468
1469         if (res->count != 1) {
1470                 goto failed;
1471         }
1472
1473         invocation_id = talloc(tmp_ctx, struct GUID);
1474         if (!invocation_id) {
1475                 goto failed;
1476         }
1477
1478         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1479         if (GUID_all_zero(invocation_id)) {
1480                 if (ldb_msg_find_ldb_val(res->msgs[0], "invocationId")) {
1481                         DEBUG(0, ("Failed to find our own NTDS Settings invocationId in the ldb!\n"));  
1482                 } else {
1483                         DEBUG(0, ("Failed to find parse own NTDS Settings invocationId from the ldb!\n"));
1484                 }
1485                 goto failed;
1486         }
1487
1488         /* cache the domain_sid in the ldb */
1489         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1490                 goto failed;
1491         }
1492
1493         talloc_steal(ldb, invocation_id);
1494         talloc_free(tmp_ctx);
1495
1496         return invocation_id;
1497
1498 failed:
1499         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1500         talloc_free(tmp_ctx);
1501         return NULL;
1502 }
1503
1504 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1505 {
1506         TALLOC_CTX *tmp_ctx;
1507         struct GUID *invocation_id_new;
1508         struct GUID *invocation_id_old;
1509
1510         /* see if we have a cached copy */
1511         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1512                                                          "cache.invocation_id");
1513
1514         tmp_ctx = talloc_new(ldb);
1515         if (tmp_ctx == NULL) {
1516                 goto failed;
1517         }
1518
1519         invocation_id_new = talloc(tmp_ctx, struct GUID);
1520         if (!invocation_id_new) {
1521                 goto failed;
1522         }
1523
1524         SMB_ASSERT(!GUID_all_zero(invocation_id_in));
1525         *invocation_id_new = *invocation_id_in;
1526
1527         /* cache the domain_sid in the ldb */
1528         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1529                 goto failed;
1530         }
1531
1532         talloc_steal(ldb, invocation_id_new);
1533         talloc_free(tmp_ctx);
1534         talloc_free(invocation_id_old);
1535
1536         return true;
1537
1538 failed:
1539         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1540         talloc_free(tmp_ctx);
1541         return false;
1542 }
1543
1544 /*
1545   work out the ntds settings objectGUID for the current open ldb
1546 */
1547 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1548 {
1549         TALLOC_CTX *tmp_ctx;
1550         const char *attrs[] = { "objectGUID", NULL };
1551         int ret;
1552         struct ldb_result *res;
1553         struct GUID *ntds_guid;
1554
1555         /* see if we have a cached copy */
1556         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1557         if (ntds_guid) {
1558                 return ntds_guid;
1559         }
1560
1561         tmp_ctx = talloc_new(ldb);
1562         if (tmp_ctx == NULL) {
1563                 goto failed;
1564         }
1565
1566         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
1567         if (ret) {
1568                 goto failed;
1569         }
1570
1571         if (res->count != 1) {
1572                 goto failed;
1573         }
1574
1575         ntds_guid = talloc(tmp_ctx, struct GUID);
1576         if (!ntds_guid) {
1577                 goto failed;
1578         }
1579
1580         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1581
1582         /* cache the domain_sid in the ldb */
1583         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1584                 goto failed;
1585         }
1586
1587         talloc_steal(ldb, ntds_guid);
1588         talloc_free(tmp_ctx);
1589
1590         return ntds_guid;
1591
1592 failed:
1593         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1594         talloc_free(tmp_ctx);
1595         return NULL;
1596 }
1597
1598 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1599 {
1600         TALLOC_CTX *tmp_ctx;
1601         struct GUID *ntds_guid_new;
1602         struct GUID *ntds_guid_old;
1603
1604         /* see if we have a cached copy */
1605         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1606
1607         tmp_ctx = talloc_new(ldb);
1608         if (tmp_ctx == NULL) {
1609                 goto failed;
1610         }
1611
1612         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1613         if (!ntds_guid_new) {
1614                 goto failed;
1615         }
1616
1617         *ntds_guid_new = *ntds_guid_in;
1618
1619         /* cache the domain_sid in the ldb */
1620         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1621                 goto failed;
1622         }
1623
1624         talloc_steal(ldb, ntds_guid_new);
1625         talloc_free(tmp_ctx);
1626         talloc_free(ntds_guid_old);
1627
1628         return true;
1629
1630 failed:
1631         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1632         talloc_free(tmp_ctx);
1633         return false;
1634 }
1635
1636 /*
1637   work out the server dn for the current open ldb
1638 */
1639 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1640 {
1641         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1642         struct ldb_dn *dn;
1643         if (!tmp_ctx) {
1644                 return NULL;
1645         }
1646         dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1647         talloc_free(tmp_ctx);
1648         return dn;
1649         
1650 }
1651
1652 /*
1653   work out the server dn for the current open ldb
1654 */
1655 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1656 {
1657         struct ldb_dn *server_dn;
1658         struct ldb_dn *servers_dn;
1659         struct ldb_dn *server_site_dn;
1660
1661         /* TODO: there must be a saner way to do this!! */
1662         server_dn = samdb_server_dn(ldb, mem_ctx);
1663         if (!server_dn) return NULL;
1664
1665         servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1666         talloc_free(server_dn);
1667         if (!servers_dn) return NULL;
1668
1669         server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1670         talloc_free(servers_dn);
1671
1672         return server_site_dn;
1673 }
1674
1675 /*
1676   find the site name from a computers DN record
1677  */
1678 int samdb_find_site_for_computer(struct ldb_context *ldb,
1679                                  TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1680                                  const char **site_name)
1681 {
1682         int ret;
1683         struct ldb_dn *dn;
1684         const struct ldb_val *rdn_val;
1685
1686         *site_name = NULL;
1687
1688         ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1689         if (ret != LDB_SUCCESS) {
1690                 return ret;
1691         }
1692
1693         if (!ldb_dn_remove_child_components(dn, 2)) {
1694                 talloc_free(dn);
1695                 return LDB_ERR_INVALID_DN_SYNTAX;
1696         }
1697
1698         rdn_val = ldb_dn_get_rdn_val(dn);
1699         if (rdn_val == NULL) {
1700                 return LDB_ERR_OPERATIONS_ERROR;
1701         }
1702
1703         (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1704         talloc_free(dn);
1705         if (!*site_name) {
1706                 return LDB_ERR_OPERATIONS_ERROR;
1707         }
1708         return LDB_SUCCESS;
1709 }
1710
1711 /*
1712   find the NTDS GUID from a computers DN record
1713  */
1714 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1715                                      struct GUID *ntds_guid)
1716 {
1717         int ret;
1718         struct ldb_dn *dn;
1719
1720         *ntds_guid = GUID_zero();
1721
1722         ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1723         if (ret != LDB_SUCCESS) {
1724                 return ret;
1725         }
1726
1727         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1728                 talloc_free(dn);
1729                 return LDB_ERR_OPERATIONS_ERROR;
1730         }
1731
1732         ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1733         talloc_free(dn);
1734         return ret;
1735 }
1736
1737 /*
1738   find a 'reference' DN that points at another object
1739   (eg. serverReference, rIDManagerReference etc)
1740  */
1741 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1742                        const char *attribute, struct ldb_dn **dn)
1743 {
1744         const char *attrs[2];
1745         struct ldb_result *res;
1746         int ret;
1747
1748         attrs[0] = attribute;
1749         attrs[1] = NULL;
1750
1751         ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1752         if (ret != LDB_SUCCESS) {
1753                 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1754                                        ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1755                 return ret;
1756         }
1757
1758         *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1759         if (!*dn) {
1760                 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1761                         ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1762                                                ldb_dn_get_linearized(base));
1763                 } else {
1764                         ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1765                                                ldb_dn_get_linearized(base));
1766                 }
1767                 talloc_free(res);
1768                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1769         }
1770
1771         talloc_free(res);
1772         return LDB_SUCCESS;
1773 }
1774
1775 /*
1776   find if a DN (must have GUID component!) is our ntdsDsa
1777  */
1778 int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1779 {
1780         NTSTATUS status;
1781         struct GUID dn_guid;
1782         const struct GUID *our_ntds_guid;
1783         status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1784         if (!NT_STATUS_IS_OK(status)) {
1785                 return LDB_ERR_OPERATIONS_ERROR;
1786         }
1787
1788         our_ntds_guid = samdb_ntds_objectGUID(ldb);
1789         if (!our_ntds_guid) {
1790                 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1791                 return LDB_ERR_OPERATIONS_ERROR;
1792         }
1793
1794         *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1795         return LDB_SUCCESS;
1796 }
1797
1798 /*
1799   find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1800  */
1801 int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1802                                     const char *attribute, bool *is_ntdsa)
1803 {
1804         int ret;
1805         struct ldb_dn *referenced_dn;
1806         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1807         if (tmp_ctx == NULL) {
1808                 return LDB_ERR_OPERATIONS_ERROR;
1809         }
1810         ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1811         if (ret != LDB_SUCCESS) {
1812                 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1813                 return ret;
1814         }
1815
1816         ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1817         
1818         talloc_free(tmp_ctx);
1819         return ret;
1820 }
1821
1822 /*
1823   find our machine account via the serverReference attribute in the
1824   server DN
1825  */
1826 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1827 {
1828         struct ldb_dn *server_dn;
1829         int ret;
1830
1831         server_dn = samdb_server_dn(ldb, mem_ctx);
1832         if (server_dn == NULL) {
1833                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
1834         }
1835
1836         ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
1837         talloc_free(server_dn);
1838
1839         return ret;
1840 }
1841
1842 /*
1843   find the RID Manager$ DN via the rIDManagerReference attribute in the
1844   base DN
1845  */
1846 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1847 {
1848         return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
1849                                   "rIDManagerReference", dn);
1850 }
1851
1852 /*
1853   find the RID Set DN via the rIDSetReferences attribute in our
1854   machine account DN
1855  */
1856 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1857 {
1858         struct ldb_dn *server_ref_dn;
1859         int ret;
1860
1861         ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
1862         if (ret != LDB_SUCCESS) {
1863                 return ret;
1864         }
1865         ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
1866         talloc_free(server_ref_dn);
1867         return ret;
1868 }
1869
1870 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1871 {
1872         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
1873                                                                             mem_ctx));
1874
1875         if (val == NULL) {
1876                 return NULL;
1877         }
1878
1879         return (const char *) val->data;
1880 }
1881
1882 /*
1883  * Finds the client site by using the client's IP address.
1884  * The "subnet_name" returns the name of the subnet if parameter != NULL
1885  *
1886  * Has a Windows-based fallback to provide the only site available, or an empty
1887  * string if there are multiple sites.
1888  */
1889 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
1890                                    const char *ip_address, char **subnet_name,
1891                                    bool fallback)
1892 {
1893         const char *attrs[] = { "cn", "siteObject", NULL };
1894         struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
1895         struct ldb_result *res;
1896         const struct ldb_val *val;
1897         const char *site_name = NULL, *l_subnet_name = NULL;
1898         const char *allow_list[2] = { NULL, NULL };
1899         unsigned int i, count;
1900         int cnt, ret;
1901
1902         /*
1903          * if we don't have a client ip e.g. ncalrpc
1904          * the server site is the client site
1905          */
1906         if (ip_address == NULL) {
1907                 return samdb_server_site_name(ldb, mem_ctx);
1908         }
1909
1910         sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
1911         if (sites_container_dn == NULL) {
1912                 return NULL;
1913         }
1914
1915         subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
1916         if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
1917                 talloc_free(sites_container_dn);
1918                 talloc_free(subnets_dn);
1919                 return NULL;
1920         }
1921
1922         ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
1923                          attrs, NULL);
1924         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1925                 count = 0;
1926         } else if (ret != LDB_SUCCESS) {
1927                 talloc_free(sites_container_dn);
1928                 talloc_free(subnets_dn);
1929                 return NULL;
1930         } else {
1931                 count = res->count;
1932         }
1933
1934         for (i = 0; i < count; i++) {
1935                 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
1936                                                             NULL);
1937
1938                 allow_list[0] = l_subnet_name;
1939
1940                 if (allow_access_nolog(NULL, allow_list, "", ip_address)) {
1941                         sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
1942                                                            res->msgs[i],
1943                                                            "siteObject");
1944                         if (sites_dn == NULL) {
1945                                 /* No reference, maybe another subnet matches */
1946                                 continue;
1947                         }
1948
1949                         /* "val" cannot be NULL here since "sites_dn" != NULL */
1950                         val = ldb_dn_get_rdn_val(sites_dn);
1951                         site_name = talloc_strdup(mem_ctx,
1952                                                   (const char *) val->data);
1953
1954                         talloc_free(sites_dn);
1955
1956                         break;
1957                 }
1958         }
1959
1960         if (site_name == NULL && fallback) {
1961                 /* This is the Windows Server fallback rule: when no subnet
1962                  * exists and we have only one site available then use it (it
1963                  * is for sure the same as our server site). If more sites do
1964                  * exist then we don't know which one to use and set the site
1965                  * name to "". */
1966                 cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
1967                                          "(objectClass=site)");
1968                 if (cnt == 1) {
1969                         site_name = samdb_server_site_name(ldb, mem_ctx);
1970                 } else {
1971                         site_name = talloc_strdup(mem_ctx, "");
1972                 }
1973                 l_subnet_name = NULL;
1974         }
1975
1976         if (subnet_name != NULL) {
1977                 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
1978         }
1979
1980         talloc_free(sites_container_dn);
1981         talloc_free(subnets_dn);
1982         talloc_free(res);
1983
1984         return site_name;
1985 }
1986
1987 /*
1988   work out if we are the PDC for the domain of the current open ldb
1989 */
1990 bool samdb_is_pdc(struct ldb_context *ldb)
1991 {
1992         int ret;
1993         bool is_pdc;
1994
1995         ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner", 
1996                                               &is_pdc);
1997         if (ret != LDB_SUCCESS) {
1998                 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n", 
1999                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
2000                          ldb_errstring(ldb)));
2001                 return false;
2002         }
2003
2004         return is_pdc;
2005 }
2006
2007 /*
2008   work out if we are a Global Catalog server for the domain of the current open ldb
2009 */
2010 bool samdb_is_gc(struct ldb_context *ldb)
2011 {
2012         uint32_t options;
2013         if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
2014                 return false;
2015         }
2016         return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
2017 }
2018
2019 /* Find a domain object in the parents of a particular DN.  */
2020 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2021                                    struct ldb_dn **parent_dn, const char **errstring)
2022 {
2023         TALLOC_CTX *local_ctx;
2024         struct ldb_dn *sdn = dn;
2025         struct ldb_result *res = NULL;
2026         int ret = LDB_SUCCESS;
2027         const char *attrs[] = { NULL };
2028
2029         local_ctx = talloc_new(mem_ctx);
2030         if (local_ctx == NULL) return ldb_oom(ldb);
2031
2032         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
2033                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
2034                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
2035                 if (ret == LDB_SUCCESS) {
2036                         if (res->count == 1) {
2037                                 break;
2038                         }
2039                 } else {
2040                         break;
2041                 }
2042         }
2043
2044         if (ret != LDB_SUCCESS) {
2045                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2046                                              ldb_dn_get_linearized(dn),
2047                                              ldb_dn_get_linearized(sdn),
2048                                              ldb_errstring(ldb));
2049                 talloc_free(local_ctx);
2050                 return ret;
2051         }
2052         if (res->count != 1) {
2053                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2054                                              ldb_dn_get_linearized(dn));
2055                 DEBUG(0,(__location__ ": %s\n", *errstring));
2056                 talloc_free(local_ctx);
2057                 return LDB_ERR_CONSTRAINT_VIOLATION;
2058         }
2059
2060         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2061         talloc_free(local_ctx);
2062         return ret;
2063 }
2064
2065 static void pwd_timeout_debug(struct tevent_context *unused1,
2066                               struct tevent_timer *unused2,
2067                               struct timeval unused3,
2068                               void *unused4)
2069 {
2070         DEBUG(0, ("WARNING: check_password_complexity: password script "
2071                   "took more than 1 second to run\n"));
2072 }
2073
2074
2075 /*
2076  * Performs checks on a user password (plaintext UNIX format - attribute
2077  * "password"). The remaining parameters have to be extracted from the domain
2078  * object in the AD.
2079  *
2080  * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2081  */
2082 enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
2083                                                 struct loadparm_context *lp_ctx,
2084                                                 const DATA_BLOB *utf8_blob,
2085                                                 const uint32_t pwdProperties,
2086                                                 const uint32_t minPwdLength)
2087 {
2088         const char *utf8_pw = (const char *)utf8_blob->data;
2089         size_t utf8_len = strlen_m(utf8_pw);
2090         char *password_script = NULL;
2091
2092         /* checks if the "minPwdLength" property is satisfied */
2093         if (minPwdLength > utf8_len) {
2094                 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2095         }
2096
2097         /* checks the password complexity */
2098         if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2099                 return SAMR_VALIDATION_STATUS_SUCCESS;
2100         }
2101
2102         if (utf8_len == 0) {
2103                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2104         }
2105
2106         password_script = lpcfg_check_password_script(lp_ctx, mem_ctx);
2107         if (password_script != NULL && *password_script != '\0') {
2108                 int check_ret = 0;
2109                 int error = 0;
2110                 struct tevent_context *event_ctx = NULL;
2111                 struct tevent_req *req = NULL;
2112                 struct samba_runcmd_state *run_cmd = NULL;
2113                 const char * const cmd[4] = {
2114                         "/bin/sh", "-c",
2115                         password_script,
2116                         NULL
2117                 };
2118
2119                 event_ctx = tevent_context_init(mem_ctx);
2120                 if (event_ctx == NULL) {
2121                         TALLOC_FREE(password_script);
2122                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2123                 }
2124
2125                 /* Gives a warning after 1 second, terminates after 10 */
2126                 tevent_add_timer(event_ctx, event_ctx,
2127                                  tevent_timeval_current_ofs(1, 0),
2128                                  pwd_timeout_debug, NULL);
2129
2130                 req = samba_runcmd_send(event_ctx, event_ctx,
2131                                         tevent_timeval_current_ofs(10, 0),
2132                                         100, 100, cmd, NULL);
2133                 run_cmd = tevent_req_data(req, struct samba_runcmd_state);
2134                 if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) {
2135                         TALLOC_FREE(password_script);
2136                         TALLOC_FREE(event_ctx);
2137                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2138                 }
2139
2140                 close(run_cmd->fd_stdin);
2141                 run_cmd->fd_stdin = -1;
2142
2143                 if (!tevent_req_poll(req, event_ctx)) {
2144                         TALLOC_FREE(password_script);
2145                         TALLOC_FREE(event_ctx);
2146                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2147                 }
2148
2149                 check_ret = samba_runcmd_recv(req, &error);
2150                 TALLOC_FREE(event_ctx);
2151
2152                 if (error == ETIMEDOUT) {
2153                         DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
2154                         TALLOC_FREE(password_script);
2155                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2156                 }
2157                 DEBUG(5,("check_password_complexity: check password script (%s) "
2158                          "returned [%d]\n", password_script, check_ret));
2159
2160                 if (check_ret != 0) {
2161                         DEBUG(1,("check_password_complexity: "
2162                                  "check password script said new password is not good "
2163                                  "enough!\n"));
2164                         TALLOC_FREE(password_script);
2165                         return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2166                 }
2167
2168                 TALLOC_FREE(password_script);
2169                 return SAMR_VALIDATION_STATUS_SUCCESS;
2170         }
2171
2172         TALLOC_FREE(password_script);
2173
2174         /*
2175          * Here are the standard AD password quality rules, which we
2176          * run after the script.
2177          */
2178
2179         if (!check_password_quality(utf8_pw)) {
2180                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2181         }
2182
2183         return SAMR_VALIDATION_STATUS_SUCCESS;
2184 }
2185
2186 /*
2187  * Callback for "samdb_set_password" password change
2188  */
2189 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2190 {
2191         int ret;
2192
2193         if (!ares) {
2194                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2195         }
2196
2197         if (ares->error != LDB_SUCCESS) {
2198                 ret = ares->error;
2199                 req->context = talloc_steal(req,
2200                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2201                 talloc_free(ares);
2202                 return ldb_request_done(req, ret);
2203         }
2204
2205         if (ares->type != LDB_REPLY_DONE) {
2206                 talloc_free(ares);
2207                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2208         }
2209
2210         req->context = talloc_steal(req,
2211                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2212         talloc_free(ares);
2213         return ldb_request_done(req, LDB_SUCCESS);
2214 }
2215
2216 /*
2217  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2218  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2219  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2220  * user change or not. The "rejectReason" gives some more information if the
2221  * change failed.
2222  *
2223  * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2224  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2225  */
2226 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2227                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2228                             const DATA_BLOB *new_password,
2229                             const struct samr_Password *lmNewHash,
2230                             const struct samr_Password *ntNewHash,
2231                             const struct samr_Password *lmOldHash,
2232                             const struct samr_Password *ntOldHash,
2233                             enum samPwdChangeReason *reject_reason,
2234                             struct samr_DomInfo1 **_dominfo,
2235                             bool permit_interdomain_trust)
2236 {
2237         struct ldb_message *msg;
2238         struct ldb_message_element *el;
2239         struct ldb_request *req;
2240         struct dsdb_control_password_change_status *pwd_stat = NULL;
2241         int ret;
2242         bool hash_values = false;
2243         NTSTATUS status = NT_STATUS_OK;
2244
2245 #define CHECK_RET(x) \
2246         if (x != LDB_SUCCESS) { \
2247                 talloc_free(msg); \
2248                 return NT_STATUS_NO_MEMORY; \
2249         }
2250
2251         msg = ldb_msg_new(mem_ctx);
2252         if (msg == NULL) {
2253                 return NT_STATUS_NO_MEMORY;
2254         }
2255         msg->dn = user_dn;
2256         if ((new_password != NULL)
2257                         && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2258                 /* we have the password as plaintext UTF16 */
2259                 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2260                                             new_password, NULL));
2261                 el = ldb_msg_find_element(msg, "clearTextPassword");
2262                 el->flags = LDB_FLAG_MOD_REPLACE;
2263         } else if ((new_password == NULL)
2264                         && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2265                 /* we have a password as LM and/or NT hash */
2266                 if (lmNewHash != NULL) {
2267                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2268                                 "dBCSPwd", lmNewHash));
2269                         el = ldb_msg_find_element(msg, "dBCSPwd");
2270                         el->flags = LDB_FLAG_MOD_REPLACE;
2271                 }
2272                 if (ntNewHash != NULL) {
2273                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2274                                 "unicodePwd", ntNewHash));
2275                         el = ldb_msg_find_element(msg, "unicodePwd");
2276                         el->flags = LDB_FLAG_MOD_REPLACE;
2277                 }
2278                 hash_values = true;
2279         } else {
2280                 /* the password wasn't specified correctly */
2281                 talloc_free(msg);
2282                 return NT_STATUS_INVALID_PARAMETER;
2283         }
2284
2285         /* build modify request */
2286         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2287                                 samdb_set_password_callback, NULL);
2288         if (ret != LDB_SUCCESS) {
2289                 talloc_free(msg);
2290                 return NT_STATUS_NO_MEMORY;
2291         }
2292
2293         /* A password change operation */
2294         if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2295                 struct dsdb_control_password_change *change;
2296
2297                 change = talloc(req, struct dsdb_control_password_change);
2298                 if (change == NULL) {
2299                         talloc_free(req);
2300                         talloc_free(msg);
2301                         return NT_STATUS_NO_MEMORY;
2302                 }
2303
2304                 change->old_nt_pwd_hash = ntOldHash;
2305                 change->old_lm_pwd_hash = lmOldHash;
2306
2307                 ret = ldb_request_add_control(req,
2308                                               DSDB_CONTROL_PASSWORD_CHANGE_OID,
2309                                               true, change);
2310                 if (ret != LDB_SUCCESS) {
2311                         talloc_free(req);
2312                         talloc_free(msg);
2313                         return NT_STATUS_NO_MEMORY;
2314                 }
2315         }
2316         if (hash_values) {
2317                 ret = ldb_request_add_control(req,
2318                                               DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2319                                               true, NULL);
2320                 if (ret != LDB_SUCCESS) {
2321                         talloc_free(req);
2322                         talloc_free(msg);
2323                         return NT_STATUS_NO_MEMORY;
2324                 }
2325         }
2326         if (permit_interdomain_trust) {
2327                 ret = ldb_request_add_control(req,
2328                                               DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2329                                               false, NULL);
2330                 if (ret != LDB_SUCCESS) {
2331                         talloc_free(req);
2332                         talloc_free(msg);
2333                         return NT_STATUS_NO_MEMORY;
2334                 }
2335         }
2336         ret = ldb_request_add_control(req,
2337                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2338                                       true, NULL);
2339         if (ret != LDB_SUCCESS) {
2340                 talloc_free(req);
2341                 talloc_free(msg);
2342                 return NT_STATUS_NO_MEMORY;
2343         }
2344
2345         ret = dsdb_autotransaction_request(ldb, req);
2346
2347         if (req->context != NULL) {
2348                 struct ldb_control *control = talloc_get_type_abort(req->context,
2349                                                                     struct ldb_control);
2350                 pwd_stat = talloc_get_type_abort(control->data,
2351                                                  struct dsdb_control_password_change_status);
2352                 talloc_steal(mem_ctx, pwd_stat);
2353         }
2354
2355         talloc_free(req);
2356         talloc_free(msg);
2357
2358         /* Sets the domain info (if requested) */
2359         if (_dominfo != NULL) {
2360                 struct samr_DomInfo1 *dominfo;
2361
2362                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2363                 if (dominfo == NULL) {
2364                         return NT_STATUS_NO_MEMORY;
2365                 }
2366
2367                 if (pwd_stat != NULL) {
2368                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
2369                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
2370                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2371                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
2372                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
2373                 }
2374
2375                 *_dominfo = dominfo;
2376         }
2377
2378         if (reject_reason != NULL) {
2379                 if (pwd_stat != NULL) {
2380                         *reject_reason = pwd_stat->reject_reason;
2381                 } else {
2382                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2383                 }
2384         }
2385
2386         if (pwd_stat != NULL) {
2387                 talloc_free(pwd_stat);
2388         }
2389
2390         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2391                 const char *errmsg = ldb_errstring(ldb);
2392                 char *endptr = NULL;
2393                 WERROR werr = WERR_GEN_FAILURE;
2394                 status = NT_STATUS_UNSUCCESSFUL;
2395                 if (errmsg != NULL) {
2396                         werr = W_ERROR(strtol(errmsg, &endptr, 16));
2397                         DBG_WARNING("%s\n", errmsg);
2398                 }
2399                 if (endptr != errmsg) {
2400                         if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2401                                 status = NT_STATUS_WRONG_PASSWORD;
2402                         }
2403                         if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2404                                 status = NT_STATUS_PASSWORD_RESTRICTION;
2405                         }
2406                 }
2407         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2408                 /* don't let the caller know if an account doesn't exist */
2409                 status = NT_STATUS_WRONG_PASSWORD;
2410         } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2411                 status = NT_STATUS_ACCESS_DENIED;
2412         } else if (ret != LDB_SUCCESS) {
2413                 DEBUG(1, ("Failed to set password on %s: %s\n",
2414                           ldb_dn_get_linearized(user_dn),
2415                           ldb_errstring(ldb)));
2416                 status = NT_STATUS_UNSUCCESSFUL;
2417         }
2418
2419         return status;
2420 }
2421
2422 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2423                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2424                             const DATA_BLOB *new_password,
2425                             const struct samr_Password *lmNewHash,
2426                             const struct samr_Password *ntNewHash,
2427                             const struct samr_Password *lmOldHash,
2428                             const struct samr_Password *ntOldHash,
2429                             enum samPwdChangeReason *reject_reason,
2430                             struct samr_DomInfo1 **_dominfo)
2431 {
2432         return samdb_set_password_internal(ldb, mem_ctx,
2433                             user_dn, domain_dn,
2434                             new_password,
2435                             lmNewHash, ntNewHash,
2436                             lmOldHash, ntOldHash,
2437                             reject_reason, _dominfo,
2438                             false); /* reject trusts */
2439 }
2440
2441 /*
2442  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2443  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2444  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2445  * user change or not. The "rejectReason" gives some more information if the
2446  * change failed.
2447  *
2448  * This wrapper function for "samdb_set_password" takes a SID as input rather
2449  * than a user DN.
2450  *
2451  * This call encapsulates a new LDB transaction for changing the password;
2452  * therefore the user hasn't to start a new one.
2453  *
2454  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2455  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2456  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2457  *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2458  */
2459 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2460                                 const struct dom_sid *user_sid,
2461                                 const uint32_t *new_version, /* optional for trusts */
2462                                 const DATA_BLOB *new_password,
2463                                 const struct samr_Password *lmNewHash,
2464                                 const struct samr_Password *ntNewHash,
2465                                 const struct samr_Password *lmOldHash,
2466                                 const struct samr_Password *ntOldHash,
2467                                 enum samPwdChangeReason *reject_reason,
2468                                 struct samr_DomInfo1 **_dominfo) 
2469 {
2470         TALLOC_CTX *frame = talloc_stackframe();
2471         NTSTATUS nt_status;
2472         const char * const user_attrs[] = {
2473                 "userAccountControl",
2474                 "sAMAccountName",
2475                 NULL
2476         };
2477         struct ldb_message *user_msg = NULL;
2478         int ret;
2479         uint32_t uac = 0;
2480
2481         ret = ldb_transaction_start(ldb);
2482         if (ret != LDB_SUCCESS) {
2483                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2484                 TALLOC_FREE(frame);
2485                 return NT_STATUS_TRANSACTION_ABORTED;
2486         }
2487
2488         ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2489                               LDB_SCOPE_SUBTREE, user_attrs, 0,
2490                               "(&(objectSid=%s)(objectClass=user))",
2491                               ldap_encode_ndr_dom_sid(frame, user_sid));
2492         if (ret != LDB_SUCCESS) {
2493                 ldb_transaction_cancel(ldb);
2494                 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2495                           "returning NO_SUCH_USER\n",
2496                           dom_sid_string(frame, user_sid),
2497                           ldb_strerror(ret), ldb_errstring(ldb)));
2498                 TALLOC_FREE(frame);
2499                 return NT_STATUS_NO_SUCH_USER;
2500         }
2501
2502         uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2503         if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2504                 ldb_transaction_cancel(ldb);
2505                 DEBUG(1, ("samdb_set_password_sid: invalid "
2506                           "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2507                           "returning NO_SUCH_USER\n",
2508                           (unsigned)uac, dom_sid_string(frame, user_sid),
2509                           ldb_dn_get_linearized(user_msg->dn)));
2510                 TALLOC_FREE(frame);
2511                 return NT_STATUS_NO_SUCH_USER;
2512         }
2513
2514         if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2515                 const char * const tdo_attrs[] = {
2516                         "trustAuthIncoming",
2517                         "trustDirection",
2518                         NULL
2519                 };
2520                 struct ldb_message *tdo_msg = NULL;
2521                 const char *account_name = NULL;
2522                 uint32_t trust_direction;
2523                 uint32_t i;
2524                 const struct ldb_val *old_val = NULL;
2525                 struct trustAuthInOutBlob old_blob = {};
2526                 uint32_t old_version = 0;
2527                 struct AuthenticationInformation *old_version_a = NULL;
2528                 uint32_t _new_version = 0;
2529                 struct trustAuthInOutBlob new_blob = {};
2530                 struct ldb_val new_val = {};
2531                 struct timeval tv = timeval_current();
2532                 NTTIME now = timeval_to_nttime(&tv);
2533                 enum ndr_err_code ndr_err;
2534
2535                 if (new_password == NULL && ntNewHash == NULL) {
2536                         ldb_transaction_cancel(ldb);
2537                         DEBUG(1, ("samdb_set_password_sid: "
2538                                   "no new password provided "
2539                                   "sAMAccountName for SID[%s] DN[%s], "
2540                                   "returning INVALID_PARAMETER\n",
2541                                   dom_sid_string(frame, user_sid),
2542                                   ldb_dn_get_linearized(user_msg->dn)));
2543                         TALLOC_FREE(frame);
2544                         return NT_STATUS_INVALID_PARAMETER;
2545                 }
2546
2547                 if (new_password != NULL && ntNewHash != NULL) {
2548                         ldb_transaction_cancel(ldb);
2549                         DEBUG(1, ("samdb_set_password_sid: "
2550                                   "two new passwords provided "
2551                                   "sAMAccountName for SID[%s] DN[%s], "
2552                                   "returning INVALID_PARAMETER\n",
2553                                   dom_sid_string(frame, user_sid),
2554                                   ldb_dn_get_linearized(user_msg->dn)));
2555                         TALLOC_FREE(frame);
2556                         return NT_STATUS_INVALID_PARAMETER;
2557                 }
2558
2559                 if (new_password != NULL && (new_password->length % 2)) {
2560                         ldb_transaction_cancel(ldb);
2561                         DEBUG(2, ("samdb_set_password_sid: "
2562                                   "invalid utf16 length (%zu) "
2563                                   "sAMAccountName for SID[%s] DN[%s], "
2564                                   "returning WRONG_PASSWORD\n",
2565                                   new_password->length,
2566                                   dom_sid_string(frame, user_sid),
2567                                   ldb_dn_get_linearized(user_msg->dn)));
2568                         TALLOC_FREE(frame);
2569                         return NT_STATUS_WRONG_PASSWORD;
2570                 }
2571
2572                 if (new_password != NULL && new_password->length >= 500) {
2573                         ldb_transaction_cancel(ldb);
2574                         DEBUG(2, ("samdb_set_password_sid: "
2575                                   "utf16 password too long (%zu) "
2576                                   "sAMAccountName for SID[%s] DN[%s], "
2577                                   "returning WRONG_PASSWORD\n",
2578                                   new_password->length,
2579                                   dom_sid_string(frame, user_sid),
2580                                   ldb_dn_get_linearized(user_msg->dn)));
2581                         TALLOC_FREE(frame);
2582                         return NT_STATUS_WRONG_PASSWORD;
2583                 }
2584
2585                 account_name = ldb_msg_find_attr_as_string(user_msg,
2586                                                         "sAMAccountName", NULL);
2587                 if (account_name == NULL) {
2588                         ldb_transaction_cancel(ldb);
2589                         DEBUG(1, ("samdb_set_password_sid: missing "
2590                                   "sAMAccountName for SID[%s] DN[%s], "
2591                                   "returning NO_SUCH_USER\n",
2592                                   dom_sid_string(frame, user_sid),
2593                                   ldb_dn_get_linearized(user_msg->dn)));
2594                         TALLOC_FREE(frame);
2595                         return NT_STATUS_NO_SUCH_USER;
2596                 }
2597
2598                 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2599                                                           SEC_CHAN_DOMAIN,
2600                                                           account_name,
2601                                                           tdo_attrs,
2602                                                           frame, &tdo_msg);
2603                 if (!NT_STATUS_IS_OK(nt_status)) {
2604                         ldb_transaction_cancel(ldb);
2605                         DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2606                                   "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2607                                   "returning INTERNAL_DB_CORRUPTION\n",
2608                                   nt_errstr(nt_status), account_name,
2609                                   dom_sid_string(frame, user_sid),
2610                                   ldb_dn_get_linearized(user_msg->dn)));
2611                         TALLOC_FREE(frame);
2612                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2613                 }
2614
2615                 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2616                                                            "trustDirection", 0);
2617                 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2618                         ldb_transaction_cancel(ldb);
2619                         DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2620                                   "not inbound for sAMAccountName[%s] "
2621                                   "DN[%s] TDO[%s], "
2622                                   "returning INTERNAL_DB_CORRUPTION\n",
2623                                   (unsigned)trust_direction,
2624                                   account_name,
2625                                   ldb_dn_get_linearized(user_msg->dn),
2626                                   ldb_dn_get_linearized(tdo_msg->dn)));
2627                         TALLOC_FREE(frame);
2628                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2629                 }
2630
2631                 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2632                 if (old_val != NULL) {
2633                         ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2634                                         (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2635                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2636                                 ldb_transaction_cancel(ldb);
2637                                 DEBUG(1, ("samdb_set_password_sid: "
2638                                           "failed(%s) to parse "
2639                                           "trustAuthOutgoing sAMAccountName[%s] "
2640                                           "DN[%s] TDO[%s], "
2641                                           "returning INTERNAL_DB_CORRUPTION\n",
2642                                           ndr_map_error2string(ndr_err),
2643                                           account_name,
2644                                           ldb_dn_get_linearized(user_msg->dn),
2645                                           ldb_dn_get_linearized(tdo_msg->dn)));
2646
2647                                 TALLOC_FREE(frame);
2648                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2649                         }
2650                 }
2651
2652                 for (i = old_blob.current.count; i > 0; i--) {
2653                         struct AuthenticationInformation *a =
2654                                 &old_blob.current.array[i - 1];
2655
2656                         switch (a->AuthType) {
2657                         case TRUST_AUTH_TYPE_NONE:
2658                                 if (i == old_blob.current.count) {
2659                                         /*
2660                                          * remove TRUST_AUTH_TYPE_NONE at the
2661                                          * end
2662                                          */
2663                                         old_blob.current.count--;
2664                                 }
2665                                 break;
2666
2667                         case TRUST_AUTH_TYPE_VERSION:
2668                                 old_version_a = a;
2669                                 old_version = a->AuthInfo.version.version;
2670                                 break;
2671
2672                         case TRUST_AUTH_TYPE_CLEAR:
2673                                 break;
2674
2675                         case TRUST_AUTH_TYPE_NT4OWF:
2676                                 break;
2677                         }
2678                 }
2679
2680                 if (new_version == NULL) {
2681                         _new_version = 0;
2682                         new_version = &_new_version;
2683                 }
2684
2685                 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2686                         old_version_a->LastUpdateTime = now;
2687                         old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2688                 }
2689
2690                 new_blob.count = MAX(old_blob.current.count, 2);
2691                 new_blob.current.array = talloc_zero_array(frame,
2692                                                 struct AuthenticationInformation,
2693                                                 new_blob.count);
2694                 if (new_blob.current.array == NULL) {
2695                         ldb_transaction_cancel(ldb);
2696                         TALLOC_FREE(frame);
2697                         return NT_STATUS_NO_MEMORY;
2698                 }
2699                 new_blob.previous.array = talloc_zero_array(frame,
2700                                                 struct AuthenticationInformation,
2701                                                 new_blob.count);
2702                 if (new_blob.current.array == NULL) {
2703                         ldb_transaction_cancel(ldb);
2704                         TALLOC_FREE(frame);
2705                         return NT_STATUS_NO_MEMORY;
2706                 }
2707
2708                 for (i = 0; i < old_blob.current.count; i++) {
2709                         struct AuthenticationInformation *o =
2710                                 &old_blob.current.array[i];
2711                         struct AuthenticationInformation *p =
2712                                 &new_blob.previous.array[i];
2713
2714                         *p = *o;
2715                         new_blob.previous.count++;
2716                 }
2717                 for (; i < new_blob.count; i++) {
2718                         struct AuthenticationInformation *pi =
2719                                 &new_blob.previous.array[i];
2720
2721                         if (i == 0) {
2722                                 /*
2723                                  * new_blob.previous is still empty so
2724                                  * we'll do new_blob.previous = new_blob.current
2725                                  * below.
2726                                  */
2727                                 break;
2728                         }
2729
2730                         pi->LastUpdateTime = now;
2731                         pi->AuthType = TRUST_AUTH_TYPE_NONE;
2732                         new_blob.previous.count++;
2733                 }
2734
2735                 for (i = 0; i < new_blob.count; i++) {
2736                         struct AuthenticationInformation *ci =
2737                                 &new_blob.current.array[i];
2738
2739                         ci->LastUpdateTime = now;
2740                         switch (i) {
2741                         case 0:
2742                                 if (ntNewHash != NULL) {
2743                                         ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2744                                         ci->AuthInfo.nt4owf.password = *ntNewHash;
2745                                         break;
2746                                 }
2747
2748                                 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2749                                 ci->AuthInfo.clear.size = new_password->length;
2750                                 ci->AuthInfo.clear.password = new_password->data;
2751                                 break;
2752                         case 1:
2753                                 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2754                                 ci->AuthInfo.version.version = *new_version;
2755                                 break;
2756                         default:
2757                                 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2758                                 break;
2759                         }
2760
2761                         new_blob.current.count++;
2762                 }
2763
2764                 if (new_blob.previous.count == 0) {
2765                         TALLOC_FREE(new_blob.previous.array);
2766                         new_blob.previous = new_blob.current;
2767                 }
2768
2769                 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2770                                 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2771                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2772                         ldb_transaction_cancel(ldb);
2773                         DEBUG(1, ("samdb_set_password_sid: "
2774                                   "failed(%s) to generate "
2775                                   "trustAuthOutgoing sAMAccountName[%s] "
2776                                   "DN[%s] TDO[%s], "
2777                                   "returning UNSUCCESSFUL\n",
2778                                   ndr_map_error2string(ndr_err),
2779                                   account_name,
2780                                   ldb_dn_get_linearized(user_msg->dn),
2781                                   ldb_dn_get_linearized(tdo_msg->dn)));
2782                         TALLOC_FREE(frame);
2783                         return NT_STATUS_UNSUCCESSFUL;
2784                 }
2785
2786                 tdo_msg->num_elements = 0;
2787                 TALLOC_FREE(tdo_msg->elements);
2788
2789                 ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
2790                                         LDB_FLAG_MOD_REPLACE, NULL);
2791                 if (ret != LDB_SUCCESS) {
2792                         ldb_transaction_cancel(ldb);
2793                         TALLOC_FREE(frame);
2794                         return NT_STATUS_NO_MEMORY;
2795                 }
2796                 ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
2797                                         &new_val, NULL);
2798                 if (ret != LDB_SUCCESS) {
2799                         ldb_transaction_cancel(ldb);
2800                         TALLOC_FREE(frame);
2801                         return NT_STATUS_NO_MEMORY;
2802                 }
2803
2804                 ret = ldb_modify(ldb, tdo_msg);
2805                 if (ret != LDB_SUCCESS) {
2806                         nt_status = dsdb_ldb_err_to_ntstatus(ret);
2807                         ldb_transaction_cancel(ldb);
2808                         DEBUG(1, ("samdb_set_password_sid: "
2809                                   "failed to replace "
2810                                   "trustAuthOutgoing sAMAccountName[%s] "
2811                                   "DN[%s] TDO[%s], "
2812                                   "%s - %s\n",
2813                                   account_name,
2814                                   ldb_dn_get_linearized(user_msg->dn),
2815                                   ldb_dn_get_linearized(tdo_msg->dn),
2816                                   nt_errstr(nt_status), ldb_errstring(ldb)));
2817                         TALLOC_FREE(frame);
2818                         return nt_status;
2819                 }
2820         }
2821
2822         nt_status = samdb_set_password_internal(ldb, mem_ctx,
2823                                                 user_msg->dn, NULL,
2824                                                 new_password,
2825                                                 lmNewHash, ntNewHash,
2826                                                 lmOldHash, ntOldHash,
2827                                                 reject_reason, _dominfo,
2828                                                 true); /* permit trusts */
2829         if (!NT_STATUS_IS_OK(nt_status)) {
2830                 ldb_transaction_cancel(ldb);
2831                 TALLOC_FREE(frame);
2832                 return nt_status;
2833         }
2834
2835         ret = ldb_transaction_commit(ldb);
2836         if (ret != LDB_SUCCESS) {
2837                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2838                          ldb_dn_get_linearized(user_msg->dn),
2839                          ldb_errstring(ldb)));
2840                 TALLOC_FREE(frame);
2841                 return NT_STATUS_TRANSACTION_ABORTED;
2842         }
2843
2844         TALLOC_FREE(frame);
2845         return NT_STATUS_OK;
2846 }
2847
2848
2849 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
2850                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
2851 {
2852         struct ldb_message *msg;
2853         struct ldb_dn *basedn;
2854         char *sidstr;
2855         int ret;
2856
2857         sidstr = dom_sid_string(mem_ctx, sid);
2858         NT_STATUS_HAVE_NO_MEMORY(sidstr);
2859
2860         /* We might have to create a ForeignSecurityPrincipal, even if this user
2861          * is in our own domain */
2862
2863         msg = ldb_msg_new(sidstr);
2864         if (msg == NULL) {
2865                 talloc_free(sidstr);
2866                 return NT_STATUS_NO_MEMORY;
2867         }
2868
2869         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2870                                 ldb_get_default_basedn(sam_ctx),
2871                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2872                                 &basedn);
2873         if (ret != LDB_SUCCESS) {
2874                 DEBUG(0, ("Failed to find DN for "
2875                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2876                 talloc_free(sidstr);
2877                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2878         }
2879
2880         /* add core elements to the ldb_message for the alias */
2881         msg->dn = basedn;
2882         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2883                 talloc_free(sidstr);
2884                 return NT_STATUS_NO_MEMORY;
2885         }
2886
2887         ret = ldb_msg_add_string(msg, "objectClass",
2888                                  "foreignSecurityPrincipal");
2889         if (ret != LDB_SUCCESS) {
2890                 talloc_free(sidstr);
2891                 return NT_STATUS_NO_MEMORY;
2892         }
2893
2894         /* create the alias */
2895         ret = ldb_add(sam_ctx, msg);
2896         if (ret != LDB_SUCCESS) {
2897                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2898                          "record %s: %s\n", 
2899                          ldb_dn_get_linearized(msg->dn),
2900                          ldb_errstring(sam_ctx)));
2901                 talloc_free(sidstr);
2902                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2903         }
2904
2905         *ret_dn = talloc_steal(mem_ctx, msg->dn);
2906         talloc_free(sidstr);
2907
2908         return NT_STATUS_OK;
2909 }
2910
2911
2912 /*
2913   Find the DN of a domain, assuming it to be a dotted.dns name
2914 */
2915
2916 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2917 {
2918         unsigned int i;
2919         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2920         const char *binary_encoded;
2921         const char * const *split_realm;
2922         struct ldb_dn *dn;
2923
2924         if (!tmp_ctx) {
2925                 return NULL;
2926         }
2927
2928         split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
2929         if (!split_realm) {
2930                 talloc_free(tmp_ctx);
2931                 return NULL;
2932         }
2933         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2934         for (i=0; split_realm[i]; i++) {
2935                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2936                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2937                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2938                                   binary_encoded, ldb_dn_get_linearized(dn)));
2939                         talloc_free(tmp_ctx);
2940                         return NULL;
2941                 }
2942         }
2943         if (!ldb_dn_validate(dn)) {
2944                 DEBUG(2, ("Failed to validated DN %s\n",
2945                           ldb_dn_get_linearized(dn)));
2946                 talloc_free(tmp_ctx);
2947                 return NULL;
2948         }
2949         talloc_free(tmp_ctx);
2950         return dn;
2951 }
2952
2953
2954 /*
2955   Find the DNS equivalent of a DN, in dotted DNS form
2956 */
2957 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
2958 {
2959         int i, num_components = ldb_dn_get_comp_num(dn);
2960         char *dns_name = talloc_strdup(mem_ctx, "");
2961         if (dns_name == NULL) {
2962                 return NULL;
2963         }
2964
2965         for (i=0; i<num_components; i++) {
2966                 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
2967                 char *s;
2968                 if (v == NULL) {
2969                         talloc_free(dns_name);
2970                         return NULL;
2971                 }
2972                 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
2973                                                   (int)v->length, (int)v->length, (char *)v->data);
2974                 if (s == NULL) {
2975                         talloc_free(dns_name);
2976                         return NULL;
2977                 }
2978                 dns_name = s;
2979         }
2980
2981         /* remove the last '.' */
2982         if (dns_name[0] != 0) {
2983                 dns_name[strlen(dns_name)-1] = 0;
2984         }
2985
2986         return dns_name;
2987 }
2988
2989 /*
2990   Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
2991   name is based on the forest DNS name
2992 */
2993 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
2994                                 TALLOC_CTX *mem_ctx,
2995                                 const struct GUID *ntds_guid)
2996 {
2997         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2998         const char *guid_str;
2999         struct ldb_dn *forest_dn;
3000         const char *dnsforest;
3001         char *ret;
3002
3003         guid_str = GUID_string(tmp_ctx, ntds_guid);
3004         if (guid_str == NULL) {
3005                 talloc_free(tmp_ctx);
3006                 return NULL;
3007         }
3008         forest_dn = ldb_get_root_basedn(samdb);
3009         if (forest_dn == NULL) {
3010                 talloc_free(tmp_ctx);
3011                 return NULL;
3012         }
3013         dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
3014         if (dnsforest == NULL) {
3015                 talloc_free(tmp_ctx);
3016                 return NULL;
3017         }
3018         ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
3019         talloc_free(tmp_ctx);
3020         return ret;
3021 }
3022
3023
3024 /*
3025   Find the DN of a domain, be it the netbios or DNS name 
3026 */
3027 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
3028                                   const char *domain_name) 
3029 {
3030         const char * const domain_ref_attrs[] = {
3031                 "ncName", NULL
3032         };
3033         const char * const domain_ref2_attrs[] = {
3034                 NULL
3035         };
3036         struct ldb_result *res_domain_ref;
3037         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
3038         /* find the domain's DN */
3039         int ret_domain = ldb_search(ldb, mem_ctx,
3040                                             &res_domain_ref, 
3041                                             samdb_partitions_dn(ldb, mem_ctx), 
3042                                             LDB_SCOPE_ONELEVEL, 
3043                                             domain_ref_attrs,
3044                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
3045                                             escaped_domain);
3046         if (ret_domain != LDB_SUCCESS) {
3047                 return NULL;
3048         }
3049
3050         if (res_domain_ref->count == 0) {
3051                 ret_domain = ldb_search(ldb, mem_ctx,
3052                                                 &res_domain_ref, 
3053                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
3054                                                 LDB_SCOPE_BASE,
3055                                                 domain_ref2_attrs,
3056                                                 "(objectclass=domain)");
3057                 if (ret_domain != LDB_SUCCESS) {
3058                         return NULL;
3059                 }
3060
3061                 if (res_domain_ref->count == 1) {
3062                         return res_domain_ref->msgs[0]->dn;
3063                 }
3064                 return NULL;
3065         }
3066
3067         if (res_domain_ref->count > 1) {
3068                 DEBUG(0,("Found %d records matching domain [%s]\n", 
3069                          ret_domain, domain_name));
3070                 return NULL;
3071         }
3072
3073         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3074
3075 }
3076
3077
3078 /*
3079   use a GUID to find a DN
3080  */
3081 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
3082                          TALLOC_CTX *mem_ctx,
3083                          const struct GUID *guid,
3084                          uint32_t dsdb_flags,
3085                          struct ldb_dn **dn)
3086 {
3087         int ret;
3088         struct ldb_result *res;
3089         const char *attrs[] = { NULL };
3090         char *guid_str = GUID_string(mem_ctx, guid);
3091
3092         if (!guid_str) {
3093                 return ldb_operr(ldb);
3094         }
3095
3096         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3097                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3098                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3099                           DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3100                           "objectGUID=%s", guid_str);
3101         talloc_free(guid_str);
3102         if (ret != LDB_SUCCESS) {
3103                 return ret;
3104         }
3105
3106         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3107         talloc_free(res);
3108
3109         return LDB_SUCCESS;
3110 }
3111
3112 /*
3113   use a DN to find a GUID with a given attribute name
3114  */
3115 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3116                               struct ldb_dn *dn, const char *attribute,
3117                               struct GUID *guid)
3118 {
3119         int ret;
3120         struct ldb_result *res;
3121         const char *attrs[2];
3122         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3123
3124         attrs[0] = attribute;
3125         attrs[1] = NULL;
3126
3127         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3128                              DSDB_SEARCH_SHOW_DELETED |
3129                              DSDB_SEARCH_SHOW_RECYCLED);
3130         if (ret != LDB_SUCCESS) {
3131                 talloc_free(tmp_ctx);
3132                 return ret;
3133         }
3134         if (res->count < 1) {
3135                 talloc_free(tmp_ctx);
3136                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3137         }
3138         *guid = samdb_result_guid(res->msgs[0], attribute);
3139         talloc_free(tmp_ctx);
3140         return LDB_SUCCESS;
3141 }
3142
3143 /*
3144   use a DN to find a GUID
3145  */
3146 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3147                          struct ldb_dn *dn, struct GUID *guid)
3148 {
3149         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3150 }
3151
3152
3153
3154 /*
3155  adds the given GUID to the given ldb_message. This value is added
3156  for the given attr_name (may be either "objectGUID" or "parentGUID").
3157  */
3158 int dsdb_msg_add_guid(struct ldb_message *msg,
3159                 struct GUID *guid,
3160                 const char *attr_name)
3161 {
3162         int ret;
3163         struct ldb_val v;
3164         NTSTATUS status;
3165         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
3166
3167         status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3168         if (!NT_STATUS_IS_OK(status)) {
3169                 ret = LDB_ERR_OPERATIONS_ERROR;
3170                 goto done;
3171         }
3172
3173         ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3174         if (ret != LDB_SUCCESS) {
3175                 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3176                                          attr_name));
3177                 goto done;
3178         }
3179
3180         ret = LDB_SUCCESS;
3181
3182 done:
3183         talloc_free(tmp_ctx);
3184         return ret;
3185
3186 }
3187
3188
3189 /*
3190   use a DN to find a SID
3191  */
3192 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 
3193                         struct ldb_dn *dn, struct dom_sid *sid)
3194 {
3195         int ret;
3196         struct ldb_result *res;
3197         const char *attrs[] = { "objectSid", NULL };
3198         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3199         struct dom_sid *s;
3200
3201         ZERO_STRUCTP(sid);
3202
3203         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3204                              DSDB_SEARCH_SHOW_DELETED |
3205                              DSDB_SEARCH_SHOW_RECYCLED);
3206         if (ret != LDB_SUCCESS) {
3207                 talloc_free(tmp_ctx);
3208                 return ret;
3209         }
3210         if (res->count < 1) {
3211                 talloc_free(tmp_ctx);
3212                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3213         }
3214         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3215         if (s == NULL) {
3216                 talloc_free(tmp_ctx);
3217                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3218         }
3219         *sid = *s;
3220         talloc_free(tmp_ctx);
3221         return LDB_SUCCESS;
3222 }
3223
3224 /*
3225   use a SID to find a DN
3226  */
3227 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3228                         TALLOC_CTX *mem_ctx,
3229                         struct dom_sid *sid, struct ldb_dn **dn)
3230 {
3231         int ret;
3232         struct ldb_result *res;
3233         const char *attrs[] = { NULL };
3234         char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3235
3236         if (!sid_str) {
3237                 return ldb_operr(ldb);
3238         }
3239
3240         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3241                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3242                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3243                           DSDB_SEARCH_ONE_ONLY,
3244                           "objectSid=%s", sid_str);
3245         talloc_free(sid_str);
3246         if (ret != LDB_SUCCESS) {
3247                 return ret;
3248         }
3249
3250         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3251         talloc_free(res);
3252
3253         return LDB_SUCCESS;
3254 }
3255
3256 /*
3257   load a repsFromTo blob list for a given partition GUID
3258   attr must be "repsFrom" or "repsTo"
3259  */
3260 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3261                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
3262 {
3263         const char *attrs[] = { attr, NULL };
3264         struct ldb_result *res = NULL;
3265         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3266         unsigned int i;
3267         struct ldb_message_element *el;
3268         int ret;
3269
3270         *r = NULL;
3271         *count = 0;
3272
3273         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3274         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3275                 /* partition hasn't been replicated yet */
3276                 return WERR_OK;
3277         }
3278         if (ret != LDB_SUCCESS) {
3279                 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3280                 talloc_free(tmp_ctx);
3281                 return WERR_DS_DRA_INTERNAL_ERROR;
3282         }
3283
3284         el = ldb_msg_find_element(res->msgs[0], attr);
3285         if (el == NULL) {
3286                 /* it's OK to be empty */
3287                 talloc_free(tmp_ctx);
3288                 return WERR_OK;
3289         }
3290
3291         *count = el->num_values;
3292         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3293         if (*r == NULL) {
3294                 talloc_free(tmp_ctx);
3295                 return WERR_DS_DRA_INTERNAL_ERROR;
3296         }
3297
3298         for (i=0; i<(*count); i++) {
3299                 enum ndr_err_code ndr_err;
3300                 ndr_err = ndr_pull_struct_blob(&el->values[i], 
3301                                                mem_ctx, 
3302                                                &(*r)[i], 
3303                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3304                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3305                         talloc_free(tmp_ctx);
3306                         return WERR_DS_DRA_INTERNAL_ERROR;
3307                 }
3308         }
3309
3310         talloc_free(tmp_ctx);
3311         
3312         return WERR_OK;
3313 }
3314
3315 /*
3316   save the repsFromTo blob list for a given partition GUID
3317   attr must be "repsFrom" or "repsTo"
3318  */
3319 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3320                      const char *attr, struct repsFromToBlob *r, uint32_t count)
3321 {
3322         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3323         struct ldb_message *msg;
3324         struct ldb_message_element *el;
3325         unsigned int i;
3326
3327         msg = ldb_msg_new(tmp_ctx);
3328         msg->dn = dn;
3329         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3330                 goto failed;
3331         }
3332
3333         el->values = talloc_array(msg, struct ldb_val, count);
3334         if (!el->values) {
3335                 goto failed;
3336         }
3337
3338         for (i=0; i<count; i++) {
3339                 struct ldb_val v;
3340                 enum ndr_err_code ndr_err;
3341
3342                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, 
3343                                                &r[i], 
3344                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3345                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3346                         goto failed;
3347                 }
3348
3349                 el->num_values++;
3350                 el->values[i] = v;
3351         }
3352
3353         if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3354                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3355                 goto failed;
3356         }
3357
3358         talloc_free(tmp_ctx);
3359         
3360         return WERR_OK;
3361
3362 failed:
3363         talloc_free(tmp_ctx);
3364         return WERR_DS_DRA_INTERNAL_ERROR;
3365 }
3366
3367
3368 /*
3369   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3370   object for a partition
3371  */
3372 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3373                                 uint64_t *uSN, uint64_t *urgent_uSN)
3374 {
3375         struct ldb_request *req;
3376         int ret;
3377         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3378         struct dsdb_control_current_partition *p_ctrl;
3379         struct ldb_result *res;
3380
3381         res = talloc_zero(tmp_ctx, struct ldb_result);
3382         if (!res) {
3383                 talloc_free(tmp_ctx);
3384                 return ldb_oom(ldb);
3385         }
3386
3387         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3388                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3389                                    LDB_SCOPE_BASE,
3390                                    NULL, NULL,
3391                                    NULL,
3392                                    res, ldb_search_default_callback,
3393                                    NULL);
3394         if (ret != LDB_SUCCESS) {
3395                 talloc_free(tmp_ctx);
3396                 return ret;
3397         }
3398
3399         p_ctrl = talloc(req, struct dsdb_control_current_partition);
3400         if (p_ctrl == NULL) {
3401                 talloc_free(tmp_ctx);
3402                 return ldb_oom(ldb);
3403         }
3404         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3405         p_ctrl->dn = dn;
3406         
3407         ret = ldb_request_add_control(req,
3408                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3409                                       false, p_ctrl);
3410         if (ret != LDB_SUCCESS) {
3411                 talloc_free(tmp_ctx);
3412                 return ret;
3413         }
3414         
3415         /* Run the new request */
3416         ret = ldb_request(ldb, req);
3417         
3418         if (ret == LDB_SUCCESS) {
3419                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3420         }
3421
3422         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3423                 /* it hasn't been created yet, which means
3424                    an implicit value of zero */
3425                 *uSN = 0;
3426                 talloc_free(tmp_ctx);
3427                 return LDB_SUCCESS;
3428         }
3429
3430         if (ret != LDB_SUCCESS) {
3431                 talloc_free(tmp_ctx);
3432                 return ret;
3433         }
3434
3435         if (res->count < 1) {
3436                 *uSN = 0;
3437                 if (urgent_uSN) {
3438                         *urgent_uSN = 0;
3439                 }
3440         } else {
3441                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3442                 if (urgent_uSN) {
3443                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3444                 }
3445         }
3446
3447         talloc_free(tmp_ctx);
3448
3449         return LDB_SUCCESS;     
3450 }
3451
3452 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3453                                                    const struct drsuapi_DsReplicaCursor2 *c2)
3454 {
3455         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3456 }
3457
3458 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3459                                     const struct drsuapi_DsReplicaCursor *c2)
3460 {
3461         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3462 }
3463
3464
3465 /*
3466   see if a computer identified by its invocationId is a RODC
3467 */
3468 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3469 {
3470         /* 1) find the DN for this servers NTDSDSA object
3471            2) search for the msDS-isRODC attribute
3472            3) if not present then not a RODC
3473            4) if present and TRUE then is a RODC
3474         */
3475         struct ldb_dn *config_dn;
3476         const char *attrs[] = { "msDS-isRODC", NULL };
3477         int ret;
3478         struct ldb_result *res;
3479         TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3480
3481         config_dn = ldb_get_config_basedn(sam_ctx);
3482         if (!config_dn) {
3483                 talloc_free(tmp_ctx);
3484                 return ldb_operr(sam_ctx);
3485         }
3486
3487         ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
3488                           DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
3489
3490         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3491                 *is_rodc = false;
3492                 talloc_free(tmp_ctx);
3493                 return LDB_SUCCESS;
3494         }
3495
3496         if (ret != LDB_SUCCESS) {
3497                 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
3498                          GUID_string(tmp_ctx, objectGUID)));
3499                 *is_rodc = false;
3500                 talloc_free(tmp_ctx);
3501                 return ret;
3502         }
3503
3504         ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
3505         *is_rodc = (ret == 1);
3506
3507         talloc_free(tmp_ctx);
3508         return LDB_SUCCESS;
3509 }
3510
3511
3512 /*
3513   see if we are a RODC
3514 */
3515 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3516 {
3517         const struct GUID *objectGUID;
3518         int ret;
3519         bool *cached;
3520
3521         /* see if we have a cached copy */
3522         cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3523         if (cached) {
3524                 *am_rodc = *cached;
3525                 return LDB_SUCCESS;
3526         }
3527
3528         objectGUID = samdb_ntds_objectGUID(sam_ctx);
3529         if (!objectGUID) {
3530                 return ldb_operr(sam_ctx);
3531         }
3532
3533         ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3534         if (ret != LDB_SUCCESS) {
3535                 return ret;
3536         }
3537
3538         cached = talloc(sam_ctx, bool);
3539         if (cached == NULL) {
3540                 return ldb_oom(sam_ctx);
3541         }
3542         *cached = *am_rodc;
3543
3544         ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3545         if (ret != LDB_SUCCESS) {
3546                 talloc_free(cached);
3547                 return ldb_operr(sam_ctx);
3548         }
3549
3550         return LDB_SUCCESS;
3551 }
3552
3553 int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
3554 {
3555         const char *_host_name = NULL;
3556         const char *attrs[] = { "dnsHostName", NULL };
3557         TALLOC_CTX *tmp_ctx = NULL;
3558         int ret;
3559         struct ldb_result *res = NULL;
3560
3561         _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
3562         if (_host_name != NULL) {
3563                 *host_name = _host_name;
3564                 return LDB_SUCCESS;
3565         }
3566
3567         tmp_ctx = talloc_new(sam_ctx);
3568
3569         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
3570
3571         if (res->count != 1 || ret != LDB_SUCCESS) {
3572                 DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s",
3573                           ldb_errstring(sam_ctx)));
3574                 TALLOC_FREE(tmp_ctx);
3575                 return ret;
3576         }
3577
3578
3579         _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
3580                                                  "dnsHostName",
3581                                                  NULL);
3582         if (_host_name == NULL) {
3583                 DEBUG(0, ("Failed to get dnsHostName from rootDSE"));
3584                 TALLOC_FREE(tmp_ctx);
3585                 return LDB_ERR_OPERATIONS_ERROR;
3586         }
3587         ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
3588                              discard_const_p(char *, _host_name));
3589         if (ret != LDB_SUCCESS) {
3590                 TALLOC_FREE(tmp_ctx);
3591                 return ldb_operr(sam_ctx);
3592         }
3593
3594         *host_name = talloc_steal(sam_ctx, _host_name);
3595
3596         TALLOC_FREE(tmp_ctx);
3597         return LDB_SUCCESS;
3598 }
3599
3600 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3601 {
3602         TALLOC_CTX *tmp_ctx;
3603         bool *cached;
3604
3605         tmp_ctx = talloc_new(ldb);
3606         if (tmp_ctx == NULL) {
3607                 goto failed;
3608         }
3609
3610         cached = talloc(tmp_ctx, bool);
3611         if (!cached) {
3612                 goto failed;
3613         }
3614
3615         *cached = am_rodc;
3616         if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3617                 goto failed;
3618         }
3619
3620         talloc_steal(ldb, cached);
3621         talloc_free(tmp_ctx);
3622         return true;
3623
3624 failed:
3625         DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3626         talloc_free(tmp_ctx);
3627         return false;
3628 }
3629
3630
3631 /*
3632  * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3633  * flags are DS_NTDSSETTINGS_OPT_*
3634  */
3635 int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3636                                         uint32_t *options)
3637 {
3638         int rc;
3639         TALLOC_CTX *tmp_ctx;
3640         struct ldb_result *res;
3641         struct ldb_dn *site_dn;
3642         const char *attrs[] = { "options", NULL };
3643
3644         tmp_ctx = talloc_new(ldb_ctx);
3645         if (tmp_ctx == NULL)
3646                 goto failed;
3647
3648         /* Retrieve the site dn for the ldb that we
3649          * have open.  This is our local site.
3650          */
3651         site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3652         if (site_dn == NULL)
3653                 goto failed;
3654
3655         /* Perform a one level (child) search from the local
3656          * site distinguided name.   We're looking for the
3657          * "options" attribute within the nTDSSiteSettings
3658          * object
3659          */
3660         rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
3661                         LDB_SCOPE_ONELEVEL, attrs,
3662                         "objectClass=nTDSSiteSettings");
3663
3664         if (rc != LDB_SUCCESS || res->count != 1)
3665                 goto failed;
3666
3667         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3668
3669         talloc_free(tmp_ctx);
3670
3671         return LDB_SUCCESS;
3672
3673 failed:
3674         DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
3675         talloc_free(tmp_ctx);
3676         return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
3677 }
3678
3679 /*
3680   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 
3681
3682   flags are DS_NTDS_OPTION_*
3683 */
3684 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3685 {
3686         TALLOC_CTX *tmp_ctx;
3687         const char *attrs[] = { "options", NULL };
3688         int ret;
3689         struct ldb_result *res;
3690
3691         tmp_ctx = talloc_new(ldb);
3692         if (tmp_ctx == NULL) {
3693                 goto failed;
3694         }
3695
3696         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3697         if (ret != LDB_SUCCESS) {
3698                 goto failed;
3699         }
3700
3701         if (res->count != 1) {
3702                 goto failed;
3703         }
3704
3705         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3706
3707         talloc_free(tmp_ctx);
3708
3709         return LDB_SUCCESS;
3710
3711 failed:
3712         DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3713         talloc_free(tmp_ctx);
3714         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3715 }
3716
3717 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3718 {
3719         const char *attrs[] = { "objectCategory", NULL };
3720         int ret;
3721         struct ldb_result *res;
3722
3723         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3724         if (ret != LDB_SUCCESS) {
3725                 goto failed;
3726         }
3727
3728         if (res->count != 1) {
3729                 goto failed;
3730         }
3731
3732         return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3733
3734 failed:
3735         DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3736         return NULL;
3737 }
3738
3739 /*
3740  * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3741  * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3742  */
3743 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3744 {
3745         char **tokens, *ret;
3746         size_t i;
3747
3748         tokens = str_list_make(mem_ctx, cn, " -_");
3749         if (tokens == NULL || tokens[0] == NULL) {
3750                 return NULL;
3751         }
3752
3753         /* "tolower()" and "toupper()" should also work properly on 0x00 */
3754         tokens[0][0] = tolower(tokens[0][0]);
3755         for (i = 1; tokens[i] != NULL; i++)
3756                 tokens[i][0] = toupper(tokens[i][0]);
3757
3758         ret = talloc_strdup(mem_ctx, tokens[0]);
3759         for (i = 1; tokens[i] != NULL; i++)
3760                 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3761
3762         talloc_free(tokens);
3763
3764         return ret;
3765 }
3766
3767 /*
3768  * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3769  */
3770 int dsdb_functional_level(struct ldb_context *ldb)
3771 {
3772         int *domainFunctionality =
3773                 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3774         if (!domainFunctionality) {
3775                 /* this is expected during initial provision */
3776                 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3777                 return DS_DOMAIN_FUNCTION_2000;
3778         }
3779         return *domainFunctionality;
3780 }
3781
3782 /*
3783  * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3784  */
3785 int dsdb_forest_functional_level(struct ldb_context *ldb)
3786 {
3787         int *forestFunctionality =
3788                 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3789         if (!forestFunctionality) {
3790                 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3791                 return DS_DOMAIN_FUNCTION_2000;
3792         }
3793         return *forestFunctionality;
3794 }
3795
3796 /*
3797   set a GUID in an extended DN structure
3798  */
3799 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3800 {
3801         struct ldb_val v;
3802         NTSTATUS status;
3803         int ret;
3804
3805         status = GUID_to_ndr_blob(guid, dn, &v);
3806         if (!NT_STATUS_IS_OK(status)) {
3807                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3808         }
3809
3810         ret = ldb_dn_set_extended_component(dn, component_name, &v);
3811         data_blob_free(&v);
3812         return ret;
3813 }
3814
3815 /*
3816   return a GUID from a extended DN structure
3817  */
3818 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3819 {
3820         const struct ldb_val *v;
3821
3822         v = ldb_dn_get_extended_component(dn, component_name);
3823         if (v == NULL) {
3824                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3825         }
3826
3827         return GUID_from_ndr_blob(v, guid);
3828 }
3829
3830 /*
3831   return a uint64_t from a extended DN structure
3832  */
3833 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3834 {
3835         const struct ldb_val *v;
3836
3837         v = ldb_dn_get_extended_component(dn, component_name);
3838         if (v == NULL) {
3839                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3840         }
3841
3842         /* Just check we don't allow the caller to fill our stack */
3843         if (v->length >= 64) {
3844                 return NT_STATUS_INVALID_PARAMETER;
3845         } else {
3846                 char s[v->length+1];
3847                 memcpy(s, v->data, v->length);
3848                 s[v->length] = 0;
3849
3850                 *val = strtoull(s, NULL, 0);
3851         }
3852         return NT_STATUS_OK;
3853 }
3854
3855 /*
3856   return a NTTIME from a extended DN structure
3857  */
3858 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3859 {
3860         return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3861 }
3862
3863 /*
3864   return a uint32_t from a extended DN structure
3865  */
3866 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3867 {
3868         const struct ldb_val *v;
3869
3870         v = ldb_dn_get_extended_component(dn, component_name);
3871         if (v == NULL) {
3872                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3873         }
3874
3875         /* Just check we don't allow the caller to fill our stack */
3876         if (v->length >= 32) {
3877                 return NT_STATUS_INVALID_PARAMETER;
3878         } else {
3879                 char s[v->length + 1];
3880                 memcpy(s, v->data, v->length);
3881                 s[v->length] = 0;
3882                 *val = strtoul(s, NULL, 0);
3883         }
3884
3885         return NT_STATUS_OK;
3886 }
3887
3888 /*
3889   return a dom_sid from a extended DN structure
3890  */
3891 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3892 {
3893         const struct ldb_val *sid_blob;
3894         enum ndr_err_code ndr_err;
3895
3896         sid_blob = ldb_dn_get_extended_component(dn, component_name);
3897         if (!sid_blob) {
3898                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3899         }
3900
3901         ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
3902                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3903         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3904                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3905                 return status;
3906         }
3907
3908         return NT_STATUS_OK;
3909 }
3910
3911
3912 /*
3913   return RMD_FLAGS directly from a ldb_dn
3914   returns 0 if not found
3915  */
3916 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3917 {
3918         uint32_t rmd_flags = 0;
3919         NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
3920                                                       "RMD_FLAGS");
3921         if (NT_STATUS_IS_OK(status)) {
3922                 return rmd_flags;
3923         }
3924         return 0;
3925 }
3926
3927 /*
3928   return RMD_FLAGS directly from a ldb_val for a DN
3929   returns 0 if RMD_FLAGS is not found
3930  */
3931 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3932 {
3933         const char *p;
3934         uint32_t flags;
3935         char *end;
3936
3937         if (val->length < 13) {
3938                 return 0;
3939         }
3940         p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3941         if (!p) {
3942                 return 0;
3943         }
3944         flags = strtoul(p+11, &end, 10);
3945         if (!end || *end != '>') {
3946                 /* it must end in a > */
3947                 return 0;
3948         }
3949         return flags;
3950 }
3951
3952 /*
3953   return true if a ldb_val containing a DN in storage form is deleted
3954  */
3955 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3956 {
3957         return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3958 }
3959
3960 /*
3961   return true if a ldb_val containing a DN in storage form is
3962   in the upgraded w2k3 linked attribute format
3963  */
3964 bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
3965 {
3966         return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
3967 }
3968
3969 /*
3970   return a DN for a wellknown GUID
3971  */
3972 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3973                       struct ldb_dn *nc_root, const char *wk_guid,
3974                       struct ldb_dn **wkguid_dn)
3975 {
3976         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3977         const char *attrs[] = { NULL };
3978         int ret;
3979         struct ldb_dn *dn;
3980         struct ldb_result *res;
3981
3982         /* construct the magic WKGUID DN */
3983         dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3984                             wk_guid, ldb_dn_get_linearized(nc_root));
3985         if (!wkguid_dn) {
3986                 talloc_free(tmp_ctx);
3987                 return ldb_operr(samdb);
3988         }
3989
3990         ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3991                              DSDB_SEARCH_SHOW_DELETED |
3992                              DSDB_SEARCH_SHOW_RECYCLED);
3993         if (ret != LDB_SUCCESS) {
3994                 talloc_free(tmp_ctx);
3995                 return ret;
3996         }
3997
3998         (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
3999         talloc_free(tmp_ctx);
4000         return LDB_SUCCESS;
4001 }
4002
4003
4004 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
4005 {
4006         return ldb_dn_compare(*dn1, *dn2);
4007 }
4008
4009 /*
4010   find a NC root given a DN within the NC
4011  */
4012 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
4013                       struct ldb_dn **nc_root)
4014 {
4015         const char *root_attrs[] = { "namingContexts", NULL };
4016         TALLOC_CTX *tmp_ctx;
4017         int ret;
4018         struct ldb_message_element *el;
4019         struct ldb_result *root_res;
4020         unsigned int i;
4021         struct ldb_dn **nc_dns;
4022
4023         tmp_ctx = talloc_new(samdb);
4024         if (tmp_ctx == NULL) {
4025                 return ldb_oom(samdb);
4026         }
4027
4028         ret = ldb_search(samdb, tmp_ctx, &root_res,
4029                          ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
4030         if (ret != LDB_SUCCESS || root_res->count == 0) {
4031                 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
4032                 talloc_free(tmp_ctx);
4033                 return ret;
4034         }
4035
4036         el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
4037         if ((el == NULL) || (el->num_values < 3)) {
4038                 struct ldb_message *tmp_msg;
4039
4040                 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
4041
4042                 /* This generates a temporary list of NCs in order to let the
4043                  * provisioning work. */
4044                 tmp_msg = ldb_msg_new(tmp_ctx);
4045                 if (tmp_msg == NULL) {
4046                         talloc_free(tmp_ctx);
4047                         return ldb_oom(samdb);
4048                 }
4049                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4050                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
4051                 if (ret != LDB_SUCCESS) {
4052                         talloc_free(tmp_ctx);
4053                         return ret;
4054                 }
4055                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4056                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
4057                 if (ret != LDB_SUCCESS) {
4058                         talloc_free(tmp_ctx);
4059                         return ret;
4060                 }
4061                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4062                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
4063                 if (ret != LDB_SUCCESS) {
4064                         talloc_free(tmp_ctx);
4065                         return ret;
4066                 }
4067                 el = &tmp_msg->elements[0];
4068         }
4069
4070        nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
4071        if (!nc_dns) {
4072                talloc_free(tmp_ctx);
4073                return ldb_oom(samdb);
4074        }
4075
4076        for (i=0; i<el->num_values; i++) {
4077                nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
4078                if (nc_dns[i] == NULL) {
4079                        talloc_free(tmp_ctx);
4080                        return ldb_operr(samdb);
4081                }
4082        }
4083
4084        TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
4085
4086        for (i=0; i<el->num_values; i++) {
4087                if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
4088                        (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
4089                        talloc_free(tmp_ctx);
4090                        return LDB_SUCCESS;
4091                }
4092        }
4093
4094        talloc_free(tmp_ctx);
4095        return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4096 }
4097
4098
4099 /*
4100   find the deleted objects DN for any object, by looking for the NC
4101   root, then looking up the wellknown GUID
4102  */
4103 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
4104                                 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
4105                                 struct ldb_dn **do_dn)
4106 {
4107         struct ldb_dn *nc_root;
4108         int ret;
4109
4110         ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
4111         if (ret != LDB_SUCCESS) {
4112                 return ret;
4113         }
4114
4115         ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
4116         talloc_free(nc_root);
4117         return ret;
4118 }
4119
4120 /*
4121   return the tombstoneLifetime, in days
4122  */
4123 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
4124 {
4125         struct ldb_dn *dn;
4126         dn = ldb_get_config_basedn(ldb);
4127         if (!dn) {
4128                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4129         }
4130         dn = ldb_dn_copy(ldb, dn);
4131         if (!dn) {
4132                 return ldb_operr(ldb);
4133         }
4134         /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
4135          be a wellknown GUID for this */
4136         if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
4137                 talloc_free(dn);
4138                 return ldb_operr(ldb);
4139         }
4140
4141         *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
4142         talloc_free(dn);
4143         return LDB_SUCCESS;
4144 }
4145
4146 /*
4147   compare a ldb_val to a string case insensitively
4148  */
4149 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
4150 {
4151         size_t len = strlen(s);
4152         int ret;
4153         if (len > v->length) return 1;
4154         ret = strncasecmp(s, (const char *)v->data, v->length);
4155         if (ret != 0) return ret;
4156         if (v->length > len && v->data[len] != 0) {
4157                 return -1;
4158         }
4159         return 0;
4160 }
4161
4162
4163 /*
4164   load the UDV for a partition in v2 format
4165   The list is returned sorted, and with our local cursor added
4166  */
4167 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4168                      struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
4169 {
4170         static const char *attrs[] = { "replUpToDateVector", NULL };
4171         struct ldb_result *r;
4172         const struct ldb_val *ouv_value;
4173         unsigned int i;
4174         int ret;
4175         uint64_t highest_usn = 0;
4176         const struct GUID *our_invocation_id;
4177         static const struct timeval tv1970;
4178         NTTIME nt1970 = timeval_to_nttime(&tv1970);
4179
4180         ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
4181         if (ret != LDB_SUCCESS) {
4182                 return ret;
4183         }
4184
4185         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
4186         if (ouv_value) {
4187                 enum ndr_err_code ndr_err;
4188                 struct replUpToDateVectorBlob ouv;
4189
4190                 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
4191                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4192                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4193                         talloc_free(r);
4194                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4195                 }
4196                 if (ouv.version != 2) {
4197                         /* we always store as version 2, and
4198                          * replUpToDateVector is not replicated
4199                          */
4200                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4201                 }
4202
4203                 *count = ouv.ctr.ctr2.count;
4204                 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
4205         } else {
4206                 *count = 0;
4207                 *cursors = NULL;
4208         }
4209
4210         talloc_free(r);
4211
4212         our_invocation_id = samdb_ntds_invocation_id(samdb);
4213         if (!our_invocation_id) {
4214                 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
4215                 talloc_free(*cursors);
4216                 return ldb_operr(samdb);
4217         }
4218
4219         ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
4220         if (ret != LDB_SUCCESS) {
4221                 /* nothing to add - this can happen after a vampire */
4222                 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4223                 return LDB_SUCCESS;
4224         }
4225
4226         for (i=0; i<*count; i++) {
4227                 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
4228                         (*cursors)[i].highest_usn = highest_usn;
4229                         (*cursors)[i].last_sync_success = nt1970;
4230                         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4231                         return LDB_SUCCESS;
4232                 }
4233         }
4234
4235         (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
4236         if (! *cursors) {
4237                 return ldb_oom(samdb);
4238         }
4239
4240         (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
4241         (*cursors)[*count].highest_usn = highest_usn;
4242         (*cursors)[*count].last_sync_success = nt1970;
4243         (*count)++;
4244
4245         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4246
4247         return LDB_SUCCESS;
4248 }
4249
4250 /*
4251   load the UDV for a partition in version 1 format
4252   The list is returned sorted, and with our local cursor added
4253  */
4254 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4255                      struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
4256 {
4257         struct drsuapi_DsReplicaCursor2 *v2;
4258         uint32_t i;
4259         int ret;
4260
4261         ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
4262         if (ret != LDB_SUCCESS) {
4263                 return ret;
4264         }
4265
4266         if (*count == 0) {
4267                 talloc_free(v2);
4268                 *cursors = NULL;
4269                 return LDB_SUCCESS;
4270         }
4271
4272         *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
4273         if (*cursors == NULL) {
4274                 talloc_free(v2);
4275                 return ldb_oom(samdb);
4276         }
4277
4278         for (i=0; i<*count; i++) {
4279                 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
4280                 (*cursors)[i].highest_usn = v2[i].highest_usn;
4281         }
4282         talloc_free(v2);
4283         return LDB_SUCCESS;
4284 }
4285
4286 /*
4287   add a set of controls to a ldb_request structure based on a set of
4288   flags. See util.h for a list of available flags
4289  */
4290 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
4291 {
4292         int ret;
4293         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
4294                 struct ldb_search_options_control *options;
4295                 /* Using the phantom root control allows us to search all partitions */
4296                 options = talloc(req, struct ldb_search_options_control);
4297                 if (options == NULL) {
4298                         return LDB_ERR_OPERATIONS_ERROR;
4299                 }
4300                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4301
4302                 ret = ldb_request_add_control(req,
4303                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
4304                                               true, options);
4305                 if (ret != LDB_SUCCESS) {
4306                         return ret;
4307                 }
4308         }
4309
4310         if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
4311                 ret = ldb_request_add_control(req,
4312                                               DSDB_CONTROL_NO_GLOBAL_CATALOG,
4313                                               false, NULL);
4314                 if (ret != LDB_SUCCESS) {
4315                         return ret;
4316                 }
4317         }
4318
4319         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
4320                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
4321                 if (ret != LDB_SUCCESS) {
4322                         return ret;
4323                 }
4324         }
4325
4326         if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
4327                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
4328                 if (ret != LDB_SUCCESS) {
4329                         return ret;
4330                 }
4331         }
4332
4333         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
4334                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
4335                 if (ret != LDB_SUCCESS) {
4336                         return ret;
4337                 }
4338         }
4339
4340         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
4341                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
4342                 if (!extended_ctrl) {
4343                         return LDB_ERR_OPERATIONS_ERROR;
4344                 }
4345                 extended_ctrl->type = 1;
4346
4347                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
4348                 if (ret != LDB_SUCCESS) {
4349                         return ret;
4350                 }
4351         }
4352
4353         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
4354                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
4355                 if (ret != LDB_SUCCESS) {
4356                         return ret;
4357                 }
4358         }
4359
4360         if (dsdb_flags & DSDB_MODIFY_RELAX) {
4361                 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
4362                 if (ret != LDB_SUCCESS) {
4363                         return ret;
4364                 }
4365         }
4366
4367         if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
4368                 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
4369                 if (ret != LDB_SUCCESS) {
4370                         return ret;
4371                 }
4372         }
4373
4374         if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
4375                 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
4376                 if (ret != LDB_SUCCESS) {
4377                         return ret;
4378                 }
4379         }
4380
4381         if (dsdb_flags & DSDB_TREE_DELETE) {
4382                 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
4383                 if (ret != LDB_SUCCESS) {
4384                         return ret;
4385                 }
4386         }
4387
4388         if (dsdb_flags & DSDB_PROVISION) {
4389                 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
4390                 if (ret != LDB_SUCCESS) {
4391                         return ret;
4392                 }
4393         }
4394
4395         /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
4396         if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
4397                 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
4398                 if (ret != LDB_SUCCESS) {
4399                         return ret;
4400                 }
4401         }
4402
4403         if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
4404                 /* 
4405                  * This must not be critical, as it will only be
4406                  * handled (and need to be handled) if the other
4407                  * attributes in the request bring password_hash into
4408                  * action
4409                  */
4410                 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
4411                 if (ret != LDB_SUCCESS) {
4412                         return ret;
4413                 }
4414         }
4415
4416         if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
4417                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
4418                 if (ret != LDB_SUCCESS) {
4419                         return ret;
4420                 }
4421         }
4422
4423         if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
4424                 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
4425                 if (ret != LDB_SUCCESS) {
4426                         return ret;
4427                 }
4428         }
4429
4430         if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
4431                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4432                 if (ret != LDB_SUCCESS) {
4433                         return ret;
4434                 }
4435         }
4436
4437         return LDB_SUCCESS;
4438 }
4439
4440 /*
4441    returns true if a control with the specified "oid" exists
4442 */
4443 bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
4444 {
4445         return (ldb_request_get_control(req, oid) != NULL);
4446 }
4447
4448 /*
4449   an add with a set of controls
4450 */
4451 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
4452              uint32_t dsdb_flags)
4453 {
4454         struct ldb_request *req;
4455         int ret;
4456
4457         ret = ldb_build_add_req(&req, ldb, ldb,
4458                                 message,
4459                                 NULL,
4460                                 NULL,
4461                                 ldb_op_default_callback,
4462                                 NULL);
4463
4464         if (ret != LDB_SUCCESS) return ret;
4465
4466         ret = dsdb_request_add_controls(req, dsdb_flags);
4467         if (ret != LDB_SUCCESS) {
4468                 talloc_free(req);
4469                 return ret;
4470         }
4471
4472         ret = dsdb_autotransaction_request(ldb, req);
4473
4474         talloc_free(req);
4475         return ret;
4476 }
4477
4478 /*
4479   a modify with a set of controls
4480 */
4481 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
4482                 uint32_t dsdb_flags)
4483 {
4484         struct ldb_request *req;
4485         int ret;
4486
4487         ret = ldb_build_mod_req(&req, ldb, ldb,
4488                                 message,
4489                                 NULL,
4490                                 NULL,
4491                                 ldb_op_default_callback,
4492                                 NULL);
4493
4494         if (ret != LDB_SUCCESS) return ret;
4495
4496         ret = dsdb_request_add_controls(req, dsdb_flags);
4497         if (ret != LDB_SUCCESS) {
4498                 talloc_free(req);
4499                 return ret;
4500         }
4501
4502         ret = dsdb_autotransaction_request(ldb, req);
4503
4504         talloc_free(req);
4505         return ret;
4506 }
4507
4508 /*
4509   a delete with a set of flags
4510 */
4511 int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
4512                 uint32_t dsdb_flags)
4513 {
4514         struct ldb_request *req;
4515         int ret;
4516
4517         ret = ldb_build_del_req(&req, ldb, ldb,
4518                                 dn,
4519                                 NULL,
4520                                 NULL,
4521                                 ldb_op_default_callback,
4522                                 NULL);
4523
4524         if (ret != LDB_SUCCESS) return ret;
4525
4526         ret = dsdb_request_add_controls(req, dsdb_flags);
4527         if (ret != LDB_SUCCESS) {
4528                 talloc_free(req);
4529                 return ret;
4530         }
4531
4532         ret = dsdb_autotransaction_request(ldb, req);
4533
4534         talloc_free(req);
4535         return ret;
4536 }
4537
4538 /*
4539   like dsdb_modify() but set all the element flags to
4540   LDB_FLAG_MOD_REPLACE
4541  */
4542 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
4543 {
4544         unsigned int i;
4545
4546         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
4547         for (i=0;i<msg->num_elements;i++) {
4548                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4549         }
4550
4551         return dsdb_modify(ldb, msg, dsdb_flags);
4552 }
4553
4554
4555 /*
4556   search for attrs on one DN, allowing for dsdb_flags controls
4557  */
4558 int dsdb_search_dn(struct ldb_context *ldb,
4559                    TALLOC_CTX *mem_ctx,
4560                    struct ldb_result **_result,
4561                    struct ldb_dn *basedn,
4562                    const char * const *attrs,
4563                    uint32_t dsdb_flags)
4564 {
4565         int ret;
4566         struct ldb_request *req;
4567         struct ldb_result *res;
4568
4569         res = talloc_zero(mem_ctx, struct ldb_result);
4570         if (!res) {
4571                 return ldb_oom(ldb);
4572         }
4573
4574         ret = ldb_build_search_req(&req, ldb, res,
4575                                    basedn,
4576                                    LDB_SCOPE_BASE,
4577                                    NULL,
4578                                    attrs,
4579                                    NULL,
4580                                    res,
4581                                    ldb_search_default_callback,
4582                                    NULL);
4583         if (ret != LDB_SUCCESS) {
4584                 talloc_free(res);
4585                 return ret;
4586         }
4587
4588         ret = dsdb_request_add_controls(req, dsdb_flags);
4589         if (ret != LDB_SUCCESS) {
4590                 talloc_free(res);
4591                 return ret;
4592         }
4593
4594         ret = ldb_request(ldb, req);
4595         if (ret == LDB_SUCCESS) {
4596                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4597         }
4598
4599         talloc_free(req);
4600         if (ret != LDB_SUCCESS) {
4601                 talloc_free(res);
4602                 return ret;
4603         }
4604
4605         *_result = res;
4606         return LDB_SUCCESS;
4607 }
4608
4609 /*
4610   search for attrs on one DN, by the GUID of the DN, allowing for
4611   dsdb_flags controls
4612  */
4613 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
4614                            TALLOC_CTX *mem_ctx,
4615                            struct ldb_result **_result,
4616                            const struct GUID *guid,
4617                            const char * const *attrs,
4618                            uint32_t dsdb_flags)
4619 {
4620         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4621         struct ldb_dn *dn;
4622         int ret;
4623
4624         dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
4625         if (dn == NULL) {
4626                 talloc_free(tmp_ctx);
4627                 return ldb_oom(ldb);
4628         }
4629
4630         ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
4631         talloc_free(tmp_ctx);
4632         return ret;
4633 }
4634
4635 /*
4636   general search with dsdb_flags for controls
4637  */
4638 int dsdb_search(struct ldb_context *ldb,
4639                 TALLOC_CTX *mem_ctx,
4640                 struct ldb_result **_result,
4641                 struct ldb_dn *basedn,
4642                 enum ldb_scope scope,
4643                 const char * const *attrs,
4644                 uint32_t dsdb_flags,
4645                 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4646 {
4647         int ret;
4648         struct ldb_request *req;
4649         struct ldb_result *res;
4650         va_list ap;
4651         char *expression = NULL;
4652         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4653
4654         /* cross-partitions searches with a basedn break multi-domain support */
4655         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
4656
4657         res = talloc_zero(tmp_ctx, struct ldb_result);
4658         if (!res) {
4659                 talloc_free(tmp_ctx);
4660                 return ldb_oom(ldb);
4661         }
4662
4663         if (exp_fmt) {
4664                 va_start(ap, exp_fmt);
4665                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4666                 va_end(ap);
4667
4668                 if (!expression) {
4669                         talloc_free(tmp_ctx);
4670                         return ldb_oom(ldb);
4671                 }
4672         }
4673
4674         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
4675                                    basedn,
4676                                    scope,
4677                                    expression,
4678                                    attrs,
4679                                    NULL,
4680                                    res,
4681                                    ldb_search_default_callback,
4682                                    NULL);
4683         if (ret != LDB_SUCCESS) {
4684                 talloc_free(tmp_ctx);
4685                 return ret;
4686         }
4687
4688         ret = dsdb_request_add_controls(req, dsdb_flags);
4689         if (ret != LDB_SUCCESS) {
4690                 talloc_free(tmp_ctx);
4691                 ldb_reset_err_string(ldb);
4692                 return ret;
4693         }
4694
4695         ret = ldb_request(ldb, req);
4696         if (ret == LDB_SUCCESS) {
4697                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4698         }
4699
4700         if (ret != LDB_SUCCESS) {
4701                 talloc_free(tmp_ctx);
4702                 return ret;
4703         }
4704
4705         if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
4706                 if (res->count == 0) {
4707                         talloc_free(tmp_ctx);
4708                         ldb_reset_err_string(ldb);
4709                         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4710                 }
4711                 if (res->count != 1) {
4712                         talloc_free(tmp_ctx);
4713                         ldb_reset_err_string(ldb);
4714                         return LDB_ERR_CONSTRAINT_VIOLATION;
4715                 }
4716         }
4717
4718         *_result = talloc_steal(mem_ctx, res);
4719         talloc_free(tmp_ctx);
4720
4721         return LDB_SUCCESS;
4722 }
4723
4724
4725 /*
4726   general search with dsdb_flags for controls
4727   returns exactly 1 record or an error
4728  */
4729 int dsdb_search_one(struct ldb_context *ldb,
4730                     TALLOC_CTX *mem_ctx,
4731                     struct ldb_message **msg,
4732                     struct ldb_dn *basedn,
4733                     enum ldb_scope scope,
4734                     const char * const *attrs,
4735                     uint32_t dsdb_flags,
4736                     const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4737 {
4738         int ret;
4739         struct ldb_result *res;
4740         va_list ap;
4741         char *expression = NULL;
4742         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4743
4744         dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
4745
4746         res = talloc_zero(tmp_ctx, struct ldb_result);
4747         if (!res) {
4748                 talloc_free(tmp_ctx);
4749                 return ldb_oom(ldb);
4750         }
4751
4752         if (exp_fmt) {
4753                 va_start(ap, exp_fmt);
4754                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4755                 va_end(ap);
4756
4757                 if (!expression) {
4758                         talloc_free(tmp_ctx);
4759                         return ldb_oom(ldb);
4760                 }
4761                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4762                                   dsdb_flags, "%s", expression);
4763         } else {
4764                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4765                                   dsdb_flags, NULL);
4766         }
4767
4768         if (ret != LDB_SUCCESS) {
4769                 talloc_free(tmp_ctx);
4770                 return ret;
4771         }
4772
4773         *msg = talloc_steal(mem_ctx, res->msgs[0]);
4774         talloc_free(tmp_ctx);
4775
4776         return LDB_SUCCESS;
4777 }
4778
4779 /* returns back the forest DNS name */
4780 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4781 {
4782         const char *forest_name = ldb_dn_canonical_string(mem_ctx,
4783                                                           ldb_get_root_basedn(ldb));
4784         char *p;
4785
4786         if (forest_name == NULL) {
4787                 return NULL;
4788         }
4789
4790         p = strchr(forest_name, '/');
4791         if (p) {
4792                 *p = '\0';
4793         }
4794
4795         return forest_name;
4796 }
4797
4798 /* returns back the default domain DNS name */
4799 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4800 {
4801         const char *domain_name = ldb_dn_canonical_string(mem_ctx,
4802                                                           ldb_get_default_basedn(ldb));
4803         char *p;
4804
4805         if (domain_name == NULL) {
4806                 return NULL;
4807         }
4808
4809         p = strchr(domain_name, '/');
4810         if (p) {
4811                 *p = '\0';
4812         }
4813
4814         return domain_name;
4815 }
4816
4817 /*
4818    validate that an DSA GUID belongs to the specified user sid.
4819    The user SID must be a domain controller account (either RODC or
4820    RWDC)
4821  */
4822 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
4823                            const struct GUID *dsa_guid,
4824                            const struct dom_sid *sid)
4825 {
4826         /* strategy:
4827             - find DN of record with the DSA GUID in the
4828               configuration partition (objectGUID)
4829             - remove "NTDS Settings" component from DN
4830             - do a base search on that DN for serverReference with
4831               extended-dn enabled
4832             - extract objectSid from resulting serverReference
4833               attribute
4834             - check this sid matches the sid argument
4835         */
4836         struct ldb_dn *config_dn;
4837         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4838         struct ldb_message *msg;
4839         const char *attrs1[] = { NULL };
4840         const char *attrs2[] = { "serverReference", NULL };
4841         int ret;
4842         struct ldb_dn *dn, *account_dn;
4843         struct dom_sid sid2;
4844         NTSTATUS status;
4845
4846         config_dn = ldb_get_config_basedn(ldb);
4847
4848         ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4849                               attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4850         if (ret != LDB_SUCCESS) {
4851                 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4852                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4853                 talloc_free(tmp_ctx);
4854                 return ldb_operr(ldb);
4855         }
4856         dn = msg->dn;
4857
4858         if (!ldb_dn_remove_child_components(dn, 1)) {
4859                 talloc_free(tmp_ctx);
4860                 return ldb_operr(ldb);
4861         }
4862
4863         ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4864                               attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4865                               "(objectClass=server)");
4866         if (ret != LDB_SUCCESS) {
4867                 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4868                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4869                 talloc_free(tmp_ctx);
4870                 return ldb_operr(ldb);
4871         }
4872
4873         account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4874         if (account_dn == NULL) {
4875                 DEBUG(1,(__location__ ": Failed to find account dn "
4876                          "(serverReference) for %s, parent of DSA with "
4877                          "objectGUID %s, sid %s\n",
4878                          ldb_dn_get_linearized(msg->dn),
4879                          GUID_string(tmp_ctx, dsa_guid),
4880                          dom_sid_string(tmp_ctx, sid)));
4881                 talloc_free(tmp_ctx);
4882                 return ldb_operr(ldb);
4883         }
4884
4885         status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4886         if (!NT_STATUS_IS_OK(status)) {
4887                 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4888                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4889                 talloc_free(tmp_ctx);
4890                 return ldb_operr(ldb);
4891         }
4892
4893         if (!dom_sid_equal(sid, &sid2)) {
4894                 /* someone is trying to spoof another account */
4895                 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4896                          GUID_string(tmp_ctx, dsa_guid),
4897                          dom_sid_string(tmp_ctx, sid),
4898                          dom_sid_string(tmp_ctx, &sid2)));
4899                 talloc_free(tmp_ctx);
4900                 return ldb_operr(ldb);
4901         }
4902
4903         talloc_free(tmp_ctx);
4904         return LDB_SUCCESS;
4905 }
4906
4907 static const char * const secret_attributes[] = {
4908         DSDB_SECRET_ATTRIBUTES,
4909         NULL
4910 };
4911
4912 /*
4913   check if the attribute belongs to the RODC filtered attribute set
4914   Note that attributes that are in the filtered attribute set are the
4915   ones that _are_ always sent to a RODC
4916 */
4917 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4918 {
4919         /* they never get secret attributes */
4920         if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4921                 return false;
4922         }
4923
4924         /* they do get non-secret critical attributes */
4925         if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4926                 return true;
4927         }
4928
4929         /* they do get non-secret attributes marked as being in the FAS  */
4930         if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4931                 return true;
4932         }
4933
4934         /* other attributes are denied */
4935         return false;
4936 }
4937
4938 /* return fsmo role dn and role owner dn for a particular role*/
4939 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4940                                struct ldb_context *ldb,
4941                                uint32_t role,
4942                                struct ldb_dn **fsmo_role_dn,
4943                                struct ldb_dn **role_owner_dn)
4944 {
4945         int ret;
4946         switch (role) {
4947         case DREPL_NAMING_MASTER:
4948                 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4949                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4950                 if (ret != LDB_SUCCESS) {
4951                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4952                                  ldb_errstring(ldb)));
4953                         talloc_free(tmp_ctx);
4954                         return WERR_DS_DRA_INTERNAL_ERROR;
4955                 }
4956                 break;
4957         case DREPL_INFRASTRUCTURE_MASTER:
4958                 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4959                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4960                 if (ret != LDB_SUCCESS) {
4961                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4962                                  ldb_errstring(ldb)));
4963                         talloc_free(tmp_ctx);
4964                         return WERR_DS_DRA_INTERNAL_ERROR;
4965                 }
4966                 break;
4967         case DREPL_RID_MASTER:
4968                 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4969                 if (ret != LDB_SUCCESS) {
4970                         DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4971                         talloc_free(tmp_ctx);
4972                         return WERR_DS_DRA_INTERNAL_ERROR;
4973                 }
4974
4975                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4976                 if (ret != LDB_SUCCESS) {
4977                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4978                                  ldb_errstring(ldb)));
4979                         talloc_free(tmp_ctx);
4980                         return WERR_DS_DRA_INTERNAL_ERROR;
4981                 }
4982                 break;
4983         case DREPL_SCHEMA_MASTER:
4984                 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4985                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4986                 if (ret != LDB_SUCCESS) {
4987                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4988                                  ldb_errstring(ldb)));
4989                         talloc_free(tmp_ctx);
4990                         return WERR_DS_DRA_INTERNAL_ERROR;
4991                 }
4992                 break;
4993         case DREPL_PDC_MASTER:
4994                 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4995                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4996                 if (ret != LDB_SUCCESS) {
4997                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4998                                  ldb_errstring(ldb)));
4999                         talloc_free(tmp_ctx);
5000                         return WERR_DS_DRA_INTERNAL_ERROR;
5001                 }
5002                 break;
5003         default:
5004                 return WERR_DS_DRA_INTERNAL_ERROR;
5005         }
5006         return WERR_OK;
5007 }
5008
5009 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
5010                                     TALLOC_CTX *mem_ctx,
5011                                     struct ldb_dn *server_dn)
5012 {
5013         int ldb_ret;
5014         struct ldb_result *res = NULL;
5015         const char * const attrs[] = { "dNSHostName", NULL};
5016
5017         ldb_ret = ldb_search(ldb, mem_ctx, &res,
5018                              server_dn,
5019                              LDB_SCOPE_BASE,
5020                              attrs, NULL);
5021         if (ldb_ret != LDB_SUCCESS) {
5022                 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
5023                           ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
5024                 return NULL;
5025         }
5026
5027         return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
5028 }
5029
5030 /*
5031   returns true if an attribute is in the filter,
5032   false otherwise, provided that attribute value is provided with the expression
5033 */
5034 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
5035                              const char *attr)
5036 {
5037        unsigned int i;
5038        switch (tree->operation) {
5039        case LDB_OP_AND:
5040        case LDB_OP_OR:
5041                for (i=0;i<tree->u.list.num_elements;i++) {
5042                        if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
5043                                                        attr))
5044                                return true;
5045                }
5046                return false;
5047        case LDB_OP_NOT:
5048                return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
5049        case LDB_OP_EQUALITY:
5050        case LDB_OP_GREATER:
5051        case LDB_OP_LESS:
5052        case LDB_OP_APPROX:
5053                if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
5054                        return true;
5055                }
5056                return false;
5057        case LDB_OP_SUBSTRING:
5058                if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
5059                        return true;
5060                }
5061                return false;
5062        case LDB_OP_PRESENT:
5063                /* (attrname=*) is not filtered out */
5064                return false;
5065        case LDB_OP_EXTENDED:
5066                if (tree->u.extended.attr &&
5067                    ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
5068                        return true;
5069                }
5070                return false;
5071        }
5072        return false;
5073 }
5074
5075 bool is_attr_in_list(const char * const * attrs, const char *attr)
5076 {
5077         unsigned int i;
5078
5079         for (i = 0; attrs[i]; i++) {
5080                 if (ldb_attr_cmp(attrs[i], attr) == 0)
5081                         return true;
5082         }
5083
5084         return false;
5085 }
5086
5087 int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
5088                    const char *location, const char *func,
5089                    const char *reason)
5090 {
5091         if (reason == NULL) {
5092                 reason = win_errstr(werr);
5093         }
5094         ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
5095                                W_ERROR_V(werr), reason, location, func);
5096         return ldb_ecode;
5097 }
5098
5099 /*
5100   map an ldb error code to an approximate NTSTATUS code
5101  */
5102 NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
5103 {
5104         switch (err) {
5105         case LDB_SUCCESS:
5106                 return NT_STATUS_OK;
5107
5108         case LDB_ERR_PROTOCOL_ERROR:
5109                 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
5110
5111         case LDB_ERR_TIME_LIMIT_EXCEEDED:
5112                 return NT_STATUS_IO_TIMEOUT;
5113
5114         case LDB_ERR_SIZE_LIMIT_EXCEEDED:
5115                 return NT_STATUS_BUFFER_TOO_SMALL;
5116
5117         case LDB_ERR_COMPARE_FALSE:
5118         case LDB_ERR_COMPARE_TRUE:
5119                 return NT_STATUS_REVISION_MISMATCH;
5120
5121         case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
5122                 return NT_STATUS_NOT_SUPPORTED;
5123
5124         case LDB_ERR_STRONG_AUTH_REQUIRED:
5125         case LDB_ERR_CONFIDENTIALITY_REQUIRED:
5126         case LDB_ERR_SASL_BIND_IN_PROGRESS:
5127         case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
5128         case LDB_ERR_INVALID_CREDENTIALS:
5129         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
5130         case LDB_ERR_UNWILLING_TO_PERFORM:
5131                 return NT_STATUS_ACCESS_DENIED;
5132
5133         case LDB_ERR_NO_SUCH_OBJECT:
5134                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5135
5136         case LDB_ERR_REFERRAL:
5137         case LDB_ERR_NO_SUCH_ATTRIBUTE:
5138                 return NT_STATUS_NOT_FOUND;
5139
5140         case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
5141                 return NT_STATUS_NOT_SUPPORTED;
5142
5143         case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
5144                 return NT_STATUS_BUFFER_TOO_SMALL;
5145
5146         case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
5147         case LDB_ERR_INAPPROPRIATE_MATCHING:
5148         case LDB_ERR_CONSTRAINT_VIOLATION:
5149         case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
5150         case LDB_ERR_INVALID_DN_SYNTAX:
5151         case LDB_ERR_NAMING_VIOLATION:
5152         case LDB_ERR_OBJECT_CLASS_VIOLATION:
5153         case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
5154         case LDB_ERR_NOT_ALLOWED_ON_RDN:
5155                 return NT_STATUS_INVALID_PARAMETER;
5156
5157         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
5158         case LDB_ERR_ENTRY_ALREADY_EXISTS:
5159                 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
5160
5161         case LDB_ERR_BUSY:
5162                 return NT_STATUS_NETWORK_BUSY;
5163
5164         case LDB_ERR_ALIAS_PROBLEM:
5165         case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
5166         case LDB_ERR_UNAVAILABLE:
5167         case LDB_ERR_LOOP_DETECT:
5168         case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
5169         case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
5170         case LDB_ERR_OTHER:
5171         case LDB_ERR_OPERATIONS_ERROR:
5172                 break;
5173         }
5174         return NT_STATUS_UNSUCCESSFUL;
5175 }
5176
5177
5178 /*
5179   create a new naming context that will hold a partial replica
5180  */
5181 int dsdb_create_partial_replica_NC(struct ldb_context *ldb,  struct ldb_dn *dn)
5182 {
5183         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5184         struct ldb_message *msg;
5185         int ret;
5186
5187         msg = ldb_msg_new(tmp_ctx);
5188         if (msg == NULL) {
5189                 talloc_free(tmp_ctx);
5190                 return ldb_oom(ldb);
5191         }
5192
5193         msg->dn = dn;
5194         ret = ldb_msg_add_string(msg, "objectClass", "top");
5195         if (ret != LDB_SUCCESS) {
5196                 talloc_free(tmp_ctx);
5197                 return ldb_oom(ldb);
5198         }
5199
5200         /* [MS-DRSR] implies that we should only add the 'top'
5201          * objectclass, but that would cause lots of problems with our
5202          * objectclass code as top is not structural, so we add
5203          * 'domainDNS' as well to keep things sane. We're expecting
5204          * this new NC to be of objectclass domainDNS after
5205          * replication anyway
5206          */
5207         ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
5208         if (ret != LDB_SUCCESS) {
5209                 talloc_free(tmp_ctx);
5210                 return ldb_oom(ldb);
5211         }
5212
5213         ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
5214                               INSTANCE_TYPE_IS_NC_HEAD|
5215                               INSTANCE_TYPE_NC_ABOVE|
5216                               INSTANCE_TYPE_UNINSTANT);
5217         if (ret != LDB_SUCCESS) {
5218                 talloc_free(tmp_ctx);
5219                 return ldb_oom(ldb);
5220         }
5221
5222         ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
5223         if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5224                 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
5225                          ldb_dn_get_linearized(dn),
5226                          ldb_errstring(ldb), ldb_strerror(ret)));
5227                 talloc_free(tmp_ctx);
5228                 return ret;
5229         }
5230
5231         DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
5232
5233         talloc_free(tmp_ctx);
5234         return LDB_SUCCESS;
5235 }
5236
5237 /**
5238   build a GUID from a string
5239 */
5240 _PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid)
5241 {
5242         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
5243         uint32_t time_low;
5244         uint32_t time_mid, time_hi_and_version;
5245         uint32_t clock_seq[2];
5246         uint32_t node[6];
5247         int i;
5248
5249         if (s == NULL) {
5250                 return NT_STATUS_INVALID_PARAMETER;
5251         }
5252
5253         status =  parse_guid_string(s,
5254                                     &time_low,
5255                                     &time_mid,
5256                                     &time_hi_and_version,
5257                                     clock_seq,
5258                                     node);
5259
5260         if (!NT_STATUS_IS_OK(status)) {
5261                 return status;
5262         }
5263
5264         guid->time_low = time_low;
5265         guid->time_mid = time_mid;
5266         guid->time_hi_and_version = time_hi_and_version;
5267         guid->clock_seq[0] = clock_seq[0];
5268         guid->clock_seq[1] = clock_seq[1];
5269         for (i=0;i<6;i++) {
5270                 guid->node[i] = node[i];
5271         }
5272
5273         return NT_STATUS_OK;
5274 }
5275
5276 _PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
5277 {
5278         return talloc_asprintf(mem_ctx, 
5279                                "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
5280                                guid->time_low, guid->time_mid,
5281                                guid->time_hi_and_version,
5282                                guid->clock_seq[0],
5283                                guid->clock_seq[1],
5284                                guid->node[0], guid->node[1],
5285                                guid->node[2], guid->node[3],
5286                                guid->node[4], guid->node[5]);
5287 }
5288
5289 /*
5290  * Return the effective badPwdCount
5291  *
5292  * This requires that the user_msg have (if present):
5293  *  - badPasswordTime
5294  *  - badPwdCount
5295  *
5296  * This also requires that the domain_msg have (if present):
5297  *  - lockOutObservationWindow
5298  */
5299 static int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
5300                                       int64_t lockOutObservationWindow,
5301                                       NTTIME now)
5302 {
5303         int64_t badPasswordTime;
5304         badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
5305
5306         if (badPasswordTime - lockOutObservationWindow >= now) {
5307                 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
5308         } else {
5309                 return 0;
5310         }
5311 }
5312
5313 /*
5314  * Returns a user's PSO, or NULL if none was found
5315  */
5316 static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
5317                                           TALLOC_CTX *mem_ctx,
5318                                           const struct ldb_message *user_msg,
5319                                           const char * const *attrs)
5320 {
5321         struct ldb_result *res = NULL;
5322         struct ldb_dn *pso_dn = NULL;
5323         int ret;
5324
5325         /* if the user has a PSO that applies, then use the PSO's setting */
5326         pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
5327                                          "msDS-ResultantPSO");
5328
5329         if (pso_dn != NULL) {
5330
5331                 ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
5332                 if (ret != LDB_SUCCESS) {
5333
5334                         /*
5335                          * log the error. The caller should fallback to using
5336                          * the default domain password settings
5337                          */
5338                         DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s",
5339                                 ldb_dn_get_linearized(pso_dn),
5340                                 ldb_dn_get_linearized(user_msg->dn));
5341                 }
5342                 talloc_free(pso_dn);
5343         }
5344         return res;
5345 }
5346
5347 /*
5348  * Return the effective badPwdCount
5349  *
5350  * This requires that the user_msg have (if present):
5351  *  - badPasswordTime
5352  *  - badPwdCount
5353  *  - msDS-ResultantPSO
5354  */
5355 int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
5356                                        TALLOC_CTX *mem_ctx,
5357                                        struct ldb_dn *domain_dn,
5358                                        const struct ldb_message *user_msg)
5359 {
5360         struct timeval tv_now = timeval_current();
5361         NTTIME now = timeval_to_nttime(&tv_now);
5362         int64_t lockOutObservationWindow;
5363         struct ldb_result *res = NULL;
5364         const char *attrs[] = { "msDS-LockoutObservationWindow",
5365                                 NULL };
5366
5367         res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
5368
5369         if (res != NULL) {
5370                 lockOutObservationWindow =
5371                         ldb_msg_find_attr_as_int(res->msgs[0],
5372                                                  "msDS-LockoutObservationWindow",
5373                                                   0);
5374                 talloc_free(res);
5375         } else {
5376
5377                 /* no PSO was found, lookup the default domain setting */
5378                 lockOutObservationWindow =
5379                          samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
5380                                             "lockOutObservationWindow", NULL);
5381         }
5382
5383         return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5384 }
5385
5386 /*
5387  * Returns the lockoutThreshold that applies. If a PSO is specified, then that
5388  * setting is used over the domain defaults
5389  */
5390 static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
5391                                      struct ldb_message *pso_msg)
5392 {
5393         if (pso_msg != NULL) {
5394                 return ldb_msg_find_attr_as_int(pso_msg,
5395                                                 "msDS-LockoutThreshold", 0);
5396         } else {
5397                 return ldb_msg_find_attr_as_int(domain_msg,
5398                                                 "lockoutThreshold", 0);
5399         }
5400 }
5401
5402 /*
5403  * Returns the lockOutObservationWindow that applies. If a PSO is specified,
5404  * then that setting is used over the domain defaults
5405  */
5406 static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
5407                                               struct ldb_message *pso_msg)
5408 {
5409         if (pso_msg != NULL) {
5410                 return ldb_msg_find_attr_as_int64(pso_msg,
5411                                                   "msDS-LockoutObservationWindow",
5412                                                    0);
5413         } else {
5414                 return ldb_msg_find_attr_as_int64(domain_msg,
5415                                                   "lockOutObservationWindow", 0);
5416         }
5417 }
5418
5419 /*
5420  * Prepare an update to the badPwdCount and associated attributes.
5421  *
5422  * This requires that the user_msg have (if present):
5423  *  - objectSid
5424  *  - badPasswordTime
5425  *  - badPwdCount
5426  *
5427  * This also requires that the domain_msg have (if present):
5428  *  - pwdProperties
5429  *  - lockoutThreshold
5430  *  - lockOutObservationWindow
5431  *
5432  * This also requires that the pso_msg have (if present):
5433  *  - msDS-LockoutThreshold
5434  *  - msDS-LockoutObservationWindow
5435  */
5436 NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
5437                                    struct ldb_context *sam_ctx,
5438                                    struct ldb_message *user_msg,
5439                                    struct ldb_message *domain_msg,
5440                                    struct ldb_message *pso_msg,
5441                                    struct ldb_message **_mod_msg)
5442 {
5443         int i, ret, badPwdCount;
5444         int64_t lockoutThreshold, lockOutObservationWindow;
5445         struct dom_sid *sid;
5446         struct timeval tv_now = timeval_current();
5447         NTTIME now = timeval_to_nttime(&tv_now);
5448         NTSTATUS status;
5449         uint32_t pwdProperties, rid = 0;
5450         struct ldb_message *mod_msg;
5451
5452         sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
5453
5454         pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
5455                                                   "pwdProperties", -1);
5456         if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
5457                 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
5458                 if (!NT_STATUS_IS_OK(status)) {
5459                         /*
5460                          * This can't happen anyway, but always try
5461                          * and update the badPwdCount on failure
5462                          */
5463                         rid = 0;
5464                 }
5465         }
5466         TALLOC_FREE(sid);
5467
5468         /*
5469          * Work out if we are doing password lockout on the domain.
5470          * Also, the built in administrator account is exempt:
5471          * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
5472          */
5473         lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
5474         if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
5475                 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
5476                           ldb_dn_get_linearized(user_msg->dn)));
5477                 return NT_STATUS_OK;
5478         }
5479
5480         mod_msg = ldb_msg_new(mem_ctx);
5481         if (mod_msg == NULL) {
5482                 return NT_STATUS_NO_MEMORY;
5483         }
5484         mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
5485         if (mod_msg->dn == NULL) {
5486                 TALLOC_FREE(mod_msg);
5487                 return NT_STATUS_NO_MEMORY;
5488         }
5489
5490         lockOutObservationWindow = get_lockout_observation_window(domain_msg,
5491                                                                   pso_msg);
5492
5493         badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5494
5495         badPwdCount++;
5496
5497         ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
5498         if (ret != LDB_SUCCESS) {
5499                 TALLOC_FREE(mod_msg);
5500                 return NT_STATUS_NO_MEMORY;
5501         }
5502         ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
5503         if (ret != LDB_SUCCESS) {
5504                 TALLOC_FREE(mod_msg);
5505                 return NT_STATUS_NO_MEMORY;
5506         }
5507
5508         if (badPwdCount >= lockoutThreshold) {
5509                 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
5510                 if (ret != LDB_SUCCESS) {
5511                         TALLOC_FREE(mod_msg);
5512                         return NT_STATUS_NO_MEMORY;
5513                 }
5514                 DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
5515                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5516         } else {
5517                 DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
5518                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5519         }
5520
5521         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5522         for (i=0; i< mod_msg->num_elements; i++) {
5523                 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5524         }
5525
5526         *_mod_msg = mod_msg;
5527         return NT_STATUS_OK;
5528 }
5529
5530 /**
5531  * Sets defaults for a User object
5532  * List of default attributes set:
5533  *      accountExpires, badPasswordTime, badPwdCount,
5534  *      codePage, countryCode, lastLogoff, lastLogon
5535  *      logonCount, pwdLastSet
5536  */
5537 int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
5538                                struct ldb_message *usr_obj,
5539                                struct ldb_request *req)
5540 {
5541         int i, ret;
5542         const struct attribute_values {
5543                 const char *name;
5544                 const char *value;
5545                 const char *add_value;
5546                 const char *mod_value;
5547                 const char *control;
5548                 unsigned add_flags;
5549                 unsigned mod_flags;
5550         } map[] = {
5551                 {
5552                         .name = "accountExpires",
5553                         .add_value = "9223372036854775807",
5554                         .mod_value = "0",
5555                 },
5556                 {
5557                         .name = "badPasswordTime",
5558                         .value = "0"
5559                 },
5560                 {
5561                         .name = "badPwdCount",
5562                         .value = "0"
5563                 },
5564                 {
5565                         .name = "codePage",
5566                         .value = "0"
5567                 },
5568                 {
5569                         .name = "countryCode",
5570                         .value = "0"
5571                 },
5572                 {
5573                         .name = "lastLogoff",
5574                         .value = "0"
5575                 },
5576                 {
5577                         .name = "lastLogon",
5578                         .value = "0"
5579                 },
5580                 {
5581                         .name = "logonCount",
5582                         .value = "0"
5583                 },
5584                 {
5585                         .name = "logonHours",
5586                         .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
5587                 },
5588                 {
5589                         .name = "pwdLastSet",
5590                         .value = "0",
5591                         .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
5592                 },
5593                 {
5594                         .name = "adminCount",
5595                         .mod_value = "0",
5596                 },
5597                 {
5598                         .name = "operatorCount",
5599                         .mod_value = "0",
5600                 },
5601         };
5602
5603         for (i = 0; i < ARRAY_SIZE(map); i++) {
5604                 bool added = false;
5605                 const char *value = NULL;
5606                 unsigned flags = 0;
5607
5608                 if (req != NULL && req->operation == LDB_ADD) {
5609                         value = map[i].add_value;
5610                         flags = map[i].add_flags;
5611                 } else {
5612                         value = map[i].mod_value;
5613                         flags = map[i].mod_flags;
5614                 }
5615
5616                 if (value == NULL) {
5617                         value = map[i].value;
5618                 }
5619
5620                 if (value != NULL) {
5621                         flags |= LDB_FLAG_MOD_ADD;
5622                 }
5623
5624                 if (flags == 0) {
5625                         continue;
5626                 }
5627
5628                 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
5629                                                      map[i].name,
5630                                                      value, flags,
5631                                                      &added);
5632                 if (ret != LDB_SUCCESS) {
5633                         return ret;
5634                 }
5635
5636                 if (req != NULL && added && map[i].control != NULL) {
5637                         ret = ldb_request_add_control(req,
5638                                                       map[i].control,
5639                                                       false, NULL);
5640                         if (ret != LDB_SUCCESS) {
5641                                 return ret;
5642                         }
5643                 }
5644         }
5645
5646         return LDB_SUCCESS;
5647 }
5648
5649 /**
5650  * Sets 'sAMAccountType on user object based on userAccountControl
5651  * @param ldb Current ldb_context
5652  * @param usr_obj ldb_message representing User object
5653  * @param user_account_control Value for userAccountControl flags
5654  * @param account_type_p Optional pointer to account_type to return
5655  * @return LDB_SUCCESS or LDB_ERR* code on failure
5656  */
5657 int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
5658                                    uint32_t user_account_control, uint32_t *account_type_p)
5659 {
5660         int ret;
5661         uint32_t account_type;
5662         struct ldb_message_element *el;
5663
5664         account_type = ds_uf2atype(user_account_control);
5665         if (account_type == 0) {
5666                 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
5667                 return LDB_ERR_UNWILLING_TO_PERFORM;
5668         }
5669         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5670                                  "sAMAccountType",
5671                                  account_type);
5672         if (ret != LDB_SUCCESS) {
5673                 return ret;
5674         }
5675         el = ldb_msg_find_element(usr_obj, "sAMAccountType");
5676         el->flags = LDB_FLAG_MOD_REPLACE;
5677
5678         if (account_type_p) {
5679                 *account_type_p = account_type;
5680         }
5681
5682         return LDB_SUCCESS;
5683 }
5684
5685 /**
5686  * Determine and set primaryGroupID based on userAccountControl value
5687  * @param ldb Current ldb_context
5688  * @param usr_obj ldb_message representing User object
5689  * @param user_account_control Value for userAccountControl flags
5690  * @param group_rid_p Optional pointer to group RID to return
5691  * @return LDB_SUCCESS or LDB_ERR* code on failure
5692  */
5693 int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
5694                                        uint32_t user_account_control, uint32_t *group_rid_p)
5695 {
5696         int ret;
5697         uint32_t rid;
5698         struct ldb_message_element *el;
5699
5700         rid = ds_uf2prim_group_rid(user_account_control);
5701
5702         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5703                                  "primaryGroupID", rid);
5704         if (ret != LDB_SUCCESS) {
5705                 return ret;
5706         }
5707         el = ldb_msg_find_element(usr_obj, "primaryGroupID");
5708         el->flags = LDB_FLAG_MOD_REPLACE;
5709
5710         if (group_rid_p) {
5711                 *group_rid_p = rid;
5712         }
5713
5714         return LDB_SUCCESS;
5715 }
5716
5717 /**
5718  * Returns True if the source and target DNs both have the same naming context,
5719  * i.e. they're both in the same partition.
5720  */
5721 bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
5722                                TALLOC_CTX *mem_ctx,
5723                                struct ldb_dn *source_dn,
5724                                struct ldb_dn *target_dn)
5725 {
5726         TALLOC_CTX *tmp_ctx;
5727         struct ldb_dn *source_nc;
5728         struct ldb_dn *target_nc;
5729         int ret;
5730         bool same_nc = true;
5731
5732         tmp_ctx = talloc_new(mem_ctx);
5733
5734         ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
5735         if (ret != LDB_SUCCESS) {
5736                 DBG_ERR("Failed to find base DN for source %s\n",
5737                         ldb_dn_get_linearized(source_dn));
5738                 talloc_free(tmp_ctx);
5739                 return true;
5740         }
5741
5742         ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
5743         if (ret != LDB_SUCCESS) {
5744                 DBG_ERR("Failed to find base DN for target %s\n",
5745                         ldb_dn_get_linearized(target_dn));
5746                 talloc_free(tmp_ctx);
5747                 return true;
5748         }
5749
5750         same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
5751
5752         talloc_free(tmp_ctx);
5753
5754         return same_nc;
5755 }