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