dsdb: Add dsdb_request_has_control() helper function
[gd/samba-autobuild/.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                 } else {
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
2169                 TALLOC_FREE(password_script);
2170                 return SAMR_VALIDATION_STATUS_SUCCESS;
2171         }
2172
2173         TALLOC_FREE(password_script);
2174
2175         /*
2176          * Here are the standard AD password quality rules, which we
2177          * run after the script.
2178          */
2179
2180         if (!check_password_quality(utf8_pw)) {
2181                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2182         }
2183
2184         return SAMR_VALIDATION_STATUS_SUCCESS;
2185 }
2186
2187 /*
2188  * Callback for "samdb_set_password" password change
2189  */
2190 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2191 {
2192         int ret;
2193
2194         if (!ares) {
2195                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2196         }
2197
2198         if (ares->error != LDB_SUCCESS) {
2199                 ret = ares->error;
2200                 req->context = talloc_steal(req,
2201                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2202                 talloc_free(ares);
2203                 return ldb_request_done(req, ret);
2204         }
2205
2206         if (ares->type != LDB_REPLY_DONE) {
2207                 talloc_free(ares);
2208                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2209         }
2210
2211         req->context = talloc_steal(req,
2212                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2213         talloc_free(ares);
2214         return ldb_request_done(req, LDB_SUCCESS);
2215 }
2216
2217 /*
2218  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2219  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2220  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2221  * user change or not. The "rejectReason" gives some more information if the
2222  * change failed.
2223  *
2224  * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2225  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
2226  */
2227 static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2228                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2229                             const DATA_BLOB *new_password,
2230                             const struct samr_Password *lmNewHash,
2231                             const struct samr_Password *ntNewHash,
2232                             const struct samr_Password *lmOldHash,
2233                             const struct samr_Password *ntOldHash,
2234                             enum samPwdChangeReason *reject_reason,
2235                             struct samr_DomInfo1 **_dominfo,
2236                             bool permit_interdomain_trust)
2237 {
2238         struct ldb_message *msg;
2239         struct ldb_message_element *el;
2240         struct ldb_request *req;
2241         struct dsdb_control_password_change_status *pwd_stat = NULL;
2242         int ret;
2243         bool hash_values = false;
2244         NTSTATUS status = NT_STATUS_OK;
2245
2246 #define CHECK_RET(x) \
2247         if (x != LDB_SUCCESS) { \
2248                 talloc_free(msg); \
2249                 return NT_STATUS_NO_MEMORY; \
2250         }
2251
2252         msg = ldb_msg_new(mem_ctx);
2253         if (msg == NULL) {
2254                 return NT_STATUS_NO_MEMORY;
2255         }
2256         msg->dn = user_dn;
2257         if ((new_password != NULL)
2258                         && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
2259                 /* we have the password as plaintext UTF16 */
2260                 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2261                                             new_password, NULL));
2262                 el = ldb_msg_find_element(msg, "clearTextPassword");
2263                 el->flags = LDB_FLAG_MOD_REPLACE;
2264         } else if ((new_password == NULL)
2265                         && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
2266                 /* we have a password as LM and/or NT hash */
2267                 if (lmNewHash != NULL) {
2268                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2269                                 "dBCSPwd", lmNewHash));
2270                         el = ldb_msg_find_element(msg, "dBCSPwd");
2271                         el->flags = LDB_FLAG_MOD_REPLACE;
2272                 }
2273                 if (ntNewHash != NULL) {
2274                         CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
2275                                 "unicodePwd", ntNewHash));
2276                         el = ldb_msg_find_element(msg, "unicodePwd");
2277                         el->flags = LDB_FLAG_MOD_REPLACE;
2278                 }
2279                 hash_values = true;
2280         } else {
2281                 /* the password wasn't specified correctly */
2282                 talloc_free(msg);
2283                 return NT_STATUS_INVALID_PARAMETER;
2284         }
2285
2286         /* build modify request */
2287         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2288                                 samdb_set_password_callback, NULL);
2289         if (ret != LDB_SUCCESS) {
2290                 talloc_free(msg);
2291                 return NT_STATUS_NO_MEMORY;
2292         }
2293
2294         /* A password change operation */
2295         if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
2296                 struct dsdb_control_password_change *change;
2297
2298                 change = talloc(req, struct dsdb_control_password_change);
2299                 if (change == NULL) {
2300                         talloc_free(req);
2301                         talloc_free(msg);
2302                         return NT_STATUS_NO_MEMORY;
2303                 }
2304
2305                 change->old_nt_pwd_hash = ntOldHash;
2306                 change->old_lm_pwd_hash = lmOldHash;
2307
2308                 ret = ldb_request_add_control(req,
2309                                               DSDB_CONTROL_PASSWORD_CHANGE_OID,
2310                                               true, change);
2311                 if (ret != LDB_SUCCESS) {
2312                         talloc_free(req);
2313                         talloc_free(msg);
2314                         return NT_STATUS_NO_MEMORY;
2315                 }
2316         }
2317         if (hash_values) {
2318                 ret = ldb_request_add_control(req,
2319                                               DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2320                                               true, NULL);
2321                 if (ret != LDB_SUCCESS) {
2322                         talloc_free(req);
2323                         talloc_free(msg);
2324                         return NT_STATUS_NO_MEMORY;
2325                 }
2326         }
2327         if (permit_interdomain_trust) {
2328                 ret = ldb_request_add_control(req,
2329                                               DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2330                                               false, NULL);
2331                 if (ret != LDB_SUCCESS) {
2332                         talloc_free(req);
2333                         talloc_free(msg);
2334                         return NT_STATUS_NO_MEMORY;
2335                 }
2336         }
2337         ret = ldb_request_add_control(req,
2338                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2339                                       true, NULL);
2340         if (ret != LDB_SUCCESS) {
2341                 talloc_free(req);
2342                 talloc_free(msg);
2343                 return NT_STATUS_NO_MEMORY;
2344         }
2345
2346         ret = dsdb_autotransaction_request(ldb, req);
2347
2348         if (req->context != NULL) {
2349                 struct ldb_control *control = talloc_get_type_abort(req->context,
2350                                                                     struct ldb_control);
2351                 pwd_stat = talloc_get_type_abort(control->data,
2352                                                  struct dsdb_control_password_change_status);
2353                 talloc_steal(mem_ctx, pwd_stat);
2354         }
2355
2356         talloc_free(req);
2357         talloc_free(msg);
2358
2359         /* Sets the domain info (if requested) */
2360         if (_dominfo != NULL) {
2361                 struct samr_DomInfo1 *dominfo;
2362
2363                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2364                 if (dominfo == NULL) {
2365                         return NT_STATUS_NO_MEMORY;
2366                 }
2367
2368                 if (pwd_stat != NULL) {
2369                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
2370                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
2371                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2372                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
2373                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
2374                 }
2375
2376                 *_dominfo = dominfo;
2377         }
2378
2379         if (reject_reason != NULL) {
2380                 if (pwd_stat != NULL) {
2381                         *reject_reason = pwd_stat->reject_reason;
2382                 } else {
2383                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2384                 }
2385         }
2386
2387         if (pwd_stat != NULL) {
2388                 talloc_free(pwd_stat);
2389         }
2390
2391         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2392                 const char *errmsg = ldb_errstring(ldb);
2393                 char *endptr = NULL;
2394                 WERROR werr = WERR_GEN_FAILURE;
2395                 status = NT_STATUS_UNSUCCESSFUL;
2396                 if (errmsg != NULL) {
2397                         werr = W_ERROR(strtol(errmsg, &endptr, 16));
2398                         DBG_WARNING("%s\n", errmsg);
2399                 }
2400                 if (endptr != errmsg) {
2401                         if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2402                                 status = NT_STATUS_WRONG_PASSWORD;
2403                         }
2404                         if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2405                                 status = NT_STATUS_PASSWORD_RESTRICTION;
2406                         }
2407                 }
2408         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2409                 /* don't let the caller know if an account doesn't exist */
2410                 status = NT_STATUS_WRONG_PASSWORD;
2411         } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2412                 status = NT_STATUS_ACCESS_DENIED;
2413         } else if (ret != LDB_SUCCESS) {
2414                 DEBUG(1, ("Failed to set password on %s: %s\n",
2415                           ldb_dn_get_linearized(user_dn),
2416                           ldb_errstring(ldb)));
2417                 status = NT_STATUS_UNSUCCESSFUL;
2418         }
2419
2420         return status;
2421 }
2422
2423 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2424                             struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
2425                             const DATA_BLOB *new_password,
2426                             const struct samr_Password *lmNewHash,
2427                             const struct samr_Password *ntNewHash,
2428                             const struct samr_Password *lmOldHash,
2429                             const struct samr_Password *ntOldHash,
2430                             enum samPwdChangeReason *reject_reason,
2431                             struct samr_DomInfo1 **_dominfo)
2432 {
2433         return samdb_set_password_internal(ldb, mem_ctx,
2434                             user_dn, domain_dn,
2435                             new_password,
2436                             lmNewHash, ntNewHash,
2437                             lmOldHash, ntOldHash,
2438                             reject_reason, _dominfo,
2439                             false); /* reject trusts */
2440 }
2441
2442 /*
2443  * Sets the user password using plaintext UTF16 (attribute "new_password") or
2444  * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
2445  * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
2446  * user change or not. The "rejectReason" gives some more information if the
2447  * change failed.
2448  *
2449  * This wrapper function for "samdb_set_password" takes a SID as input rather
2450  * than a user DN.
2451  *
2452  * This call encapsulates a new LDB transaction for changing the password;
2453  * therefore the user hasn't to start a new one.
2454  *
2455  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2456  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2457  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2458  *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2459  */
2460 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2461                                 const struct dom_sid *user_sid,
2462                                 const uint32_t *new_version, /* optional for trusts */
2463                                 const DATA_BLOB *new_password,
2464                                 const struct samr_Password *lmNewHash,
2465                                 const struct samr_Password *ntNewHash,
2466                                 const struct samr_Password *lmOldHash,
2467                                 const struct samr_Password *ntOldHash,
2468                                 enum samPwdChangeReason *reject_reason,
2469                                 struct samr_DomInfo1 **_dominfo) 
2470 {
2471         TALLOC_CTX *frame = talloc_stackframe();
2472         NTSTATUS nt_status;
2473         const char * const user_attrs[] = {
2474                 "userAccountControl",
2475                 "sAMAccountName",
2476                 NULL
2477         };
2478         struct ldb_message *user_msg = NULL;
2479         int ret;
2480         uint32_t uac = 0;
2481
2482         ret = ldb_transaction_start(ldb);
2483         if (ret != LDB_SUCCESS) {
2484                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2485                 TALLOC_FREE(frame);
2486                 return NT_STATUS_TRANSACTION_ABORTED;
2487         }
2488
2489         ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2490                               LDB_SCOPE_SUBTREE, user_attrs, 0,
2491                               "(&(objectSid=%s)(objectClass=user))",
2492                               ldap_encode_ndr_dom_sid(frame, user_sid));
2493         if (ret != LDB_SUCCESS) {
2494                 ldb_transaction_cancel(ldb);
2495                 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2496                           "returning NO_SUCH_USER\n",
2497                           dom_sid_string(frame, user_sid),
2498                           ldb_strerror(ret), ldb_errstring(ldb)));
2499                 TALLOC_FREE(frame);
2500                 return NT_STATUS_NO_SUCH_USER;
2501         }
2502
2503         uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2504         if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2505                 ldb_transaction_cancel(ldb);
2506                 DEBUG(1, ("samdb_set_password_sid: invalid "
2507                           "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2508                           "returning NO_SUCH_USER\n",
2509                           (unsigned)uac, dom_sid_string(frame, user_sid),
2510                           ldb_dn_get_linearized(user_msg->dn)));
2511                 TALLOC_FREE(frame);
2512                 return NT_STATUS_NO_SUCH_USER;
2513         }
2514
2515         if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2516                 const char * const tdo_attrs[] = {
2517                         "trustAuthIncoming",
2518                         "trustDirection",
2519                         NULL
2520                 };
2521                 struct ldb_message *tdo_msg = NULL;
2522                 const char *account_name = NULL;
2523                 uint32_t trust_direction;
2524                 uint32_t i;
2525                 const struct ldb_val *old_val = NULL;
2526                 struct trustAuthInOutBlob old_blob = {};
2527                 uint32_t old_version = 0;
2528                 struct AuthenticationInformation *old_version_a = NULL;
2529                 uint32_t _new_version = 0;
2530                 struct trustAuthInOutBlob new_blob = {};
2531                 struct ldb_val new_val = {};
2532                 struct timeval tv = timeval_current();
2533                 NTTIME now = timeval_to_nttime(&tv);
2534                 enum ndr_err_code ndr_err;
2535
2536                 if (new_password == NULL && ntNewHash == NULL) {
2537                         ldb_transaction_cancel(ldb);
2538                         DEBUG(1, ("samdb_set_password_sid: "
2539                                   "no new password provided "
2540                                   "sAMAccountName for SID[%s] DN[%s], "
2541                                   "returning INVALID_PARAMETER\n",
2542                                   dom_sid_string(frame, user_sid),
2543                                   ldb_dn_get_linearized(user_msg->dn)));
2544                         TALLOC_FREE(frame);
2545                         return NT_STATUS_INVALID_PARAMETER;
2546                 }
2547
2548                 if (new_password != NULL && ntNewHash != NULL) {
2549                         ldb_transaction_cancel(ldb);
2550                         DEBUG(1, ("samdb_set_password_sid: "
2551                                   "two new passwords provided "
2552                                   "sAMAccountName for SID[%s] DN[%s], "
2553                                   "returning INVALID_PARAMETER\n",
2554                                   dom_sid_string(frame, user_sid),
2555                                   ldb_dn_get_linearized(user_msg->dn)));
2556                         TALLOC_FREE(frame);
2557                         return NT_STATUS_INVALID_PARAMETER;
2558                 }
2559
2560                 if (new_password != NULL && (new_password->length % 2)) {
2561                         ldb_transaction_cancel(ldb);
2562                         DEBUG(2, ("samdb_set_password_sid: "
2563                                   "invalid utf16 length (%zu) "
2564                                   "sAMAccountName for SID[%s] DN[%s], "
2565                                   "returning WRONG_PASSWORD\n",
2566                                   new_password->length,
2567                                   dom_sid_string(frame, user_sid),
2568                                   ldb_dn_get_linearized(user_msg->dn)));
2569                         TALLOC_FREE(frame);
2570                         return NT_STATUS_WRONG_PASSWORD;
2571                 }
2572
2573                 if (new_password != NULL && new_password->length >= 500) {
2574                         ldb_transaction_cancel(ldb);
2575                         DEBUG(2, ("samdb_set_password_sid: "
2576                                   "utf16 password too long (%zu) "
2577                                   "sAMAccountName for SID[%s] DN[%s], "
2578                                   "returning WRONG_PASSWORD\n",
2579                                   new_password->length,
2580                                   dom_sid_string(frame, user_sid),
2581                                   ldb_dn_get_linearized(user_msg->dn)));
2582                         TALLOC_FREE(frame);
2583                         return NT_STATUS_WRONG_PASSWORD;
2584                 }
2585
2586                 account_name = ldb_msg_find_attr_as_string(user_msg,
2587                                                         "sAMAccountName", NULL);
2588                 if (account_name == NULL) {
2589                         ldb_transaction_cancel(ldb);
2590                         DEBUG(1, ("samdb_set_password_sid: missing "
2591                                   "sAMAccountName for SID[%s] DN[%s], "
2592                                   "returning NO_SUCH_USER\n",
2593                                   dom_sid_string(frame, user_sid),
2594                                   ldb_dn_get_linearized(user_msg->dn)));
2595                         TALLOC_FREE(frame);
2596                         return NT_STATUS_NO_SUCH_USER;
2597                 }
2598
2599                 nt_status = dsdb_trust_search_tdo_by_type(ldb,
2600                                                           SEC_CHAN_DOMAIN,
2601                                                           account_name,
2602                                                           tdo_attrs,
2603                                                           frame, &tdo_msg);
2604                 if (!NT_STATUS_IS_OK(nt_status)) {
2605                         ldb_transaction_cancel(ldb);
2606                         DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2607                                   "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2608                                   "returning INTERNAL_DB_CORRUPTION\n",
2609                                   nt_errstr(nt_status), account_name,
2610                                   dom_sid_string(frame, user_sid),
2611                                   ldb_dn_get_linearized(user_msg->dn)));
2612                         TALLOC_FREE(frame);
2613                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2614                 }
2615
2616                 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2617                                                            "trustDirection", 0);
2618                 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2619                         ldb_transaction_cancel(ldb);
2620                         DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2621                                   "not inbound for sAMAccountName[%s] "
2622                                   "DN[%s] TDO[%s], "
2623                                   "returning INTERNAL_DB_CORRUPTION\n",
2624                                   (unsigned)trust_direction,
2625                                   account_name,
2626                                   ldb_dn_get_linearized(user_msg->dn),
2627                                   ldb_dn_get_linearized(tdo_msg->dn)));
2628                         TALLOC_FREE(frame);
2629                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2630                 }
2631
2632                 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2633                 if (old_val != NULL) {
2634                         ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2635                                         (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2636                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2637                                 ldb_transaction_cancel(ldb);
2638                                 DEBUG(1, ("samdb_set_password_sid: "
2639                                           "failed(%s) to parse "
2640                                           "trustAuthOutgoing sAMAccountName[%s] "
2641                                           "DN[%s] TDO[%s], "
2642                                           "returning INTERNAL_DB_CORRUPTION\n",
2643                                           ndr_map_error2string(ndr_err),
2644                                           account_name,
2645                                           ldb_dn_get_linearized(user_msg->dn),
2646                                           ldb_dn_get_linearized(tdo_msg->dn)));
2647
2648                                 TALLOC_FREE(frame);
2649                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2650                         }
2651                 }
2652
2653                 for (i = old_blob.current.count; i > 0; i--) {
2654                         struct AuthenticationInformation *a =
2655                                 &old_blob.current.array[i - 1];
2656
2657                         switch (a->AuthType) {
2658                         case TRUST_AUTH_TYPE_NONE:
2659                                 if (i == old_blob.current.count) {
2660                                         /*
2661                                          * remove TRUST_AUTH_TYPE_NONE at the
2662                                          * end
2663                                          */
2664                                         old_blob.current.count--;
2665                                 }
2666                                 break;
2667
2668                         case TRUST_AUTH_TYPE_VERSION:
2669                                 old_version_a = a;
2670                                 old_version = a->AuthInfo.version.version;
2671                                 break;
2672
2673                         case TRUST_AUTH_TYPE_CLEAR:
2674                                 break;
2675
2676                         case TRUST_AUTH_TYPE_NT4OWF:
2677                                 break;
2678                         }
2679                 }
2680
2681                 if (new_version == NULL) {
2682                         _new_version = 0;
2683                         new_version = &_new_version;
2684                 }
2685
2686                 if (old_version_a != NULL && *new_version != (old_version + 1)) {
2687                         old_version_a->LastUpdateTime = now;
2688                         old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2689                 }
2690
2691                 new_blob.count = MAX(old_blob.current.count, 2);
2692                 new_blob.current.array = talloc_zero_array(frame,
2693                                                 struct AuthenticationInformation,
2694                                                 new_blob.count);
2695                 if (new_blob.current.array == NULL) {
2696                         ldb_transaction_cancel(ldb);
2697                         TALLOC_FREE(frame);
2698                         return NT_STATUS_NO_MEMORY;
2699                 }
2700                 new_blob.previous.array = talloc_zero_array(frame,
2701                                                 struct AuthenticationInformation,
2702                                                 new_blob.count);
2703                 if (new_blob.current.array == NULL) {
2704                         ldb_transaction_cancel(ldb);
2705                         TALLOC_FREE(frame);
2706                         return NT_STATUS_NO_MEMORY;
2707                 }
2708
2709                 for (i = 0; i < old_blob.current.count; i++) {
2710                         struct AuthenticationInformation *o =
2711                                 &old_blob.current.array[i];
2712                         struct AuthenticationInformation *p =
2713                                 &new_blob.previous.array[i];
2714
2715                         *p = *o;
2716                         new_blob.previous.count++;
2717                 }
2718                 for (; i < new_blob.count; i++) {
2719                         struct AuthenticationInformation *pi =
2720                                 &new_blob.previous.array[i];
2721
2722                         if (i == 0) {
2723                                 /*
2724                                  * new_blob.previous is still empty so
2725                                  * we'll do new_blob.previous = new_blob.current
2726                                  * below.
2727                                  */
2728                                 break;
2729                         }
2730
2731                         pi->LastUpdateTime = now;
2732                         pi->AuthType = TRUST_AUTH_TYPE_NONE;
2733                         new_blob.previous.count++;
2734                 }
2735
2736                 for (i = 0; i < new_blob.count; i++) {
2737                         struct AuthenticationInformation *ci =
2738                                 &new_blob.current.array[i];
2739
2740                         ci->LastUpdateTime = now;
2741                         switch (i) {
2742                         case 0:
2743                                 if (ntNewHash != NULL) {
2744                                         ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
2745                                         ci->AuthInfo.nt4owf.password = *ntNewHash;
2746                                         break;
2747                                 }
2748
2749                                 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
2750                                 ci->AuthInfo.clear.size = new_password->length;
2751                                 ci->AuthInfo.clear.password = new_password->data;
2752                                 break;
2753                         case 1:
2754                                 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
2755                                 ci->AuthInfo.version.version = *new_version;
2756                                 break;
2757                         default:
2758                                 ci->AuthType = TRUST_AUTH_TYPE_NONE;
2759                                 break;
2760                         }
2761
2762                         new_blob.current.count++;
2763                 }
2764
2765                 if (new_blob.previous.count == 0) {
2766                         TALLOC_FREE(new_blob.previous.array);
2767                         new_blob.previous = new_blob.current;
2768                 }
2769
2770                 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
2771                                 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
2772                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2773                         ldb_transaction_cancel(ldb);
2774                         DEBUG(1, ("samdb_set_password_sid: "
2775                                   "failed(%s) to generate "
2776                                   "trustAuthOutgoing sAMAccountName[%s] "
2777                                   "DN[%s] TDO[%s], "
2778                                   "returning UNSUCCESSFUL\n",
2779                                   ndr_map_error2string(ndr_err),
2780                                   account_name,
2781                                   ldb_dn_get_linearized(user_msg->dn),
2782                                   ldb_dn_get_linearized(tdo_msg->dn)));
2783                         TALLOC_FREE(frame);
2784                         return NT_STATUS_UNSUCCESSFUL;
2785                 }
2786
2787                 tdo_msg->num_elements = 0;
2788                 TALLOC_FREE(tdo_msg->elements);
2789
2790                 ret = ldb_msg_add_empty(tdo_msg, "trustAuthIncoming",
2791                                         LDB_FLAG_MOD_REPLACE, NULL);
2792                 if (ret != LDB_SUCCESS) {
2793                         ldb_transaction_cancel(ldb);
2794                         TALLOC_FREE(frame);
2795                         return NT_STATUS_NO_MEMORY;
2796                 }
2797                 ret = ldb_msg_add_value(tdo_msg, "trustAuthIncoming",
2798                                         &new_val, NULL);
2799                 if (ret != LDB_SUCCESS) {
2800                         ldb_transaction_cancel(ldb);
2801                         TALLOC_FREE(frame);
2802                         return NT_STATUS_NO_MEMORY;
2803                 }
2804
2805                 ret = ldb_modify(ldb, tdo_msg);
2806                 if (ret != LDB_SUCCESS) {
2807                         nt_status = dsdb_ldb_err_to_ntstatus(ret);
2808                         ldb_transaction_cancel(ldb);
2809                         DEBUG(1, ("samdb_set_password_sid: "
2810                                   "failed to replace "
2811                                   "trustAuthOutgoing sAMAccountName[%s] "
2812                                   "DN[%s] TDO[%s], "
2813                                   "%s - %s\n",
2814                                   account_name,
2815                                   ldb_dn_get_linearized(user_msg->dn),
2816                                   ldb_dn_get_linearized(tdo_msg->dn),
2817                                   nt_errstr(nt_status), ldb_errstring(ldb)));
2818                         TALLOC_FREE(frame);
2819                         return nt_status;
2820                 }
2821         }
2822
2823         nt_status = samdb_set_password_internal(ldb, mem_ctx,
2824                                                 user_msg->dn, NULL,
2825                                                 new_password,
2826                                                 lmNewHash, ntNewHash,
2827                                                 lmOldHash, ntOldHash,
2828                                                 reject_reason, _dominfo,
2829                                                 true); /* permit trusts */
2830         if (!NT_STATUS_IS_OK(nt_status)) {
2831                 ldb_transaction_cancel(ldb);
2832                 TALLOC_FREE(frame);
2833                 return nt_status;
2834         }
2835
2836         ret = ldb_transaction_commit(ldb);
2837         if (ret != LDB_SUCCESS) {
2838                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
2839                          ldb_dn_get_linearized(user_msg->dn),
2840                          ldb_errstring(ldb)));
2841                 TALLOC_FREE(frame);
2842                 return NT_STATUS_TRANSACTION_ABORTED;
2843         }
2844
2845         TALLOC_FREE(frame);
2846         return NT_STATUS_OK;
2847 }
2848
2849
2850 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
2851                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
2852 {
2853         struct ldb_message *msg;
2854         struct ldb_dn *basedn;
2855         char *sidstr;
2856         int ret;
2857
2858         sidstr = dom_sid_string(mem_ctx, sid);
2859         NT_STATUS_HAVE_NO_MEMORY(sidstr);
2860
2861         /* We might have to create a ForeignSecurityPrincipal, even if this user
2862          * is in our own domain */
2863
2864         msg = ldb_msg_new(sidstr);
2865         if (msg == NULL) {
2866                 talloc_free(sidstr);
2867                 return NT_STATUS_NO_MEMORY;
2868         }
2869
2870         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
2871                                 ldb_get_default_basedn(sam_ctx),
2872                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
2873                                 &basedn);
2874         if (ret != LDB_SUCCESS) {
2875                 DEBUG(0, ("Failed to find DN for "
2876                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
2877                 talloc_free(sidstr);
2878                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2879         }
2880
2881         /* add core elements to the ldb_message for the alias */
2882         msg->dn = basedn;
2883         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
2884                 talloc_free(sidstr);
2885                 return NT_STATUS_NO_MEMORY;
2886         }
2887
2888         ret = ldb_msg_add_string(msg, "objectClass",
2889                                  "foreignSecurityPrincipal");
2890         if (ret != LDB_SUCCESS) {
2891                 talloc_free(sidstr);
2892                 return NT_STATUS_NO_MEMORY;
2893         }
2894
2895         /* create the alias */
2896         ret = ldb_add(sam_ctx, msg);
2897         if (ret != LDB_SUCCESS) {
2898                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
2899                          "record %s: %s\n", 
2900                          ldb_dn_get_linearized(msg->dn),
2901                          ldb_errstring(sam_ctx)));
2902                 talloc_free(sidstr);
2903                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2904         }
2905
2906         *ret_dn = talloc_steal(mem_ctx, msg->dn);
2907         talloc_free(sidstr);
2908
2909         return NT_STATUS_OK;
2910 }
2911
2912
2913 /*
2914   Find the DN of a domain, assuming it to be a dotted.dns name
2915 */
2916
2917 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
2918 {
2919         unsigned int i;
2920         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2921         const char *binary_encoded;
2922         const char * const *split_realm;
2923         struct ldb_dn *dn;
2924
2925         if (!tmp_ctx) {
2926                 return NULL;
2927         }
2928
2929         split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
2930         if (!split_realm) {
2931                 talloc_free(tmp_ctx);
2932                 return NULL;
2933         }
2934         dn = ldb_dn_new(mem_ctx, ldb, NULL);
2935         for (i=0; split_realm[i]; i++) {
2936                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
2937                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
2938                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
2939                                   binary_encoded, ldb_dn_get_linearized(dn)));
2940                         talloc_free(tmp_ctx);
2941                         return NULL;
2942                 }
2943         }
2944         if (!ldb_dn_validate(dn)) {
2945                 DEBUG(2, ("Failed to validated DN %s\n",
2946                           ldb_dn_get_linearized(dn)));
2947                 talloc_free(tmp_ctx);
2948                 return NULL;
2949         }
2950         talloc_free(tmp_ctx);
2951         return dn;
2952 }
2953
2954
2955 /*
2956   Find the DNS equivalent of a DN, in dotted DNS form
2957 */
2958 char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
2959 {
2960         int i, num_components = ldb_dn_get_comp_num(dn);
2961         char *dns_name = talloc_strdup(mem_ctx, "");
2962         if (dns_name == NULL) {
2963                 return NULL;
2964         }
2965
2966         for (i=0; i<num_components; i++) {
2967                 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
2968                 char *s;
2969                 if (v == NULL) {
2970                         talloc_free(dns_name);
2971                         return NULL;
2972                 }
2973                 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
2974                                                   (int)v->length, (int)v->length, (char *)v->data);
2975                 if (s == NULL) {
2976                         talloc_free(dns_name);
2977                         return NULL;
2978                 }
2979                 dns_name = s;
2980         }
2981
2982         /* remove the last '.' */
2983         if (dns_name[0] != 0) {
2984                 dns_name[strlen(dns_name)-1] = 0;
2985         }
2986
2987         return dns_name;
2988 }
2989
2990 /*
2991   Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
2992   name is based on the forest DNS name
2993 */
2994 char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
2995                                 TALLOC_CTX *mem_ctx,
2996                                 const struct GUID *ntds_guid)
2997 {
2998         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2999         const char *guid_str;
3000         struct ldb_dn *forest_dn;
3001         const char *dnsforest;
3002         char *ret;
3003
3004         guid_str = GUID_string(tmp_ctx, ntds_guid);
3005         if (guid_str == NULL) {
3006                 talloc_free(tmp_ctx);
3007                 return NULL;
3008         }
3009         forest_dn = ldb_get_root_basedn(samdb);
3010         if (forest_dn == NULL) {
3011                 talloc_free(tmp_ctx);
3012                 return NULL;
3013         }
3014         dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
3015         if (dnsforest == NULL) {
3016                 talloc_free(tmp_ctx);
3017                 return NULL;
3018         }
3019         ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
3020         talloc_free(tmp_ctx);
3021         return ret;
3022 }
3023
3024
3025 /*
3026   Find the DN of a domain, be it the netbios or DNS name 
3027 */
3028 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
3029                                   const char *domain_name) 
3030 {
3031         const char * const domain_ref_attrs[] = {
3032                 "ncName", NULL
3033         };
3034         const char * const domain_ref2_attrs[] = {
3035                 NULL
3036         };
3037         struct ldb_result *res_domain_ref;
3038         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
3039         /* find the domain's DN */
3040         int ret_domain = ldb_search(ldb, mem_ctx,
3041                                             &res_domain_ref, 
3042                                             samdb_partitions_dn(ldb, mem_ctx), 
3043                                             LDB_SCOPE_ONELEVEL, 
3044                                             domain_ref_attrs,
3045                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
3046                                             escaped_domain);
3047         if (ret_domain != LDB_SUCCESS) {
3048                 return NULL;
3049         }
3050
3051         if (res_domain_ref->count == 0) {
3052                 ret_domain = ldb_search(ldb, mem_ctx,
3053                                                 &res_domain_ref, 
3054                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
3055                                                 LDB_SCOPE_BASE,
3056                                                 domain_ref2_attrs,
3057                                                 "(objectclass=domain)");
3058                 if (ret_domain != LDB_SUCCESS) {
3059                         return NULL;
3060                 }
3061
3062                 if (res_domain_ref->count == 1) {
3063                         return res_domain_ref->msgs[0]->dn;
3064                 }
3065                 return NULL;
3066         }
3067
3068         if (res_domain_ref->count > 1) {
3069                 DEBUG(0,("Found %d records matching domain [%s]\n", 
3070                          ret_domain, domain_name));
3071                 return NULL;
3072         }
3073
3074         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3075
3076 }
3077
3078
3079 /*
3080   use a GUID to find a DN
3081  */
3082 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 
3083                          TALLOC_CTX *mem_ctx,
3084                          const struct GUID *guid,
3085                          uint32_t dsdb_flags,
3086                          struct ldb_dn **dn)
3087 {
3088         int ret;
3089         struct ldb_result *res;
3090         const char *attrs[] = { NULL };
3091         char *guid_str = GUID_string(mem_ctx, guid);
3092
3093         if (!guid_str) {
3094                 return ldb_operr(ldb);
3095         }
3096
3097         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3098                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3099                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3100                           DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3101                           "objectGUID=%s", guid_str);
3102         talloc_free(guid_str);
3103         if (ret != LDB_SUCCESS) {
3104                 return ret;
3105         }
3106
3107         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3108         talloc_free(res);
3109
3110         return LDB_SUCCESS;
3111 }
3112
3113 /*
3114   use a DN to find a GUID with a given attribute name
3115  */
3116 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3117                               struct ldb_dn *dn, const char *attribute,
3118                               struct GUID *guid)
3119 {
3120         int ret;
3121         struct ldb_result *res;
3122         const char *attrs[2];
3123         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3124
3125         attrs[0] = attribute;
3126         attrs[1] = NULL;
3127
3128         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3129                              DSDB_SEARCH_SHOW_DELETED |
3130                              DSDB_SEARCH_SHOW_RECYCLED);
3131         if (ret != LDB_SUCCESS) {
3132                 talloc_free(tmp_ctx);
3133                 return ret;
3134         }
3135         if (res->count < 1) {
3136                 talloc_free(tmp_ctx);
3137                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3138         }
3139         *guid = samdb_result_guid(res->msgs[0], attribute);
3140         talloc_free(tmp_ctx);
3141         return LDB_SUCCESS;
3142 }
3143
3144 /*
3145   use a DN to find a GUID
3146  */
3147 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3148                          struct ldb_dn *dn, struct GUID *guid)
3149 {
3150         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3151 }
3152
3153
3154
3155 /*
3156  adds the given GUID to the given ldb_message. This value is added
3157  for the given attr_name (may be either "objectGUID" or "parentGUID").
3158  */
3159 int dsdb_msg_add_guid(struct ldb_message *msg,
3160                 struct GUID *guid,
3161                 const char *attr_name)
3162 {
3163         int ret;
3164         struct ldb_val v;
3165         NTSTATUS status;
3166         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
3167
3168         status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3169         if (!NT_STATUS_IS_OK(status)) {
3170                 ret = LDB_ERR_OPERATIONS_ERROR;
3171                 goto done;
3172         }
3173
3174         ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3175         if (ret != LDB_SUCCESS) {
3176                 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3177                                          attr_name));
3178                 goto done;
3179         }
3180
3181         ret = LDB_SUCCESS;
3182
3183 done:
3184         talloc_free(tmp_ctx);
3185         return ret;
3186
3187 }
3188
3189
3190 /*
3191   use a DN to find a SID
3192  */
3193 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 
3194                         struct ldb_dn *dn, struct dom_sid *sid)
3195 {
3196         int ret;
3197         struct ldb_result *res;
3198         const char *attrs[] = { "objectSid", NULL };
3199         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3200         struct dom_sid *s;
3201
3202         ZERO_STRUCTP(sid);
3203
3204         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3205                              DSDB_SEARCH_SHOW_DELETED |
3206                              DSDB_SEARCH_SHOW_RECYCLED);
3207         if (ret != LDB_SUCCESS) {
3208                 talloc_free(tmp_ctx);
3209                 return ret;
3210         }
3211         if (res->count < 1) {
3212                 talloc_free(tmp_ctx);
3213                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3214         }
3215         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3216         if (s == NULL) {
3217                 talloc_free(tmp_ctx);
3218                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3219         }
3220         *sid = *s;
3221         talloc_free(tmp_ctx);
3222         return LDB_SUCCESS;
3223 }
3224
3225 /*
3226   use a SID to find a DN
3227  */
3228 int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3229                         TALLOC_CTX *mem_ctx,
3230                         struct dom_sid *sid, struct ldb_dn **dn)
3231 {
3232         int ret;
3233         struct ldb_result *res;
3234         const char *attrs[] = { NULL };
3235         char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3236
3237         if (!sid_str) {
3238                 return ldb_operr(ldb);
3239         }
3240
3241         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3242                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3243                           DSDB_SEARCH_SHOW_EXTENDED_DN |
3244                           DSDB_SEARCH_ONE_ONLY,
3245                           "objectSid=%s", sid_str);
3246         talloc_free(sid_str);
3247         if (ret != LDB_SUCCESS) {
3248                 return ret;
3249         }
3250
3251         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3252         talloc_free(res);
3253
3254         return LDB_SUCCESS;
3255 }
3256
3257 /*
3258   load a repsFromTo blob list for a given partition GUID
3259   attr must be "repsFrom" or "repsTo"
3260  */
3261 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3262                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
3263 {
3264         const char *attrs[] = { attr, NULL };
3265         struct ldb_result *res = NULL;
3266         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3267         unsigned int i;
3268         struct ldb_message_element *el;
3269         int ret;
3270
3271         *r = NULL;
3272         *count = 0;
3273
3274         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3275         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3276                 /* partition hasn't been replicated yet */
3277                 return WERR_OK;
3278         }
3279         if (ret != LDB_SUCCESS) {
3280                 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3281                 talloc_free(tmp_ctx);
3282                 return WERR_DS_DRA_INTERNAL_ERROR;
3283         }
3284
3285         el = ldb_msg_find_element(res->msgs[0], attr);
3286         if (el == NULL) {
3287                 /* it's OK to be empty */
3288                 talloc_free(tmp_ctx);
3289                 return WERR_OK;
3290         }
3291
3292         *count = el->num_values;
3293         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3294         if (*r == NULL) {
3295                 talloc_free(tmp_ctx);
3296                 return WERR_DS_DRA_INTERNAL_ERROR;
3297         }
3298
3299         for (i=0; i<(*count); i++) {
3300                 enum ndr_err_code ndr_err;
3301                 ndr_err = ndr_pull_struct_blob(&el->values[i], 
3302                                                mem_ctx, 
3303                                                &(*r)[i], 
3304                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3305                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3306                         talloc_free(tmp_ctx);
3307                         return WERR_DS_DRA_INTERNAL_ERROR;
3308                 }
3309         }
3310
3311         talloc_free(tmp_ctx);
3312         
3313         return WERR_OK;
3314 }
3315
3316 /*
3317   save the repsFromTo blob list for a given partition GUID
3318   attr must be "repsFrom" or "repsTo"
3319  */
3320 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3321                      const char *attr, struct repsFromToBlob *r, uint32_t count)
3322 {
3323         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3324         struct ldb_message *msg;
3325         struct ldb_message_element *el;
3326         unsigned int i;
3327
3328         msg = ldb_msg_new(tmp_ctx);
3329         msg->dn = dn;
3330         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3331                 goto failed;
3332         }
3333
3334         el->values = talloc_array(msg, struct ldb_val, count);
3335         if (!el->values) {
3336                 goto failed;
3337         }
3338
3339         for (i=0; i<count; i++) {
3340                 struct ldb_val v;
3341                 enum ndr_err_code ndr_err;
3342
3343                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, 
3344                                                &r[i], 
3345                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3346                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3347                         goto failed;
3348                 }
3349
3350                 el->num_values++;
3351                 el->values[i] = v;
3352         }
3353
3354         if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3355                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3356                 goto failed;
3357         }
3358
3359         talloc_free(tmp_ctx);
3360         
3361         return WERR_OK;
3362
3363 failed:
3364         talloc_free(tmp_ctx);
3365         return WERR_DS_DRA_INTERNAL_ERROR;
3366 }
3367
3368
3369 /*
3370   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3371   object for a partition
3372  */
3373 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3374                                 uint64_t *uSN, uint64_t *urgent_uSN)
3375 {
3376         struct ldb_request *req;
3377         int ret;
3378         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3379         struct dsdb_control_current_partition *p_ctrl;
3380         struct ldb_result *res;
3381
3382         res = talloc_zero(tmp_ctx, struct ldb_result);
3383         if (!res) {
3384                 talloc_free(tmp_ctx);
3385                 return ldb_oom(ldb);
3386         }
3387
3388         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3389                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3390                                    LDB_SCOPE_BASE,
3391                                    NULL, NULL,
3392                                    NULL,
3393                                    res, ldb_search_default_callback,
3394                                    NULL);
3395         if (ret != LDB_SUCCESS) {
3396                 talloc_free(tmp_ctx);
3397                 return ret;
3398         }
3399
3400         p_ctrl = talloc(req, struct dsdb_control_current_partition);
3401         if (p_ctrl == NULL) {
3402                 talloc_free(tmp_ctx);
3403                 return ldb_oom(ldb);
3404         }
3405         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3406         p_ctrl->dn = dn;
3407         
3408         ret = ldb_request_add_control(req,
3409                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3410                                       false, p_ctrl);
3411         if (ret != LDB_SUCCESS) {
3412                 talloc_free(tmp_ctx);
3413                 return ret;
3414         }
3415         
3416         /* Run the new request */
3417         ret = ldb_request(ldb, req);
3418         
3419         if (ret == LDB_SUCCESS) {
3420                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3421         }
3422
3423         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3424                 /* it hasn't been created yet, which means
3425                    an implicit value of zero */
3426                 *uSN = 0;
3427                 talloc_free(tmp_ctx);
3428                 return LDB_SUCCESS;
3429         }
3430
3431         if (ret != LDB_SUCCESS) {
3432                 talloc_free(tmp_ctx);
3433                 return ret;
3434         }
3435
3436         if (res->count < 1) {
3437                 *uSN = 0;
3438                 if (urgent_uSN) {
3439                         *urgent_uSN = 0;
3440                 }
3441         } else {
3442                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3443                 if (urgent_uSN) {
3444                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3445                 }
3446         }
3447
3448         talloc_free(tmp_ctx);
3449
3450         return LDB_SUCCESS;     
3451 }
3452
3453 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3454                                                    const struct drsuapi_DsReplicaCursor2 *c2)
3455 {
3456         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3457 }
3458
3459 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3460                                     const struct drsuapi_DsReplicaCursor *c2)
3461 {
3462         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3463 }
3464
3465
3466 /*
3467   see if a computer identified by its invocationId is a RODC
3468 */
3469 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3470 {
3471         /* 1) find the DN for this servers NTDSDSA object
3472            2) search for the msDS-isRODC attribute
3473            3) if not present then not a RODC
3474            4) if present and TRUE then is a RODC
3475         */
3476         struct ldb_dn *config_dn;
3477         const char *attrs[] = { "msDS-isRODC", NULL };
3478         int ret;
3479         struct ldb_result *res;
3480         TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3481
3482         config_dn = ldb_get_config_basedn(sam_ctx);
3483         if (!config_dn) {
3484                 talloc_free(tmp_ctx);
3485                 return ldb_operr(sam_ctx);
3486         }
3487
3488         ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
3489                           DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
3490
3491         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3492                 *is_rodc = false;
3493                 talloc_free(tmp_ctx);
3494                 return LDB_SUCCESS;
3495         }
3496
3497         if (ret != LDB_SUCCESS) {
3498                 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
3499                          GUID_string(tmp_ctx, objectGUID)));
3500                 *is_rodc = false;
3501                 talloc_free(tmp_ctx);
3502                 return ret;
3503         }
3504
3505         ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
3506         *is_rodc = (ret == 1);
3507
3508         talloc_free(tmp_ctx);
3509         return LDB_SUCCESS;
3510 }
3511
3512
3513 /*
3514   see if we are a RODC
3515 */
3516 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3517 {
3518         const struct GUID *objectGUID;
3519         int ret;
3520         bool *cached;
3521
3522         /* see if we have a cached copy */
3523         cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3524         if (cached) {
3525                 *am_rodc = *cached;
3526                 return LDB_SUCCESS;
3527         }
3528
3529         objectGUID = samdb_ntds_objectGUID(sam_ctx);
3530         if (!objectGUID) {
3531                 return ldb_operr(sam_ctx);
3532         }
3533
3534         ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3535         if (ret != LDB_SUCCESS) {
3536                 return ret;
3537         }
3538
3539         cached = talloc(sam_ctx, bool);
3540         if (cached == NULL) {
3541                 return ldb_oom(sam_ctx);
3542         }
3543         *cached = *am_rodc;
3544
3545         ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3546         if (ret != LDB_SUCCESS) {
3547                 talloc_free(cached);
3548                 return ldb_operr(sam_ctx);
3549         }
3550
3551         return LDB_SUCCESS;
3552 }
3553
3554 int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
3555 {
3556         const char *_host_name = NULL;
3557         const char *attrs[] = { "dnsHostName", NULL };
3558         TALLOC_CTX *tmp_ctx = NULL;
3559         int ret;
3560         struct ldb_result *res = NULL;
3561
3562         _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
3563         if (_host_name != NULL) {
3564                 *host_name = _host_name;
3565                 return LDB_SUCCESS;
3566         }
3567
3568         tmp_ctx = talloc_new(sam_ctx);
3569
3570         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
3571
3572         if (res->count != 1 || ret != LDB_SUCCESS) {
3573                 DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s",
3574                           ldb_errstring(sam_ctx)));
3575                 TALLOC_FREE(tmp_ctx);
3576                 return ret;
3577         }
3578
3579
3580         _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
3581                                                  "dnsHostName",
3582                                                  NULL);
3583         if (_host_name == NULL) {
3584                 DEBUG(0, ("Failed to get dnsHostName from rootDSE"));
3585                 TALLOC_FREE(tmp_ctx);
3586                 return LDB_ERR_OPERATIONS_ERROR;
3587         }
3588         ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
3589                              discard_const_p(char *, _host_name));
3590         if (ret != LDB_SUCCESS) {
3591                 TALLOC_FREE(tmp_ctx);
3592                 return ldb_operr(sam_ctx);
3593         }
3594
3595         *host_name = talloc_steal(sam_ctx, _host_name);
3596
3597         TALLOC_FREE(tmp_ctx);
3598         return LDB_SUCCESS;
3599 }
3600
3601 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3602 {
3603         TALLOC_CTX *tmp_ctx;
3604         bool *cached;
3605
3606         tmp_ctx = talloc_new(ldb);
3607         if (tmp_ctx == NULL) {
3608                 goto failed;
3609         }
3610
3611         cached = talloc(tmp_ctx, bool);
3612         if (!cached) {
3613                 goto failed;
3614         }
3615
3616         *cached = am_rodc;
3617         if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3618                 goto failed;
3619         }
3620
3621         talloc_steal(ldb, cached);
3622         talloc_free(tmp_ctx);
3623         return true;
3624
3625 failed:
3626         DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3627         talloc_free(tmp_ctx);
3628         return false;
3629 }
3630
3631
3632 /*
3633  * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3634  * flags are DS_NTDSSETTINGS_OPT_*
3635  */
3636 int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3637                                         uint32_t *options)
3638 {
3639         int rc;
3640         TALLOC_CTX *tmp_ctx;
3641         struct ldb_result *res;
3642         struct ldb_dn *site_dn;
3643         const char *attrs[] = { "options", NULL };
3644
3645         tmp_ctx = talloc_new(ldb_ctx);
3646         if (tmp_ctx == NULL)
3647                 goto failed;
3648
3649         /* Retrieve the site dn for the ldb that we
3650          * have open.  This is our local site.
3651          */
3652         site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3653         if (site_dn == NULL)
3654                 goto failed;
3655
3656         /* Perform a one level (child) search from the local
3657          * site distinguided name.   We're looking for the
3658          * "options" attribute within the nTDSSiteSettings
3659          * object
3660          */
3661         rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
3662                         LDB_SCOPE_ONELEVEL, attrs,
3663                         "objectClass=nTDSSiteSettings");
3664
3665         if (rc != LDB_SUCCESS || res->count != 1)
3666                 goto failed;
3667
3668         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3669
3670         talloc_free(tmp_ctx);
3671
3672         return LDB_SUCCESS;
3673
3674 failed:
3675         DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
3676         talloc_free(tmp_ctx);
3677         return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
3678 }
3679
3680 /*
3681   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 
3682
3683   flags are DS_NTDS_OPTION_*
3684 */
3685 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
3686 {
3687         TALLOC_CTX *tmp_ctx;
3688         const char *attrs[] = { "options", NULL };
3689         int ret;
3690         struct ldb_result *res;
3691
3692         tmp_ctx = talloc_new(ldb);
3693         if (tmp_ctx == NULL) {
3694                 goto failed;
3695         }
3696
3697         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3698         if (ret != LDB_SUCCESS) {
3699                 goto failed;
3700         }
3701
3702         if (res->count != 1) {
3703                 goto failed;
3704         }
3705
3706         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
3707
3708         talloc_free(tmp_ctx);
3709
3710         return LDB_SUCCESS;
3711
3712 failed:
3713         DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
3714         talloc_free(tmp_ctx);
3715         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3716 }
3717
3718 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
3719 {
3720         const char *attrs[] = { "objectCategory", NULL };
3721         int ret;
3722         struct ldb_result *res;
3723
3724         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
3725         if (ret != LDB_SUCCESS) {
3726                 goto failed;
3727         }
3728
3729         if (res->count != 1) {
3730                 goto failed;
3731         }
3732
3733         return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
3734
3735 failed:
3736         DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
3737         return NULL;
3738 }
3739
3740 /*
3741  * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
3742  * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
3743  */
3744 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
3745 {
3746         char **tokens, *ret;
3747         size_t i;
3748
3749         tokens = str_list_make(mem_ctx, cn, " -_");
3750         if (tokens == NULL || tokens[0] == NULL) {
3751                 return NULL;
3752         }
3753
3754         /* "tolower()" and "toupper()" should also work properly on 0x00 */
3755         tokens[0][0] = tolower(tokens[0][0]);
3756         for (i = 1; tokens[i] != NULL; i++)
3757                 tokens[i][0] = toupper(tokens[i][0]);
3758
3759         ret = talloc_strdup(mem_ctx, tokens[0]);
3760         for (i = 1; tokens[i] != NULL; i++)
3761                 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
3762
3763         talloc_free(tokens);
3764
3765         return ret;
3766 }
3767
3768 /*
3769  * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
3770  */
3771 int dsdb_functional_level(struct ldb_context *ldb)
3772 {
3773         int *domainFunctionality =
3774                 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
3775         if (!domainFunctionality) {
3776                 /* this is expected during initial provision */
3777                 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
3778                 return DS_DOMAIN_FUNCTION_2000;
3779         }
3780         return *domainFunctionality;
3781 }
3782
3783 /*
3784  * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
3785  */
3786 int dsdb_forest_functional_level(struct ldb_context *ldb)
3787 {
3788         int *forestFunctionality =
3789                 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
3790         if (!forestFunctionality) {
3791                 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
3792                 return DS_DOMAIN_FUNCTION_2000;
3793         }
3794         return *forestFunctionality;
3795 }
3796
3797 /*
3798   set a GUID in an extended DN structure
3799  */
3800 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
3801 {
3802         struct ldb_val v;
3803         NTSTATUS status;
3804         int ret;
3805
3806         status = GUID_to_ndr_blob(guid, dn, &v);
3807         if (!NT_STATUS_IS_OK(status)) {
3808                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
3809         }
3810
3811         ret = ldb_dn_set_extended_component(dn, component_name, &v);
3812         data_blob_free(&v);
3813         return ret;
3814 }
3815
3816 /*
3817   return a GUID from a extended DN structure
3818  */
3819 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
3820 {
3821         const struct ldb_val *v;
3822
3823         v = ldb_dn_get_extended_component(dn, component_name);
3824         if (v == NULL) {
3825                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3826         }
3827
3828         return GUID_from_ndr_blob(v, guid);
3829 }
3830
3831 /*
3832   return a uint64_t from a extended DN structure
3833  */
3834 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
3835 {
3836         const struct ldb_val *v;
3837
3838         v = ldb_dn_get_extended_component(dn, component_name);
3839         if (v == NULL) {
3840                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3841         }
3842
3843         /* Just check we don't allow the caller to fill our stack */
3844         if (v->length >= 64) {
3845                 return NT_STATUS_INVALID_PARAMETER;
3846         } else {
3847                 char s[v->length+1];
3848                 memcpy(s, v->data, v->length);
3849                 s[v->length] = 0;
3850
3851                 *val = strtoull(s, NULL, 0);
3852         }
3853         return NT_STATUS_OK;
3854 }
3855
3856 /*
3857   return a NTTIME from a extended DN structure
3858  */
3859 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
3860 {
3861         return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
3862 }
3863
3864 /*
3865   return a uint32_t from a extended DN structure
3866  */
3867 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
3868 {
3869         const struct ldb_val *v;
3870
3871         v = ldb_dn_get_extended_component(dn, component_name);
3872         if (v == NULL) {
3873                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3874         }
3875
3876         /* Just check we don't allow the caller to fill our stack */
3877         if (v->length >= 32) {
3878                 return NT_STATUS_INVALID_PARAMETER;
3879         } else {
3880                 char s[v->length + 1];
3881                 memcpy(s, v->data, v->length);
3882                 s[v->length] = 0;
3883                 *val = strtoul(s, NULL, 0);
3884         }
3885
3886         return NT_STATUS_OK;
3887 }
3888
3889 /*
3890   return a dom_sid from a extended DN structure
3891  */
3892 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
3893 {
3894         const struct ldb_val *sid_blob;
3895         enum ndr_err_code ndr_err;
3896
3897         sid_blob = ldb_dn_get_extended_component(dn, component_name);
3898         if (!sid_blob) {
3899                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3900         }
3901
3902         ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
3903                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
3904         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3905                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3906                 return status;
3907         }
3908
3909         return NT_STATUS_OK;
3910 }
3911
3912
3913 /*
3914   return RMD_FLAGS directly from a ldb_dn
3915   returns 0 if not found
3916  */
3917 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
3918 {
3919         uint32_t rmd_flags = 0;
3920         NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
3921                                                       "RMD_FLAGS");
3922         if (NT_STATUS_IS_OK(status)) {
3923                 return rmd_flags;
3924         }
3925         return 0;
3926 }
3927
3928 /*
3929   return RMD_FLAGS directly from a ldb_val for a DN
3930   returns 0 if RMD_FLAGS is not found
3931  */
3932 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
3933 {
3934         const char *p;
3935         uint32_t flags;
3936         char *end;
3937
3938         if (val->length < 13) {
3939                 return 0;
3940         }
3941         p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
3942         if (!p) {
3943                 return 0;
3944         }
3945         flags = strtoul(p+11, &end, 10);
3946         if (!end || *end != '>') {
3947                 /* it must end in a > */
3948                 return 0;
3949         }
3950         return flags;
3951 }
3952
3953 /*
3954   return true if a ldb_val containing a DN in storage form is deleted
3955  */
3956 bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
3957 {
3958         return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
3959 }
3960
3961 /*
3962   return true if a ldb_val containing a DN in storage form is
3963   in the upgraded w2k3 linked attribute format
3964  */
3965 bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
3966 {
3967         return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
3968 }
3969
3970 /*
3971   return a DN for a wellknown GUID
3972  */
3973 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
3974                       struct ldb_dn *nc_root, const char *wk_guid,
3975                       struct ldb_dn **wkguid_dn)
3976 {
3977         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3978         const char *attrs[] = { NULL };
3979         int ret;
3980         struct ldb_dn *dn;
3981         struct ldb_result *res;
3982
3983         /* construct the magic WKGUID DN */
3984         dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
3985                             wk_guid, ldb_dn_get_linearized(nc_root));
3986         if (!wkguid_dn) {
3987                 talloc_free(tmp_ctx);
3988                 return ldb_operr(samdb);
3989         }
3990
3991         ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
3992                              DSDB_SEARCH_SHOW_DELETED |
3993                              DSDB_SEARCH_SHOW_RECYCLED);
3994         if (ret != LDB_SUCCESS) {
3995                 talloc_free(tmp_ctx);
3996                 return ret;
3997         }
3998
3999         (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
4000         talloc_free(tmp_ctx);
4001         return LDB_SUCCESS;
4002 }
4003
4004
4005 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
4006 {
4007         return ldb_dn_compare(*dn1, *dn2);
4008 }
4009
4010 /*
4011   find a NC root given a DN within the NC
4012  */
4013 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
4014                       struct ldb_dn **nc_root)
4015 {
4016         const char *root_attrs[] = { "namingContexts", NULL };
4017         TALLOC_CTX *tmp_ctx;
4018         int ret;
4019         struct ldb_message_element *el;
4020         struct ldb_result *root_res;
4021         unsigned int i;
4022         struct ldb_dn **nc_dns;
4023
4024         tmp_ctx = talloc_new(samdb);
4025         if (tmp_ctx == NULL) {
4026                 return ldb_oom(samdb);
4027         }
4028
4029         ret = ldb_search(samdb, tmp_ctx, &root_res,
4030                          ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
4031         if (ret != LDB_SUCCESS || root_res->count == 0) {
4032                 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
4033                 talloc_free(tmp_ctx);
4034                 return ret;
4035         }
4036
4037         el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
4038         if ((el == NULL) || (el->num_values < 3)) {
4039                 struct ldb_message *tmp_msg;
4040
4041                 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
4042
4043                 /* This generates a temporary list of NCs in order to let the
4044                  * provisioning work. */
4045                 tmp_msg = ldb_msg_new(tmp_ctx);
4046                 if (tmp_msg == NULL) {
4047                         talloc_free(tmp_ctx);
4048                         return ldb_oom(samdb);
4049                 }
4050                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4051                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
4052                 if (ret != LDB_SUCCESS) {
4053                         talloc_free(tmp_ctx);
4054                         return ret;
4055                 }
4056                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4057                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
4058                 if (ret != LDB_SUCCESS) {
4059                         talloc_free(tmp_ctx);
4060                         return ret;
4061                 }
4062                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4063                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
4064                 if (ret != LDB_SUCCESS) {
4065                         talloc_free(tmp_ctx);
4066                         return ret;
4067                 }
4068                 el = &tmp_msg->elements[0];
4069         }
4070
4071        nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
4072        if (!nc_dns) {
4073                talloc_free(tmp_ctx);
4074                return ldb_oom(samdb);
4075        }
4076
4077        for (i=0; i<el->num_values; i++) {
4078                nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
4079                if (nc_dns[i] == NULL) {
4080                        talloc_free(tmp_ctx);
4081                        return ldb_operr(samdb);
4082                }
4083        }
4084
4085        TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
4086
4087        for (i=0; i<el->num_values; i++) {
4088                if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
4089                        (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
4090                        talloc_free(tmp_ctx);
4091                        return LDB_SUCCESS;
4092                }
4093        }
4094
4095        talloc_free(tmp_ctx);
4096        return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4097 }
4098
4099
4100 /*
4101   find the deleted objects DN for any object, by looking for the NC
4102   root, then looking up the wellknown GUID
4103  */
4104 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
4105                                 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
4106                                 struct ldb_dn **do_dn)
4107 {
4108         struct ldb_dn *nc_root;
4109         int ret;
4110
4111         ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
4112         if (ret != LDB_SUCCESS) {
4113                 return ret;
4114         }
4115
4116         ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
4117         talloc_free(nc_root);
4118         return ret;
4119 }
4120
4121 /*
4122   return the tombstoneLifetime, in days
4123  */
4124 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
4125 {
4126         struct ldb_dn *dn;
4127         dn = ldb_get_config_basedn(ldb);
4128         if (!dn) {
4129                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4130         }
4131         dn = ldb_dn_copy(ldb, dn);
4132         if (!dn) {
4133                 return ldb_operr(ldb);
4134         }
4135         /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
4136          be a wellknown GUID for this */
4137         if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
4138                 talloc_free(dn);
4139                 return ldb_operr(ldb);
4140         }
4141
4142         *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
4143         talloc_free(dn);
4144         return LDB_SUCCESS;
4145 }
4146
4147 /*
4148   compare a ldb_val to a string case insensitively
4149  */
4150 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
4151 {
4152         size_t len = strlen(s);
4153         int ret;
4154         if (len > v->length) return 1;
4155         ret = strncasecmp(s, (const char *)v->data, v->length);
4156         if (ret != 0) return ret;
4157         if (v->length > len && v->data[len] != 0) {
4158                 return -1;
4159         }
4160         return 0;
4161 }
4162
4163
4164 /*
4165   load the UDV for a partition in v2 format
4166   The list is returned sorted, and with our local cursor added
4167  */
4168 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4169                      struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
4170 {
4171         static const char *attrs[] = { "replUpToDateVector", NULL };
4172         struct ldb_result *r;
4173         const struct ldb_val *ouv_value;
4174         unsigned int i;
4175         int ret;
4176         uint64_t highest_usn = 0;
4177         const struct GUID *our_invocation_id;
4178         static const struct timeval tv1970;
4179         NTTIME nt1970 = timeval_to_nttime(&tv1970);
4180
4181         ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
4182         if (ret != LDB_SUCCESS) {
4183                 return ret;
4184         }
4185
4186         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
4187         if (ouv_value) {
4188                 enum ndr_err_code ndr_err;
4189                 struct replUpToDateVectorBlob ouv;
4190
4191                 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
4192                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4193                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4194                         talloc_free(r);
4195                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4196                 }
4197                 if (ouv.version != 2) {
4198                         /* we always store as version 2, and
4199                          * replUpToDateVector is not replicated
4200                          */
4201                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4202                 }
4203
4204                 *count = ouv.ctr.ctr2.count;
4205                 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
4206         } else {
4207                 *count = 0;
4208                 *cursors = NULL;
4209         }
4210
4211         talloc_free(r);
4212
4213         our_invocation_id = samdb_ntds_invocation_id(samdb);
4214         if (!our_invocation_id) {
4215                 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
4216                 talloc_free(*cursors);
4217                 return ldb_operr(samdb);
4218         }
4219
4220         ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
4221         if (ret != LDB_SUCCESS) {
4222                 /* nothing to add - this can happen after a vampire */
4223                 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4224                 return LDB_SUCCESS;
4225         }
4226
4227         for (i=0; i<*count; i++) {
4228                 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
4229                         (*cursors)[i].highest_usn = highest_usn;
4230                         (*cursors)[i].last_sync_success = nt1970;
4231                         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4232                         return LDB_SUCCESS;
4233                 }
4234         }
4235
4236         (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
4237         if (! *cursors) {
4238                 return ldb_oom(samdb);
4239         }
4240
4241         (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
4242         (*cursors)[*count].highest_usn = highest_usn;
4243         (*cursors)[*count].last_sync_success = nt1970;
4244         (*count)++;
4245
4246         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
4247
4248         return LDB_SUCCESS;
4249 }
4250
4251 /*
4252   load the UDV for a partition in version 1 format
4253   The list is returned sorted, and with our local cursor added
4254  */
4255 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
4256                      struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
4257 {
4258         struct drsuapi_DsReplicaCursor2 *v2;
4259         uint32_t i;
4260         int ret;
4261
4262         ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
4263         if (ret != LDB_SUCCESS) {
4264                 return ret;
4265         }
4266
4267         if (*count == 0) {
4268                 talloc_free(v2);
4269                 *cursors = NULL;
4270                 return LDB_SUCCESS;
4271         }
4272
4273         *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
4274         if (*cursors == NULL) {
4275                 talloc_free(v2);
4276                 return ldb_oom(samdb);
4277         }
4278
4279         for (i=0; i<*count; i++) {
4280                 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
4281                 (*cursors)[i].highest_usn = v2[i].highest_usn;
4282         }
4283         talloc_free(v2);
4284         return LDB_SUCCESS;
4285 }
4286
4287 /*
4288   add a set of controls to a ldb_request structure based on a set of
4289   flags. See util.h for a list of available flags
4290  */
4291 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
4292 {
4293         int ret;
4294         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
4295                 struct ldb_search_options_control *options;
4296                 /* Using the phantom root control allows us to search all partitions */
4297                 options = talloc(req, struct ldb_search_options_control);
4298                 if (options == NULL) {
4299                         return LDB_ERR_OPERATIONS_ERROR;
4300                 }
4301                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4302
4303                 ret = ldb_request_add_control(req,
4304                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
4305                                               true, options);
4306                 if (ret != LDB_SUCCESS) {
4307                         return ret;
4308                 }
4309         }
4310
4311         if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
4312                 ret = ldb_request_add_control(req,
4313                                               DSDB_CONTROL_NO_GLOBAL_CATALOG,
4314                                               false, NULL);
4315                 if (ret != LDB_SUCCESS) {
4316                         return ret;
4317                 }
4318         }
4319
4320         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
4321                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
4322                 if (ret != LDB_SUCCESS) {
4323                         return ret;
4324                 }
4325         }
4326
4327         if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
4328                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
4329                 if (ret != LDB_SUCCESS) {
4330                         return ret;
4331                 }
4332         }
4333
4334         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
4335                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
4336                 if (ret != LDB_SUCCESS) {
4337                         return ret;
4338                 }
4339         }
4340
4341         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
4342                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
4343                 if (!extended_ctrl) {
4344                         return LDB_ERR_OPERATIONS_ERROR;
4345                 }
4346                 extended_ctrl->type = 1;
4347
4348                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
4349                 if (ret != LDB_SUCCESS) {
4350                         return ret;
4351                 }
4352         }
4353
4354         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
4355                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
4356                 if (ret != LDB_SUCCESS) {
4357                         return ret;
4358                 }
4359         }
4360
4361         if (dsdb_flags & DSDB_MODIFY_RELAX) {
4362                 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
4363                 if (ret != LDB_SUCCESS) {
4364                         return ret;
4365                 }
4366         }
4367
4368         if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
4369                 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
4370                 if (ret != LDB_SUCCESS) {
4371                         return ret;
4372                 }
4373         }
4374
4375         if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
4376                 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
4377                 if (ret != LDB_SUCCESS) {
4378                         return ret;
4379                 }
4380         }
4381
4382         if (dsdb_flags & DSDB_TREE_DELETE) {
4383                 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
4384                 if (ret != LDB_SUCCESS) {
4385                         return ret;
4386                 }
4387         }
4388
4389         if (dsdb_flags & DSDB_PROVISION) {
4390                 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
4391                 if (ret != LDB_SUCCESS) {
4392                         return ret;
4393                 }
4394         }
4395
4396         /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
4397         if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
4398                 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
4399                 if (ret != LDB_SUCCESS) {
4400                         return ret;
4401                 }
4402         }
4403
4404         if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
4405                 /* 
4406                  * This must not be critical, as it will only be
4407                  * handled (and need to be handled) if the other
4408                  * attributes in the request bring password_hash into
4409                  * action
4410                  */
4411                 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
4412                 if (ret != LDB_SUCCESS) {
4413                         return ret;
4414                 }
4415         }
4416
4417         if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
4418                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
4419                 if (ret != LDB_SUCCESS) {
4420                         return ret;
4421                 }
4422         }
4423
4424         if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
4425                 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
4426                 if (ret != LDB_SUCCESS) {
4427                         return ret;
4428                 }
4429         }
4430
4431         if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
4432                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4433                 if (ret != LDB_SUCCESS) {
4434                         return ret;
4435                 }
4436         }
4437
4438         return LDB_SUCCESS;
4439 }
4440
4441 /*
4442    returns true if a control with the specified "oid" exists
4443 */
4444 bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
4445 {
4446         return (ldb_request_get_control(req, oid) != NULL);
4447 }
4448
4449 /*
4450   an add with a set of controls
4451 */
4452 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
4453              uint32_t dsdb_flags)
4454 {
4455         struct ldb_request *req;
4456         int ret;
4457
4458         ret = ldb_build_add_req(&req, ldb, ldb,
4459                                 message,
4460                                 NULL,
4461                                 NULL,
4462                                 ldb_op_default_callback,
4463                                 NULL);
4464
4465         if (ret != LDB_SUCCESS) return ret;
4466
4467         ret = dsdb_request_add_controls(req, dsdb_flags);
4468         if (ret != LDB_SUCCESS) {
4469                 talloc_free(req);
4470                 return ret;
4471         }
4472
4473         ret = dsdb_autotransaction_request(ldb, req);
4474
4475         talloc_free(req);
4476         return ret;
4477 }
4478
4479 /*
4480   a modify with a set of controls
4481 */
4482 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
4483                 uint32_t dsdb_flags)
4484 {
4485         struct ldb_request *req;
4486         int ret;
4487
4488         ret = ldb_build_mod_req(&req, ldb, ldb,
4489                                 message,
4490                                 NULL,
4491                                 NULL,
4492                                 ldb_op_default_callback,
4493                                 NULL);
4494
4495         if (ret != LDB_SUCCESS) return ret;
4496
4497         ret = dsdb_request_add_controls(req, dsdb_flags);
4498         if (ret != LDB_SUCCESS) {
4499                 talloc_free(req);
4500                 return ret;
4501         }
4502
4503         ret = dsdb_autotransaction_request(ldb, req);
4504
4505         talloc_free(req);
4506         return ret;
4507 }
4508
4509 /*
4510   a delete with a set of flags
4511 */
4512 int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
4513                 uint32_t dsdb_flags)
4514 {
4515         struct ldb_request *req;
4516         int ret;
4517
4518         ret = ldb_build_del_req(&req, ldb, ldb,
4519                                 dn,
4520                                 NULL,
4521                                 NULL,
4522                                 ldb_op_default_callback,
4523                                 NULL);
4524
4525         if (ret != LDB_SUCCESS) return ret;
4526
4527         ret = dsdb_request_add_controls(req, dsdb_flags);
4528         if (ret != LDB_SUCCESS) {
4529                 talloc_free(req);
4530                 return ret;
4531         }
4532
4533         ret = dsdb_autotransaction_request(ldb, req);
4534
4535         talloc_free(req);
4536         return ret;
4537 }
4538
4539 /*
4540   like dsdb_modify() but set all the element flags to
4541   LDB_FLAG_MOD_REPLACE
4542  */
4543 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
4544 {
4545         unsigned int i;
4546
4547         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
4548         for (i=0;i<msg->num_elements;i++) {
4549                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4550         }
4551
4552         return dsdb_modify(ldb, msg, dsdb_flags);
4553 }
4554
4555
4556 /*
4557   search for attrs on one DN, allowing for dsdb_flags controls
4558  */
4559 int dsdb_search_dn(struct ldb_context *ldb,
4560                    TALLOC_CTX *mem_ctx,
4561                    struct ldb_result **_result,
4562                    struct ldb_dn *basedn,
4563                    const char * const *attrs,
4564                    uint32_t dsdb_flags)
4565 {
4566         int ret;
4567         struct ldb_request *req;
4568         struct ldb_result *res;
4569
4570         res = talloc_zero(mem_ctx, struct ldb_result);
4571         if (!res) {
4572                 return ldb_oom(ldb);
4573         }
4574
4575         ret = ldb_build_search_req(&req, ldb, res,
4576                                    basedn,
4577                                    LDB_SCOPE_BASE,
4578                                    NULL,
4579                                    attrs,
4580                                    NULL,
4581                                    res,
4582                                    ldb_search_default_callback,
4583                                    NULL);
4584         if (ret != LDB_SUCCESS) {
4585                 talloc_free(res);
4586                 return ret;
4587         }
4588
4589         ret = dsdb_request_add_controls(req, dsdb_flags);
4590         if (ret != LDB_SUCCESS) {
4591                 talloc_free(res);
4592                 return ret;
4593         }
4594
4595         ret = ldb_request(ldb, req);
4596         if (ret == LDB_SUCCESS) {
4597                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4598         }
4599
4600         talloc_free(req);
4601         if (ret != LDB_SUCCESS) {
4602                 talloc_free(res);
4603                 return ret;
4604         }
4605
4606         *_result = res;
4607         return LDB_SUCCESS;
4608 }
4609
4610 /*
4611   search for attrs on one DN, by the GUID of the DN, allowing for
4612   dsdb_flags controls
4613  */
4614 int dsdb_search_by_dn_guid(struct ldb_context *ldb,
4615                            TALLOC_CTX *mem_ctx,
4616                            struct ldb_result **_result,
4617                            const struct GUID *guid,
4618                            const char * const *attrs,
4619                            uint32_t dsdb_flags)
4620 {
4621         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4622         struct ldb_dn *dn;
4623         int ret;
4624
4625         dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
4626         if (dn == NULL) {
4627                 talloc_free(tmp_ctx);
4628                 return ldb_oom(ldb);
4629         }
4630
4631         ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
4632         talloc_free(tmp_ctx);
4633         return ret;
4634 }
4635
4636 /*
4637   general search with dsdb_flags for controls
4638  */
4639 int dsdb_search(struct ldb_context *ldb,
4640                 TALLOC_CTX *mem_ctx,
4641                 struct ldb_result **_result,
4642                 struct ldb_dn *basedn,
4643                 enum ldb_scope scope,
4644                 const char * const *attrs,
4645                 uint32_t dsdb_flags,
4646                 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4647 {
4648         int ret;
4649         struct ldb_request *req;
4650         struct ldb_result *res;
4651         va_list ap;
4652         char *expression = NULL;
4653         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4654
4655         /* cross-partitions searches with a basedn break multi-domain support */
4656         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
4657
4658         res = talloc_zero(tmp_ctx, struct ldb_result);
4659         if (!res) {
4660                 talloc_free(tmp_ctx);
4661                 return ldb_oom(ldb);
4662         }
4663
4664         if (exp_fmt) {
4665                 va_start(ap, exp_fmt);
4666                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4667                 va_end(ap);
4668
4669                 if (!expression) {
4670                         talloc_free(tmp_ctx);
4671                         return ldb_oom(ldb);
4672                 }
4673         }
4674
4675         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
4676                                    basedn,
4677                                    scope,
4678                                    expression,
4679                                    attrs,
4680                                    NULL,
4681                                    res,
4682                                    ldb_search_default_callback,
4683                                    NULL);
4684         if (ret != LDB_SUCCESS) {
4685                 talloc_free(tmp_ctx);
4686                 return ret;
4687         }
4688
4689         ret = dsdb_request_add_controls(req, dsdb_flags);
4690         if (ret != LDB_SUCCESS) {
4691                 talloc_free(tmp_ctx);
4692                 ldb_reset_err_string(ldb);
4693                 return ret;
4694         }
4695
4696         ret = ldb_request(ldb, req);
4697         if (ret == LDB_SUCCESS) {
4698                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4699         }
4700
4701         if (ret != LDB_SUCCESS) {
4702                 talloc_free(tmp_ctx);
4703                 return ret;
4704         }
4705
4706         if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
4707                 if (res->count == 0) {
4708                         talloc_free(tmp_ctx);
4709                         ldb_reset_err_string(ldb);
4710                         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4711                 }
4712                 if (res->count != 1) {
4713                         talloc_free(tmp_ctx);
4714                         ldb_reset_err_string(ldb);
4715                         return LDB_ERR_CONSTRAINT_VIOLATION;
4716                 }
4717         }
4718
4719         *_result = talloc_steal(mem_ctx, res);
4720         talloc_free(tmp_ctx);
4721
4722         return LDB_SUCCESS;
4723 }
4724
4725
4726 /*
4727   general search with dsdb_flags for controls
4728   returns exactly 1 record or an error
4729  */
4730 int dsdb_search_one(struct ldb_context *ldb,
4731                     TALLOC_CTX *mem_ctx,
4732                     struct ldb_message **msg,
4733                     struct ldb_dn *basedn,
4734                     enum ldb_scope scope,
4735                     const char * const *attrs,
4736                     uint32_t dsdb_flags,
4737                     const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
4738 {
4739         int ret;
4740         struct ldb_result *res;
4741         va_list ap;
4742         char *expression = NULL;
4743         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4744
4745         dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
4746
4747         res = talloc_zero(tmp_ctx, struct ldb_result);
4748         if (!res) {
4749                 talloc_free(tmp_ctx);
4750                 return ldb_oom(ldb);
4751         }
4752
4753         if (exp_fmt) {
4754                 va_start(ap, exp_fmt);
4755                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
4756                 va_end(ap);
4757
4758                 if (!expression) {
4759                         talloc_free(tmp_ctx);
4760                         return ldb_oom(ldb);
4761                 }
4762                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4763                                   dsdb_flags, "%s", expression);
4764         } else {
4765                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
4766                                   dsdb_flags, NULL);
4767         }
4768
4769         if (ret != LDB_SUCCESS) {
4770                 talloc_free(tmp_ctx);
4771                 return ret;
4772         }
4773
4774         *msg = talloc_steal(mem_ctx, res->msgs[0]);
4775         talloc_free(tmp_ctx);
4776
4777         return LDB_SUCCESS;
4778 }
4779
4780 /* returns back the forest DNS name */
4781 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4782 {
4783         const char *forest_name = ldb_dn_canonical_string(mem_ctx,
4784                                                           ldb_get_root_basedn(ldb));
4785         char *p;
4786
4787         if (forest_name == NULL) {
4788                 return NULL;
4789         }
4790
4791         p = strchr(forest_name, '/');
4792         if (p) {
4793                 *p = '\0';
4794         }
4795
4796         return forest_name;
4797 }
4798
4799 /* returns back the default domain DNS name */
4800 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
4801 {
4802         const char *domain_name = ldb_dn_canonical_string(mem_ctx,
4803                                                           ldb_get_default_basedn(ldb));
4804         char *p;
4805
4806         if (domain_name == NULL) {
4807                 return NULL;
4808         }
4809
4810         p = strchr(domain_name, '/');
4811         if (p) {
4812                 *p = '\0';
4813         }
4814
4815         return domain_name;
4816 }
4817
4818 /*
4819    validate that an DSA GUID belongs to the specified user sid.
4820    The user SID must be a domain controller account (either RODC or
4821    RWDC)
4822  */
4823 int dsdb_validate_dsa_guid(struct ldb_context *ldb,
4824                            const struct GUID *dsa_guid,
4825                            const struct dom_sid *sid)
4826 {
4827         /* strategy:
4828             - find DN of record with the DSA GUID in the
4829               configuration partition (objectGUID)
4830             - remove "NTDS Settings" component from DN
4831             - do a base search on that DN for serverReference with
4832               extended-dn enabled
4833             - extract objectSid from resulting serverReference
4834               attribute
4835             - check this sid matches the sid argument
4836         */
4837         struct ldb_dn *config_dn;
4838         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
4839         struct ldb_message *msg;
4840         const char *attrs1[] = { NULL };
4841         const char *attrs2[] = { "serverReference", NULL };
4842         int ret;
4843         struct ldb_dn *dn, *account_dn;
4844         struct dom_sid sid2;
4845         NTSTATUS status;
4846
4847         config_dn = ldb_get_config_basedn(ldb);
4848
4849         ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
4850                               attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
4851         if (ret != LDB_SUCCESS) {
4852                 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
4853                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4854                 talloc_free(tmp_ctx);
4855                 return ldb_operr(ldb);
4856         }
4857         dn = msg->dn;
4858
4859         if (!ldb_dn_remove_child_components(dn, 1)) {
4860                 talloc_free(tmp_ctx);
4861                 return ldb_operr(ldb);
4862         }
4863
4864         ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
4865                               attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
4866                               "(objectClass=server)");
4867         if (ret != LDB_SUCCESS) {
4868                 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
4869                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4870                 talloc_free(tmp_ctx);
4871                 return ldb_operr(ldb);
4872         }
4873
4874         account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
4875         if (account_dn == NULL) {
4876                 DEBUG(1,(__location__ ": Failed to find account dn "
4877                          "(serverReference) for %s, parent of DSA with "
4878                          "objectGUID %s, sid %s\n",
4879                          ldb_dn_get_linearized(msg->dn),
4880                          GUID_string(tmp_ctx, dsa_guid),
4881                          dom_sid_string(tmp_ctx, sid)));
4882                 talloc_free(tmp_ctx);
4883                 return ldb_operr(ldb);
4884         }
4885
4886         status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
4887         if (!NT_STATUS_IS_OK(status)) {
4888                 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
4889                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
4890                 talloc_free(tmp_ctx);
4891                 return ldb_operr(ldb);
4892         }
4893
4894         if (!dom_sid_equal(sid, &sid2)) {
4895                 /* someone is trying to spoof another account */
4896                 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
4897                          GUID_string(tmp_ctx, dsa_guid),
4898                          dom_sid_string(tmp_ctx, sid),
4899                          dom_sid_string(tmp_ctx, &sid2)));
4900                 talloc_free(tmp_ctx);
4901                 return ldb_operr(ldb);
4902         }
4903
4904         talloc_free(tmp_ctx);
4905         return LDB_SUCCESS;
4906 }
4907
4908 static const char * const secret_attributes[] = {
4909         DSDB_SECRET_ATTRIBUTES,
4910         NULL
4911 };
4912
4913 /*
4914   check if the attribute belongs to the RODC filtered attribute set
4915   Note that attributes that are in the filtered attribute set are the
4916   ones that _are_ always sent to a RODC
4917 */
4918 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
4919 {
4920         /* they never get secret attributes */
4921         if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
4922                 return false;
4923         }
4924
4925         /* they do get non-secret critical attributes */
4926         if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
4927                 return true;
4928         }
4929
4930         /* they do get non-secret attributes marked as being in the FAS  */
4931         if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
4932                 return true;
4933         }
4934
4935         /* other attributes are denied */
4936         return false;
4937 }
4938
4939 /* return fsmo role dn and role owner dn for a particular role*/
4940 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
4941                                struct ldb_context *ldb,
4942                                uint32_t role,
4943                                struct ldb_dn **fsmo_role_dn,
4944                                struct ldb_dn **role_owner_dn)
4945 {
4946         int ret;
4947         switch (role) {
4948         case DREPL_NAMING_MASTER:
4949                 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
4950                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4951                 if (ret != LDB_SUCCESS) {
4952                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
4953                                  ldb_errstring(ldb)));
4954                         talloc_free(tmp_ctx);
4955                         return WERR_DS_DRA_INTERNAL_ERROR;
4956                 }
4957                 break;
4958         case DREPL_INFRASTRUCTURE_MASTER:
4959                 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
4960                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4961                 if (ret != LDB_SUCCESS) {
4962                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4963                                  ldb_errstring(ldb)));
4964                         talloc_free(tmp_ctx);
4965                         return WERR_DS_DRA_INTERNAL_ERROR;
4966                 }
4967                 break;
4968         case DREPL_RID_MASTER:
4969                 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
4970                 if (ret != LDB_SUCCESS) {
4971                         DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
4972                         talloc_free(tmp_ctx);
4973                         return WERR_DS_DRA_INTERNAL_ERROR;
4974                 }
4975
4976                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4977                 if (ret != LDB_SUCCESS) {
4978                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
4979                                  ldb_errstring(ldb)));
4980                         talloc_free(tmp_ctx);
4981                         return WERR_DS_DRA_INTERNAL_ERROR;
4982                 }
4983                 break;
4984         case DREPL_SCHEMA_MASTER:
4985                 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
4986                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4987                 if (ret != LDB_SUCCESS) {
4988                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
4989                                  ldb_errstring(ldb)));
4990                         talloc_free(tmp_ctx);
4991                         return WERR_DS_DRA_INTERNAL_ERROR;
4992                 }
4993                 break;
4994         case DREPL_PDC_MASTER:
4995                 *fsmo_role_dn = ldb_get_default_basedn(ldb);
4996                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
4997                 if (ret != LDB_SUCCESS) {
4998                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
4999                                  ldb_errstring(ldb)));
5000                         talloc_free(tmp_ctx);
5001                         return WERR_DS_DRA_INTERNAL_ERROR;
5002                 }
5003                 break;
5004         default:
5005                 return WERR_DS_DRA_INTERNAL_ERROR;
5006         }
5007         return WERR_OK;
5008 }
5009
5010 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
5011                                     TALLOC_CTX *mem_ctx,
5012                                     struct ldb_dn *server_dn)
5013 {
5014         int ldb_ret;
5015         struct ldb_result *res = NULL;
5016         const char * const attrs[] = { "dNSHostName", NULL};
5017
5018         ldb_ret = ldb_search(ldb, mem_ctx, &res,
5019                              server_dn,
5020                              LDB_SCOPE_BASE,
5021                              attrs, NULL);
5022         if (ldb_ret != LDB_SUCCESS) {
5023                 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
5024                           ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
5025                 return NULL;
5026         }
5027
5028         return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
5029 }
5030
5031 /*
5032   returns true if an attribute is in the filter,
5033   false otherwise, provided that attribute value is provided with the expression
5034 */
5035 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
5036                              const char *attr)
5037 {
5038        unsigned int i;
5039        switch (tree->operation) {
5040        case LDB_OP_AND:
5041        case LDB_OP_OR:
5042                for (i=0;i<tree->u.list.num_elements;i++) {
5043                        if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
5044                                                        attr))
5045                                return true;
5046                }
5047                return false;
5048        case LDB_OP_NOT:
5049                return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
5050        case LDB_OP_EQUALITY:
5051        case LDB_OP_GREATER:
5052        case LDB_OP_LESS:
5053        case LDB_OP_APPROX:
5054                if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
5055                        return true;
5056                }
5057                return false;
5058        case LDB_OP_SUBSTRING:
5059                if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
5060                        return true;
5061                }
5062                return false;
5063        case LDB_OP_PRESENT:
5064                /* (attrname=*) is not filtered out */
5065                return false;
5066        case LDB_OP_EXTENDED:
5067                if (tree->u.extended.attr &&
5068                    ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
5069                        return true;
5070                }
5071                return false;
5072        }
5073        return false;
5074 }
5075
5076 bool is_attr_in_list(const char * const * attrs, const char *attr)
5077 {
5078         unsigned int i;
5079
5080         for (i = 0; attrs[i]; i++) {
5081                 if (ldb_attr_cmp(attrs[i], attr) == 0)
5082                         return true;
5083         }
5084
5085         return false;
5086 }
5087
5088 int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
5089                    const char *location, const char *func,
5090                    const char *reason)
5091 {
5092         if (reason == NULL) {
5093                 reason = win_errstr(werr);
5094         }
5095         ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
5096                                W_ERROR_V(werr), reason, location, func);
5097         return ldb_ecode;
5098 }
5099
5100 /*
5101   map an ldb error code to an approximate NTSTATUS code
5102  */
5103 NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
5104 {
5105         switch (err) {
5106         case LDB_SUCCESS:
5107                 return NT_STATUS_OK;
5108
5109         case LDB_ERR_PROTOCOL_ERROR:
5110                 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
5111
5112         case LDB_ERR_TIME_LIMIT_EXCEEDED:
5113                 return NT_STATUS_IO_TIMEOUT;
5114
5115         case LDB_ERR_SIZE_LIMIT_EXCEEDED:
5116                 return NT_STATUS_BUFFER_TOO_SMALL;
5117
5118         case LDB_ERR_COMPARE_FALSE:
5119         case LDB_ERR_COMPARE_TRUE:
5120                 return NT_STATUS_REVISION_MISMATCH;
5121
5122         case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
5123                 return NT_STATUS_NOT_SUPPORTED;
5124
5125         case LDB_ERR_STRONG_AUTH_REQUIRED:
5126         case LDB_ERR_CONFIDENTIALITY_REQUIRED:
5127         case LDB_ERR_SASL_BIND_IN_PROGRESS:
5128         case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
5129         case LDB_ERR_INVALID_CREDENTIALS:
5130         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
5131         case LDB_ERR_UNWILLING_TO_PERFORM:
5132                 return NT_STATUS_ACCESS_DENIED;
5133
5134         case LDB_ERR_NO_SUCH_OBJECT:
5135                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5136
5137         case LDB_ERR_REFERRAL:
5138         case LDB_ERR_NO_SUCH_ATTRIBUTE:
5139                 return NT_STATUS_NOT_FOUND;
5140
5141         case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
5142                 return NT_STATUS_NOT_SUPPORTED;
5143
5144         case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
5145                 return NT_STATUS_BUFFER_TOO_SMALL;
5146
5147         case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
5148         case LDB_ERR_INAPPROPRIATE_MATCHING:
5149         case LDB_ERR_CONSTRAINT_VIOLATION:
5150         case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
5151         case LDB_ERR_INVALID_DN_SYNTAX:
5152         case LDB_ERR_NAMING_VIOLATION:
5153         case LDB_ERR_OBJECT_CLASS_VIOLATION:
5154         case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
5155         case LDB_ERR_NOT_ALLOWED_ON_RDN:
5156                 return NT_STATUS_INVALID_PARAMETER;
5157
5158         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
5159         case LDB_ERR_ENTRY_ALREADY_EXISTS:
5160                 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
5161
5162         case LDB_ERR_BUSY:
5163                 return NT_STATUS_NETWORK_BUSY;
5164
5165         case LDB_ERR_ALIAS_PROBLEM:
5166         case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
5167         case LDB_ERR_UNAVAILABLE:
5168         case LDB_ERR_LOOP_DETECT:
5169         case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
5170         case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
5171         case LDB_ERR_OTHER:
5172         case LDB_ERR_OPERATIONS_ERROR:
5173                 break;
5174         }
5175         return NT_STATUS_UNSUCCESSFUL;
5176 }
5177
5178
5179 /*
5180   create a new naming context that will hold a partial replica
5181  */
5182 int dsdb_create_partial_replica_NC(struct ldb_context *ldb,  struct ldb_dn *dn)
5183 {
5184         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5185         struct ldb_message *msg;
5186         int ret;
5187
5188         msg = ldb_msg_new(tmp_ctx);
5189         if (msg == NULL) {
5190                 talloc_free(tmp_ctx);
5191                 return ldb_oom(ldb);
5192         }
5193
5194         msg->dn = dn;
5195         ret = ldb_msg_add_string(msg, "objectClass", "top");
5196         if (ret != LDB_SUCCESS) {
5197                 talloc_free(tmp_ctx);
5198                 return ldb_oom(ldb);
5199         }
5200
5201         /* [MS-DRSR] implies that we should only add the 'top'
5202          * objectclass, but that would cause lots of problems with our
5203          * objectclass code as top is not structural, so we add
5204          * 'domainDNS' as well to keep things sane. We're expecting
5205          * this new NC to be of objectclass domainDNS after
5206          * replication anyway
5207          */
5208         ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
5209         if (ret != LDB_SUCCESS) {
5210                 talloc_free(tmp_ctx);
5211                 return ldb_oom(ldb);
5212         }
5213
5214         ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
5215                               INSTANCE_TYPE_IS_NC_HEAD|
5216                               INSTANCE_TYPE_NC_ABOVE|
5217                               INSTANCE_TYPE_UNINSTANT);
5218         if (ret != LDB_SUCCESS) {
5219                 talloc_free(tmp_ctx);
5220                 return ldb_oom(ldb);
5221         }
5222
5223         ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
5224         if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5225                 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
5226                          ldb_dn_get_linearized(dn),
5227                          ldb_errstring(ldb), ldb_strerror(ret)));
5228                 talloc_free(tmp_ctx);
5229                 return ret;
5230         }
5231
5232         DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
5233
5234         talloc_free(tmp_ctx);
5235         return LDB_SUCCESS;
5236 }
5237
5238 /**
5239   build a GUID from a string
5240 */
5241 _PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid)
5242 {
5243         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
5244         uint32_t time_low;
5245         uint32_t time_mid, time_hi_and_version;
5246         uint32_t clock_seq[2];
5247         uint32_t node[6];
5248         int i;
5249
5250         if (s == NULL) {
5251                 return NT_STATUS_INVALID_PARAMETER;
5252         }
5253
5254         status =  parse_guid_string(s,
5255                                     &time_low,
5256                                     &time_mid,
5257                                     &time_hi_and_version,
5258                                     clock_seq,
5259                                     node);
5260
5261         if (!NT_STATUS_IS_OK(status)) {
5262                 return status;
5263         }
5264
5265         guid->time_low = time_low;
5266         guid->time_mid = time_mid;
5267         guid->time_hi_and_version = time_hi_and_version;
5268         guid->clock_seq[0] = clock_seq[0];
5269         guid->clock_seq[1] = clock_seq[1];
5270         for (i=0;i<6;i++) {
5271                 guid->node[i] = node[i];
5272         }
5273
5274         return NT_STATUS_OK;
5275 }
5276
5277 _PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
5278 {
5279         return talloc_asprintf(mem_ctx, 
5280                                "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x",
5281                                guid->time_low, guid->time_mid,
5282                                guid->time_hi_and_version,
5283                                guid->clock_seq[0],
5284                                guid->clock_seq[1],
5285                                guid->node[0], guid->node[1],
5286                                guid->node[2], guid->node[3],
5287                                guid->node[4], guid->node[5]);
5288 }
5289
5290 /*
5291  * Return the effective badPwdCount
5292  *
5293  * This requires that the user_msg have (if present):
5294  *  - badPasswordTime
5295  *  - badPwdCount
5296  *
5297  * This also requires that the domain_msg have (if present):
5298  *  - lockOutObservationWindow
5299  */
5300 static int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
5301                                       int64_t lockOutObservationWindow,
5302                                       NTTIME now)
5303 {
5304         int64_t badPasswordTime;
5305         badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
5306
5307         if (badPasswordTime - lockOutObservationWindow >= now) {
5308                 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
5309         } else {
5310                 return 0;
5311         }
5312 }
5313
5314 /*
5315  * Returns a user's PSO, or NULL if none was found
5316  */
5317 static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
5318                                           TALLOC_CTX *mem_ctx,
5319                                           const struct ldb_message *user_msg,
5320                                           const char * const *attrs)
5321 {
5322         struct ldb_result *res = NULL;
5323         struct ldb_dn *pso_dn = NULL;
5324         int ret;
5325
5326         /* if the user has a PSO that applies, then use the PSO's setting */
5327         pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
5328                                          "msDS-ResultantPSO");
5329
5330         if (pso_dn != NULL) {
5331
5332                 ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
5333                 if (ret != LDB_SUCCESS) {
5334
5335                         /*
5336                          * log the error. The caller should fallback to using
5337                          * the default domain password settings
5338                          */
5339                         DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s",
5340                                 ldb_dn_get_linearized(pso_dn),
5341                                 ldb_dn_get_linearized(user_msg->dn));
5342                 }
5343                 talloc_free(pso_dn);
5344         }
5345         return res;
5346 }
5347
5348 /*
5349  * Return the effective badPwdCount
5350  *
5351  * This requires that the user_msg have (if present):
5352  *  - badPasswordTime
5353  *  - badPwdCount
5354  *  - msDS-ResultantPSO
5355  */
5356 int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
5357                                        TALLOC_CTX *mem_ctx,
5358                                        struct ldb_dn *domain_dn,
5359                                        const struct ldb_message *user_msg)
5360 {
5361         struct timeval tv_now = timeval_current();
5362         NTTIME now = timeval_to_nttime(&tv_now);
5363         int64_t lockOutObservationWindow;
5364         struct ldb_result *res = NULL;
5365         const char *attrs[] = { "msDS-LockoutObservationWindow",
5366                                 NULL };
5367
5368         res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
5369
5370         if (res != NULL) {
5371                 lockOutObservationWindow =
5372                         ldb_msg_find_attr_as_int(res->msgs[0],
5373                                                  "msDS-LockoutObservationWindow",
5374                                                   0);
5375                 talloc_free(res);
5376         } else {
5377
5378                 /* no PSO was found, lookup the default domain setting */
5379                 lockOutObservationWindow =
5380                          samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
5381                                             "lockOutObservationWindow", NULL);
5382         }
5383
5384         return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5385 }
5386
5387 /*
5388  * Returns the lockoutThreshold that applies. If a PSO is specified, then that
5389  * setting is used over the domain defaults
5390  */
5391 static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
5392                                      struct ldb_message *pso_msg)
5393 {
5394         if (pso_msg != NULL) {
5395                 return ldb_msg_find_attr_as_int(pso_msg,
5396                                                 "msDS-LockoutThreshold", 0);
5397         } else {
5398                 return ldb_msg_find_attr_as_int(domain_msg,
5399                                                 "lockoutThreshold", 0);
5400         }
5401 }
5402
5403 /*
5404  * Returns the lockOutObservationWindow that applies. If a PSO is specified,
5405  * then that setting is used over the domain defaults
5406  */
5407 static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
5408                                               struct ldb_message *pso_msg)
5409 {
5410         if (pso_msg != NULL) {
5411                 return ldb_msg_find_attr_as_int(pso_msg,
5412                                                 "msDS-LockoutObservationWindow",
5413                                                  0);
5414         } else {
5415                 return ldb_msg_find_attr_as_int(domain_msg,
5416                                                 "lockOutObservationWindow", 0);
5417         }
5418 }
5419
5420 /*
5421  * Prepare an update to the badPwdCount and associated attributes.
5422  *
5423  * This requires that the user_msg have (if present):
5424  *  - objectSid
5425  *  - badPasswordTime
5426  *  - badPwdCount
5427  *
5428  * This also requires that the domain_msg have (if present):
5429  *  - pwdProperties
5430  *  - lockoutThreshold
5431  *  - lockOutObservationWindow
5432  *
5433  * This also requires that the pso_msg have (if present):
5434  *  - msDS-LockoutThreshold
5435  *  - msDS-LockoutObservationWindow
5436  */
5437 NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
5438                                    struct ldb_context *sam_ctx,
5439                                    struct ldb_message *user_msg,
5440                                    struct ldb_message *domain_msg,
5441                                    struct ldb_message *pso_msg,
5442                                    struct ldb_message **_mod_msg)
5443 {
5444         int i, ret, badPwdCount;
5445         int64_t lockoutThreshold, lockOutObservationWindow;
5446         struct dom_sid *sid;
5447         struct timeval tv_now = timeval_current();
5448         NTTIME now = timeval_to_nttime(&tv_now);
5449         NTSTATUS status;
5450         uint32_t pwdProperties, rid = 0;
5451         struct ldb_message *mod_msg;
5452
5453         sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
5454
5455         pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
5456                                                   "pwdProperties", -1);
5457         if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
5458                 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
5459                 if (!NT_STATUS_IS_OK(status)) {
5460                         /*
5461                          * This can't happen anyway, but always try
5462                          * and update the badPwdCount on failure
5463                          */
5464                         rid = 0;
5465                 }
5466         }
5467         TALLOC_FREE(sid);
5468
5469         /*
5470          * Work out if we are doing password lockout on the domain.
5471          * Also, the built in administrator account is exempt:
5472          * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
5473          */
5474         lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
5475         if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
5476                 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
5477                           ldb_dn_get_linearized(user_msg->dn)));
5478                 return NT_STATUS_OK;
5479         }
5480
5481         mod_msg = ldb_msg_new(mem_ctx);
5482         if (mod_msg == NULL) {
5483                 return NT_STATUS_NO_MEMORY;
5484         }
5485         mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
5486         if (mod_msg->dn == NULL) {
5487                 TALLOC_FREE(mod_msg);
5488                 return NT_STATUS_NO_MEMORY;
5489         }
5490
5491         lockOutObservationWindow = get_lockout_observation_window(domain_msg,
5492                                                                   pso_msg);
5493
5494         badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
5495
5496         badPwdCount++;
5497
5498         ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
5499         if (ret != LDB_SUCCESS) {
5500                 TALLOC_FREE(mod_msg);
5501                 return NT_STATUS_NO_MEMORY;
5502         }
5503         ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
5504         if (ret != LDB_SUCCESS) {
5505                 TALLOC_FREE(mod_msg);
5506                 return NT_STATUS_NO_MEMORY;
5507         }
5508
5509         if (badPwdCount >= lockoutThreshold) {
5510                 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
5511                 if (ret != LDB_SUCCESS) {
5512                         TALLOC_FREE(mod_msg);
5513                         return NT_STATUS_NO_MEMORY;
5514                 }
5515                 DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
5516                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5517         } else {
5518                 DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
5519                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
5520         }
5521
5522         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5523         for (i=0; i< mod_msg->num_elements; i++) {
5524                 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5525         }
5526
5527         *_mod_msg = mod_msg;
5528         return NT_STATUS_OK;
5529 }
5530
5531 /**
5532  * Sets defaults for a User object
5533  * List of default attributes set:
5534  *      accountExpires, badPasswordTime, badPwdCount,
5535  *      codePage, countryCode, lastLogoff, lastLogon
5536  *      logonCount, pwdLastSet
5537  */
5538 int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
5539                                struct ldb_message *usr_obj,
5540                                struct ldb_request *req)
5541 {
5542         int i, ret;
5543         const struct attribute_values {
5544                 const char *name;
5545                 const char *value;
5546                 const char *add_value;
5547                 const char *mod_value;
5548                 const char *control;
5549                 unsigned add_flags;
5550                 unsigned mod_flags;
5551         } map[] = {
5552                 {
5553                         .name = "accountExpires",
5554                         .add_value = "9223372036854775807",
5555                         .mod_value = "0",
5556                 },
5557                 {
5558                         .name = "badPasswordTime",
5559                         .value = "0"
5560                 },
5561                 {
5562                         .name = "badPwdCount",
5563                         .value = "0"
5564                 },
5565                 {
5566                         .name = "codePage",
5567                         .value = "0"
5568                 },
5569                 {
5570                         .name = "countryCode",
5571                         .value = "0"
5572                 },
5573                 {
5574                         .name = "lastLogoff",
5575                         .value = "0"
5576                 },
5577                 {
5578                         .name = "lastLogon",
5579                         .value = "0"
5580                 },
5581                 {
5582                         .name = "logonCount",
5583                         .value = "0"
5584                 },
5585                 {
5586                         .name = "logonHours",
5587                         .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
5588                 },
5589                 {
5590                         .name = "pwdLastSet",
5591                         .value = "0",
5592                         .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
5593                 },
5594                 {
5595                         .name = "adminCount",
5596                         .mod_value = "0",
5597                 },
5598                 {
5599                         .name = "operatorCount",
5600                         .mod_value = "0",
5601                 },
5602         };
5603
5604         for (i = 0; i < ARRAY_SIZE(map); i++) {
5605                 bool added = false;
5606                 const char *value = NULL;
5607                 unsigned flags = 0;
5608
5609                 if (req != NULL && req->operation == LDB_ADD) {
5610                         value = map[i].add_value;
5611                         flags = map[i].add_flags;
5612                 } else {
5613                         value = map[i].mod_value;
5614                         flags = map[i].mod_flags;
5615                 }
5616
5617                 if (value == NULL) {
5618                         value = map[i].value;
5619                 }
5620
5621                 if (value != NULL) {
5622                         flags |= LDB_FLAG_MOD_ADD;
5623                 }
5624
5625                 if (flags == 0) {
5626                         continue;
5627                 }
5628
5629                 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
5630                                                      map[i].name,
5631                                                      value, flags,
5632                                                      &added);
5633                 if (ret != LDB_SUCCESS) {
5634                         return ret;
5635                 }
5636
5637                 if (req != NULL && added && map[i].control != NULL) {
5638                         ret = ldb_request_add_control(req,
5639                                                       map[i].control,
5640                                                       false, NULL);
5641                         if (ret != LDB_SUCCESS) {
5642                                 return ret;
5643                         }
5644                 }
5645         }
5646
5647         return LDB_SUCCESS;
5648 }
5649
5650 /**
5651  * Sets 'sAMAccountType on user object based on userAccountControl
5652  * @param ldb Current ldb_context
5653  * @param usr_obj ldb_message representing User object
5654  * @param user_account_control Value for userAccountControl flags
5655  * @param account_type_p Optional pointer to account_type to return
5656  * @return LDB_SUCCESS or LDB_ERR* code on failure
5657  */
5658 int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
5659                                    uint32_t user_account_control, uint32_t *account_type_p)
5660 {
5661         int ret;
5662         uint32_t account_type;
5663         struct ldb_message_element *el;
5664
5665         account_type = ds_uf2atype(user_account_control);
5666         if (account_type == 0) {
5667                 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
5668                 return LDB_ERR_UNWILLING_TO_PERFORM;
5669         }
5670         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5671                                  "sAMAccountType",
5672                                  account_type);
5673         if (ret != LDB_SUCCESS) {
5674                 return ret;
5675         }
5676         el = ldb_msg_find_element(usr_obj, "sAMAccountType");
5677         el->flags = LDB_FLAG_MOD_REPLACE;
5678
5679         if (account_type_p) {
5680                 *account_type_p = account_type;
5681         }
5682
5683         return LDB_SUCCESS;
5684 }
5685
5686 /**
5687  * Determine and set primaryGroupID based on userAccountControl value
5688  * @param ldb Current ldb_context
5689  * @param usr_obj ldb_message representing User object
5690  * @param user_account_control Value for userAccountControl flags
5691  * @param group_rid_p Optional pointer to group RID to return
5692  * @return LDB_SUCCESS or LDB_ERR* code on failure
5693  */
5694 int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
5695                                        uint32_t user_account_control, uint32_t *group_rid_p)
5696 {
5697         int ret;
5698         uint32_t rid;
5699         struct ldb_message_element *el;
5700
5701         rid = ds_uf2prim_group_rid(user_account_control);
5702
5703         ret = samdb_msg_add_uint(ldb, usr_obj, usr_obj,
5704                                  "primaryGroupID", rid);
5705         if (ret != LDB_SUCCESS) {
5706                 return ret;
5707         }
5708         el = ldb_msg_find_element(usr_obj, "primaryGroupID");
5709         el->flags = LDB_FLAG_MOD_REPLACE;
5710
5711         if (group_rid_p) {
5712                 *group_rid_p = rid;
5713         }
5714
5715         return LDB_SUCCESS;
5716 }
5717
5718 /**
5719  * Returns True if the source and target DNs both have the same naming context,
5720  * i.e. they're both in the same partition.
5721  */
5722 bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
5723                                TALLOC_CTX *mem_ctx,
5724                                struct ldb_dn *source_dn,
5725                                struct ldb_dn *target_dn)
5726 {
5727         TALLOC_CTX *tmp_ctx;
5728         struct ldb_dn *source_nc;
5729         struct ldb_dn *target_nc;
5730         int ret;
5731         bool same_nc = true;
5732
5733         tmp_ctx = talloc_new(mem_ctx);
5734
5735         ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
5736         if (ret != LDB_SUCCESS) {
5737                 DBG_ERR("Failed to find base DN for source %s\n",
5738                         ldb_dn_get_linearized(source_dn));
5739                 talloc_free(tmp_ctx);
5740                 return true;
5741         }
5742
5743         ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
5744         if (ret != LDB_SUCCESS) {
5745                 DBG_ERR("Failed to find base DN for target %s\n",
5746                         ldb_dn_get_linearized(target_dn));
5747                 talloc_free(tmp_ctx);
5748                 return true;
5749         }
5750
5751         same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
5752
5753         talloc_free(tmp_ctx);
5754
5755         return same_nc;
5756 }