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