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